fix: 修改设备物模型-属性来源可以选择规则
* feat: 修改bug优化ui * fix: 修改物模型导入bug * fix: 优化设备物模型-规则调试 * fix: 优化设备物模型-属性来源可以修改产品规则 * fix: 修改设备物模型-属性来源可以选择规则
This commit is contained in:
parent
074f351fa1
commit
fe0b235405
|
@ -11,7 +11,7 @@ export const save = (data: any) => server.post(`/data-collect/channel`, data);
|
|||
export const update = (id: string, data: any) =>
|
||||
server.put(`/data-collect/channel/${id}`, data);
|
||||
|
||||
export const getProviders = () => server.get(`/gateway/device/providers`);
|
||||
export const getProviders = () => server.get(`/data-collect/channel/providers`);
|
||||
|
||||
export const queryOptionsList = (type: string) =>
|
||||
server.get(`/data-collect/opc/${type}`);
|
||||
|
|
|
@ -62,3 +62,5 @@ export const scanOpcUAList = (data: any) =>
|
|||
export const queryTypeList = () => server.get(`/data-collect/opc/data-types`);
|
||||
|
||||
export const getProviders = () => server.get('/data-collect/channel/gateway/codec/providers')
|
||||
|
||||
export const getStates = () => server.get('/dictionary/running-state/items')
|
|
@ -3,7 +3,9 @@
|
|||
<j-input-search @search="search" allow-clear placeholder="搜索关键字" />
|
||||
<div class="tree">
|
||||
<j-tree @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
||||
:tree-data="data">
|
||||
:tree-data="data"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true">
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
<div style="max-width: 180px"><Ellipsis>{{ node.name }}</Ellipsis></div>
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
:field-names="{ title: 'name', key: 'id' }"
|
||||
auto-expand-parent
|
||||
:tree-data="data"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="node">
|
||||
<div class="node">
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</j-button>
|
||||
</template>
|
||||
</template>
|
||||
<j-tooltip v-else title="暂无权限,请联系管理员">
|
||||
<j-tooltip v-else title="暂无权限,请联系管理员" :placement="placement">
|
||||
<slot v-if="noButton"></slot>
|
||||
<j-button v-else v-bind="props" :disabled="_isPermission" :style="props.style">
|
||||
<slot></slot>
|
||||
|
@ -89,6 +89,10 @@ const props = defineProps({
|
|||
style: {
|
||||
type: Object as PropType<CSSProperties>
|
||||
},
|
||||
placement:{
|
||||
type: String,
|
||||
default: 'top'
|
||||
},
|
||||
...omit(buttonProps(), 'icon')
|
||||
})
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ export const USER_CENTER_MENU_BUTTON_CODE = 'user-center-passwd-update'
|
|||
|
||||
/**协议列表 */
|
||||
export const protocolList = [
|
||||
{ label: 'OPC-UA', value: 'OPC_UA', alias: 'opc-ua' },
|
||||
{ label: 'Modbus/TCP', value: 'MODBUS_TCP', alias: 'modbus-tcp' },
|
||||
{ label: 'GATEWAY', value: 'COLLECTOR_GATEWAY', alias: 'collector-gateway' },
|
||||
{ label: 'OPC_UA', value: 'OPC_UA', alias: 'opc-ua' },
|
||||
{ label: 'MODBUS_TCP', value: 'MODBUS_TCP', alias: 'Modbus/TCP' },
|
||||
{ label: 'COLLECTOR_GATEWAY', value: 'COLLECTOR_GATEWAY', alias: 'GATEWAY' },
|
||||
]
|
||||
|
|
|
@ -304,9 +304,9 @@ const getProvidersList = async () => {
|
|||
if (resp.status === 200) {
|
||||
const arr = resp.result
|
||||
.filter(
|
||||
(item: any) => ['collector-gateway', 'modbus-tcp', 'opc-ua'].includes(item.id),
|
||||
(item: any) => ['GATEWAY', 'Modbus/TCP', 'opc-ua'].includes(item.name),
|
||||
)
|
||||
.map((it: any) => it.id);
|
||||
.map((it: any) => it.name);
|
||||
const providers: any = protocolList.filter((item: any) =>
|
||||
arr.includes(item.alias),
|
||||
);
|
||||
|
|
|
@ -143,11 +143,12 @@
|
|||
<script lang="ts" setup name="DataCollectPage">
|
||||
import type { ActionsType } from '@/components/Table/index';
|
||||
import { getImage } from '@/utils/comm';
|
||||
import { query, remove, update } from '@/api/data-collect/channel';
|
||||
import { query, remove, update ,getProviders} from '@/api/data-collect/channel';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import { StatusColorEnum, updateStatus } from './data';
|
||||
import { useMenuStore } from 'store/menu';
|
||||
import Save from './Save/index.vue';
|
||||
import { protocolList } from '@/utils/consts';
|
||||
import _ from 'lodash';
|
||||
|
||||
const menuStory = useMenuStore();
|
||||
|
@ -174,10 +175,20 @@ const columns = [
|
|||
ellipsis: true,
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{ label: 'OPC_UA', value: 'OPC_UA' },
|
||||
{ label: 'MODBUS_TCP', value: 'MODBUS_TCP' },
|
||||
],
|
||||
options: async() =>{
|
||||
const resp: any = await getProviders();
|
||||
if (resp.status === 200) {
|
||||
const arr = resp.result
|
||||
.filter(
|
||||
(item: any) => ['GATEWAY', 'Modbus/TCP', 'opc-ua'].includes(item.name),
|
||||
)
|
||||
.map((it: any) => it.name);
|
||||
const providers: any = protocolList.filter((item: any) =>
|
||||
arr.includes(item.alias),
|
||||
);
|
||||
return providers
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -204,8 +215,7 @@ const columns = [
|
|||
type: 'select',
|
||||
options: [
|
||||
{ label: '运行中', value: 'running' },
|
||||
{ label: '部分错误', value: 'partialError' },
|
||||
{ label: '错误', value: 'failed' },
|
||||
{ label: '已停止', value: 'stopped' },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
checkable
|
||||
@check="onCheck"
|
||||
:height="600"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name, key }">
|
||||
<span
|
||||
|
|
|
@ -329,6 +329,8 @@ import {
|
|||
batchDeletePoint,
|
||||
removePoint,
|
||||
readPoint,
|
||||
getProviders,
|
||||
getStates
|
||||
} from '@/api/data-collect/collector';
|
||||
import { onlyMessage } from '@/utils/comm';
|
||||
import PointCardBox from './components/PointCardBox/index.vue';
|
||||
|
@ -342,6 +344,7 @@ import { cloneDeep, isNumber, throttle } from 'lodash-es';
|
|||
import { getWebSocket } from '@/utils/websocket';
|
||||
import { map } from 'rxjs/operators';
|
||||
import dayjs from 'dayjs';
|
||||
import { responsiveArray } from 'ant-design-vue/lib/_util/responsiveObserve';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
|
@ -409,16 +412,14 @@ const columns = [
|
|||
key: 'provider',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: 'OPC_UA',
|
||||
value: 'OPC_UA',
|
||||
},
|
||||
{
|
||||
label: 'MODBUS_TCP',
|
||||
value: 'MODBUS_TCP',
|
||||
},
|
||||
],
|
||||
options: async () =>{
|
||||
const resp:any = await getProviders();
|
||||
if(resp.success){
|
||||
return resp.result.map((item: any) => ({ label: item.name, value: item.id }))
|
||||
}else{
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -436,16 +437,16 @@ const columns = [
|
|||
key: 'runningState',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '运行中',
|
||||
value: 'running',
|
||||
},
|
||||
{
|
||||
label: '已停止',
|
||||
value: 'stopped',
|
||||
},
|
||||
],
|
||||
options: async() =>{
|
||||
const resq:any = await getStates();
|
||||
if(resq.status === 200){
|
||||
return resq.result.map((item:any)=>(
|
||||
{label:item.text,value:item.value}
|
||||
))
|
||||
}else{
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -542,7 +543,7 @@ const getQuantity = (item: Partial<Record<string, any>>) => {
|
|||
};
|
||||
const getAddress = (item: Partial<Record<string, any>>) => {
|
||||
const { address } = item.configuration?.parameter || '';
|
||||
return !!address ? address + '(地址)' : '';
|
||||
return (!!address || address === 0) ? address + '(地址)' : '';
|
||||
};
|
||||
const getScaleFactor = (item: Partial<Record<string, any>>) => {
|
||||
const { scaleFactor } = item.configuration?.codec?.configuration || '';
|
||||
|
|
|
@ -134,16 +134,16 @@
|
|||
</div>
|
||||
<j-form-item
|
||||
:name="['configuration', 'requsetTimeout']"
|
||||
label="请求超时时间配置"
|
||||
:rules="LeftTreeRules.requsetTimeout"
|
||||
>
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入请求超时时间配置"
|
||||
v-model:value="formData.configuration.requsetTimeout"
|
||||
addon-after="ms"
|
||||
:max="2147483648"
|
||||
:min="1"
|
||||
/>
|
||||
<j-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入请求超时时间配置"
|
||||
v-model:value="formData.configuration.requsetTimeout"
|
||||
addon-after="ms"
|
||||
:max="60000"
|
||||
:min="2000"
|
||||
/>
|
||||
</j-form-item>
|
||||
<j-form-item label="说明" name="description">
|
||||
<j-textarea
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
:height="660"
|
||||
@select='treeSelect'
|
||||
defaultExpandAll
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name, data }">
|
||||
<Ellipsis class="tree-left-title">
|
||||
|
@ -54,7 +56,7 @@
|
|||
class="tree-left-tag"
|
||||
v-if="data.id !== '*'"
|
||||
:color="colorMap.get(data?.uniformState?.value)"
|
||||
>{{ data?.uniformState?.text }}</j-tag
|
||||
>{{ data?.pointNumber === 0 ? '--' : (data?.uniformState?.value === 'normal' ? '运行中' : data?.uniformState?.text) }}</j-tag
|
||||
>
|
||||
<j-tag
|
||||
class="tree-left-tag2"
|
||||
|
@ -65,7 +67,7 @@
|
|||
"
|
||||
>
|
||||
{{
|
||||
data?.state?.text
|
||||
data?.state?.value === 'disabled' ? '禁用' : '运行中'
|
||||
}}
|
||||
</j-tag
|
||||
>
|
||||
|
|
|
@ -57,7 +57,7 @@ export const ModBusRules = {
|
|||
},
|
||||
{
|
||||
pattern: regOnlyNumber,
|
||||
message: '请输入0-999999999之间的正整数',
|
||||
message: '请输入0-999999之间的正整数',
|
||||
},
|
||||
],
|
||||
quantity: [
|
||||
|
@ -170,6 +170,9 @@ export const LeftTreeRules = {
|
|||
endianIn: [
|
||||
{ required: true, message: '请选择单字高低位切换', trigger: 'blur' },
|
||||
],
|
||||
requsetTimeout:[
|
||||
{ pattern: /^\d+$/, message:'请输入2000-60000的正整数',trigger: 'change'}
|
||||
]
|
||||
};
|
||||
|
||||
export const FormTableColumns = [
|
||||
|
|
|
@ -83,7 +83,8 @@ const handleOptions = (x = [], y = []) => {
|
|||
const chart: any = chartRef.value;
|
||||
if (chart) {
|
||||
const myChart = echarts.init(chart);
|
||||
const maxY: number = y.sort((a,b)=>{
|
||||
const _y = [...y];
|
||||
const maxY: number = _y.sort((a,b)=>{
|
||||
return b-a
|
||||
})?.[0]
|
||||
const options = {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<div class="box">
|
||||
<j-scrollbar :height="`calc(100% - 51px)`">
|
||||
<div class="box">
|
||||
<div class="content">
|
||||
<template v-if="bindList.length">
|
||||
<div
|
||||
|
@ -47,7 +48,8 @@
|
|||
</template>
|
||||
<j-empty v-else style="margin: 200px 0" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</j-scrollbar>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="notification-record-container">
|
||||
<div class="notification-record-container">
|
||||
<pro-search
|
||||
:columns="columns"
|
||||
:target="type"
|
||||
|
@ -14,6 +14,7 @@
|
|||
:params="queryParams"
|
||||
:bodyStyle="{ padding: 0 }"
|
||||
:defaultParams="defaultParams"
|
||||
:scroll="{y:420}"
|
||||
>
|
||||
<!-- <template #rightExtraRender>
|
||||
<j-popconfirm title="确认全部已读?" @confirm="onAllRead">
|
||||
|
@ -75,7 +76,7 @@
|
|||
:data="viewItem"
|
||||
:type="type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="NotificationRecord">
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
:key="item.provider"
|
||||
:tab="item.name"
|
||||
>
|
||||
<NotificationRecord :type="item.provider" />
|
||||
<NotificationRecord :type="item.provider" />
|
||||
</j-tab-pane>
|
||||
</j-tabs>
|
||||
<j-empty v-else style="margin: 200px 0" />
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<j-spin :spinning="loading">
|
||||
<j-scrollbar :height="`calc(100% - 51px)`">
|
||||
<j-spin :spinning="loading">
|
||||
<div style="padding: 0 10px">
|
||||
<div class="alert">
|
||||
<AIcon type="InfoCircleOutlined" />
|
||||
|
@ -47,7 +48,8 @@
|
|||
<j-empty style="margin: 200px 0" v-else />
|
||||
</div>
|
||||
</div>
|
||||
</j-spin>
|
||||
</j-spin>
|
||||
</j-scrollbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
|
@ -53,9 +53,7 @@
|
|||
:tab="item.title"
|
||||
/>
|
||||
</j-tabs>
|
||||
<j-scrollbar :height="`calc(100% - 51px)`">
|
||||
<component :is="tabs[user.tabKey]" />
|
||||
</j-scrollbar>
|
||||
<component :is="tabs[user.tabKey]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
<j-form-item label="名称" name="name">
|
||||
<j-input
|
||||
v-model:value="formModel.name"
|
||||
:maxlength="64"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</j-form-item>
|
||||
|
@ -31,6 +30,7 @@
|
|||
id="inputNumber"
|
||||
v-model:value="formModel.sortIndex"
|
||||
:min="1"
|
||||
:max="9999"
|
||||
placeholder="请输入排序"
|
||||
/>
|
||||
</j-form-item>
|
||||
|
@ -102,7 +102,11 @@ const rules = ref({
|
|||
message: '最多可输入64个字符',
|
||||
},
|
||||
],
|
||||
sortIndex: [{ required: true, message: '请输入排序', trigger: 'blur' }],
|
||||
sortIndex: [{ required: true, message: '请输入排序', trigger: 'blur' },{
|
||||
pattern:/^\d+$/,
|
||||
message:'请输入正整数',
|
||||
trigger:'change'
|
||||
}],
|
||||
});
|
||||
const visible = ref(false);
|
||||
const { resetFields, validate, validateInfos } = useForm(
|
||||
|
@ -174,7 +178,7 @@ const show = async (row: any) => {
|
|||
childArr.value = row.children.sort(compare('sortIndex'));
|
||||
formModel.value = {
|
||||
name: '',
|
||||
sortIndex:
|
||||
sortIndex:childArr.value[childArr.value.length - 1].sortIndex === 9999 ? childArr.value[childArr.value.length - 1].sortIndex :
|
||||
childArr.value[childArr.value.length - 1].sortIndex + 1,
|
||||
description: '',
|
||||
};
|
||||
|
@ -186,7 +190,7 @@ const show = async (row: any) => {
|
|||
if (arr.value.length > 0) {
|
||||
formModel.value = {
|
||||
name: '',
|
||||
sortIndex: arr.value[arr.value.length - 1].sortIndex + 1,
|
||||
sortIndex: arr.value[arr.value.length - 1].sortIndex === 9999 ? arr.value[arr.value.length - 1].sortIndex : arr.value[arr.value.length - 1].sortIndex + 1,
|
||||
description: '',
|
||||
};
|
||||
}
|
||||
|
|
|
@ -107,11 +107,15 @@ const query = reactive({
|
|||
key: 'sortIndex',
|
||||
search: {
|
||||
type: 'number',
|
||||
componentProps:{
|
||||
precision:0,
|
||||
min:0
|
||||
}
|
||||
},
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
title: '说明',
|
||||
key: 'description',
|
||||
dataIndex: 'description',
|
||||
search: {
|
||||
|
|
|
@ -150,7 +150,7 @@ const menuStore = useMenuStore();
|
|||
* 获取产品数量
|
||||
*/
|
||||
const getProductData = () => {
|
||||
if (menuStore.hasMenu('device/Product')) {
|
||||
// if (menuStore.hasMenu('device/Product')) {
|
||||
productCount().then((res) => {
|
||||
if (res.status == 200) {
|
||||
productTotal.value = res.result;
|
||||
|
@ -180,14 +180,14 @@ const getProductData = () => {
|
|||
productFooter.value[1].value = res.result;
|
||||
}
|
||||
});
|
||||
}
|
||||
// }
|
||||
};
|
||||
getProductData();
|
||||
/**
|
||||
* 获取设备数量
|
||||
*/
|
||||
const getDeviceData = () => {
|
||||
if (menuStore.hasMenu('device/Instance')) {
|
||||
// if (menuStore.hasMenu('device/Instance')) {
|
||||
deviceCount().then((res) => {
|
||||
if (res.status == 200) {
|
||||
deviceTotal.value = res.result;
|
||||
|
@ -206,7 +206,7 @@ const getDeviceData = () => {
|
|||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
// }
|
||||
};
|
||||
getDeviceData();
|
||||
/**
|
||||
|
@ -214,7 +214,7 @@ getDeviceData();
|
|||
*/
|
||||
const getOnline = () => {
|
||||
const startTime = dayjs().subtract(0, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||
const endTime = dayjs().subtract(0, 'days').endOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||
const endTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
dashboard([
|
||||
{
|
||||
|
@ -481,7 +481,7 @@ const setDevMesChartOption = (
|
|||
//今日设备消息量
|
||||
const getDevice = () => {
|
||||
const startTime = dayjs().subtract(0, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||
const endTime = dayjs().subtract(0, 'days').endOf('day').format('YYYY-MM-DD HH:mm:ss');
|
||||
const endTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
dashboard([
|
||||
{
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
:load-data="onLoadData"
|
||||
@check="onCheck"
|
||||
v-model:expandedKeys="expandedKeys"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
/>
|
||||
</j-card>
|
||||
<div style="width: 100px">
|
||||
|
|
|
@ -177,7 +177,7 @@ const funcChange = (val: string) => {
|
|||
};
|
||||
|
||||
const saveBtn = async () => {
|
||||
const _inputs = await inputsRef.value.onSave();
|
||||
const _inputs = await inputsRef.value?.onSave();
|
||||
console.log(_inputs)
|
||||
if(!_inputs){
|
||||
return
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
:load-data="onLoadData"
|
||||
@check="onCheck"
|
||||
v-model:expandedKeys="expandedKeys"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
/>
|
||||
</j-card>
|
||||
<div style="width: 100px">
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
:tree-data="dataSource"
|
||||
:checkedKeys="checkedKeys"
|
||||
@check="onCheck"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
/>
|
||||
</j-card>
|
||||
<div style="width: 100px">
|
||||
|
|
|
@ -26,18 +26,22 @@
|
|||
<j-descriptions-item label="设备类型">{{
|
||||
productStore.current.deviceType?.text
|
||||
}}</j-descriptions-item>
|
||||
|
||||
<j-descriptions-item label="接入方式">
|
||||
<PermissionButton
|
||||
type="link"
|
||||
@click="changeTables"
|
||||
hasPermission="device/Product:update"
|
||||
>{{
|
||||
productStore.current.accessName
|
||||
? productStore.current.accessName
|
||||
: '配置接入方式'
|
||||
}}</PermissionButton
|
||||
>
|
||||
type="link"
|
||||
style="width:100%;padding:0"
|
||||
@click="changeTables"
|
||||
hasPermission="device/Product:update"
|
||||
>
|
||||
<div style="white-space: normal">
|
||||
<Ellipsis>{{
|
||||
productStore.current.accessName
|
||||
? productStore.current.accessName
|
||||
: '配置接入方式'
|
||||
}}</Ellipsis>
|
||||
</div>
|
||||
</PermissionButton
|
||||
>
|
||||
</j-descriptions-item>
|
||||
<j-descriptions-item label="创建时间">{{
|
||||
dayjs(productStore.current.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||
|
|
|
@ -23,11 +23,13 @@
|
|||
v-if="productStore.current.state === 1"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
:disabled="!permissionStore.hasPermission('device/Product:action')"
|
||||
>
|
||||
<j-switch
|
||||
:checked="productStore.current.state === 1"
|
||||
checked-children="正常"
|
||||
un-checked-children="禁用"
|
||||
:disabled="!permissionStore.hasPermission('device/Product:action')"
|
||||
/>
|
||||
</j-popconfirm>
|
||||
<j-popconfirm
|
||||
|
@ -36,6 +38,7 @@
|
|||
v-if="productStore.current.state === 0"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
:disabled="!permissionStore.hasPermission('device/Product:action')"
|
||||
>
|
||||
<j-switch
|
||||
:unCheckedValue="
|
||||
|
@ -43,6 +46,7 @@
|
|||
"
|
||||
checked-children="正常"
|
||||
un-checked-children="禁用"
|
||||
:disabled="!permissionStore.hasPermission('device/Product:action')"
|
||||
/>
|
||||
</j-popconfirm>
|
||||
</div>
|
||||
|
@ -87,6 +91,7 @@
|
|||
: undefined
|
||||
"
|
||||
hasPermission="device/Product:update"
|
||||
placement="topRight"
|
||||
>应用配置</PermissionButton
|
||||
>
|
||||
</template>
|
||||
|
@ -124,7 +129,9 @@ import { getImage, handleParamsToString, onlyMessage } from '@/utils/comm';
|
|||
import { useMenuStore } from '@/store/menu';
|
||||
import { useRouterParams } from '@/utils/hooks/useParams';
|
||||
import {EventEmitter} from "@/utils/utils";
|
||||
import { usePermissionStore } from '@/store/permission';
|
||||
|
||||
const permissionStore = usePermissionStore()
|
||||
const menuStory = useMenuStore();
|
||||
const route = useRoute();
|
||||
const checked = ref<boolean>(true);
|
||||
|
|
|
@ -101,6 +101,10 @@ defineExpose({
|
|||
}
|
||||
.product-id {
|
||||
margin: 10px 15px 10px 0px;
|
||||
max-width: 520px;
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.product-btn {
|
||||
margin: 10px 0px 10px 0;
|
||||
|
|
|
@ -306,6 +306,7 @@ const getActions = (
|
|||
|
||||
icon: 'icon-xiazai',
|
||||
onClick: () => {
|
||||
console.log(data);
|
||||
const extra = omit(data, [
|
||||
'transportProtocol',
|
||||
'protocolName',
|
||||
|
@ -314,7 +315,7 @@ const getActions = (
|
|||
'accessProvider',
|
||||
'messageProtocol',
|
||||
]);
|
||||
downloadObject(extra, '产品');
|
||||
downloadObject(extra, data.name+'产品');
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -389,6 +390,7 @@ const beforeUpload = (file: any) => {
|
|||
reader.onload = async (result) => {
|
||||
const text = result.target?.result;
|
||||
console.log('text: ', text);
|
||||
console.log(file);
|
||||
if (!file.type.includes('json')) {
|
||||
onlyMessage('请上传json格式文件', 'error');
|
||||
return false;
|
||||
|
@ -398,7 +400,7 @@ const beforeUpload = (file: any) => {
|
|||
// 设置导入的产品状态为未发布
|
||||
data.state = 0;
|
||||
if (Array.isArray(data)) {
|
||||
onlyMessage('请上传json格式文件', 'error');
|
||||
onlyMessage('文件内容不能为空', 'error');
|
||||
return false;
|
||||
}
|
||||
delete data.state;
|
||||
|
@ -409,7 +411,7 @@ const beforeUpload = (file: any) => {
|
|||
}
|
||||
return true;
|
||||
} catch {
|
||||
// onlyMessage('请上传json格式文件', 'error');
|
||||
onlyMessage('请上传json格式文件', 'error');
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
: '新增',
|
||||
}"
|
||||
@click="handleAddClick()"
|
||||
placement="topRight"
|
||||
>
|
||||
新增
|
||||
</PermissionButton>
|
||||
|
|
|
@ -97,6 +97,7 @@ const handleConvertMetadata = (key: Key) => {
|
|||
convertMetadata('to', 'alink', JSON.parse(metadata.value)).then(res => {
|
||||
if (res.status === 200) {
|
||||
value.value = JSON.stringify(res.result)
|
||||
monacoValue.value = JSON.stringify(res.result)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,318 +1,443 @@
|
|||
<template>
|
||||
<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">
|
||||
<AIcon type="ExclamationCircleOutlined" style="margin-right: 5px" />
|
||||
<template v-if="type === 'product'">
|
||||
导入的物模型会覆盖原来的属性、功能、事件、标签,请谨慎操作。
|
||||
</template>
|
||||
<template v-else>
|
||||
导入时会根据标识跳过继承自产品物模型的属性、功能、事件、标签。
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<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" showSearch></j-select>
|
||||
</j-form-item>
|
||||
<j-form-item label="物模型类型" v-bind="validateInfos.metadata" v-if="type === 'device' || formModel.type === 'import'">
|
||||
<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'">
|
||||
<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 v-if="formModel.type === 'import' && formModel.metadataType === 'file'" label="文件上传" v-bind="validateInfos.upload">
|
||||
<j-input v-model:value="formModel.upload">
|
||||
<template #addonAfter>
|
||||
<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" />
|
||||
</j-upload>
|
||||
</template>
|
||||
</j-input>
|
||||
</j-form-item>
|
||||
<j-form-item v-bind="validateInfos.import" v-if="(type === 'device' || formModel.type === 'import') && formModel.metadataType === 'script'">
|
||||
<template #label>
|
||||
<j-space>
|
||||
物模型
|
||||
<j-tooltip title="在线编辑器中编写物模型脚本">
|
||||
<AIcon type="QuestionCircleOutlined" style="color: rgb(136, 136, 136);"/>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<JMonacoEditor v-model="formModel.import" theme="vs" style="height: 300px" lang="json"></JMonacoEditor>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</j-modal>
|
||||
<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">
|
||||
<AIcon
|
||||
type="ExclamationCircleOutlined"
|
||||
style="margin-right: 5px"
|
||||
/>
|
||||
<template v-if="type === 'product'">
|
||||
导入的物模型会覆盖原来的属性、功能、事件、标签,请谨慎操作。
|
||||
</template>
|
||||
<template v-else>
|
||||
导入时会根据标识跳过继承自产品物模型的属性、功能、事件、标签。
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<j-form layout="vertical" ref="formRef" :model="formModel">
|
||||
<j-form-item
|
||||
v-if="type === 'product'"
|
||||
label="导入方式"
|
||||
name="type"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择导入方式',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<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="选择产品"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择产品',
|
||||
},
|
||||
]"
|
||||
name="copy"
|
||||
v-if="formModel.type === 'copy'"
|
||||
>
|
||||
<j-select
|
||||
:options="productList"
|
||||
v-model:value="formModel.copy"
|
||||
option-filter-prop="label"
|
||||
placeholder="请选择产品"
|
||||
showSearch
|
||||
></j-select>
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
label="物模型类型"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择物模型类型',
|
||||
},
|
||||
]"
|
||||
name="metadata"
|
||||
v-if="type === 'device' || formModel.type === 'import'"
|
||||
>
|
||||
<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="导入类型"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请选择导入类型',
|
||||
},
|
||||
]"
|
||||
name="metadataType"
|
||||
v-if="type === 'device' || formModel.type === 'import'"
|
||||
>
|
||||
<j-select v-model:value="formModel.metadataType" @change="formModel.import = undefined">
|
||||
<j-select-option value="file">文件上传</j-select-option>
|
||||
<j-select-option value="script">脚本</j-select-option>
|
||||
</j-select>
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
v-if="
|
||||
formModel.type === 'import' &&
|
||||
formModel.metadataType === 'file'
|
||||
"
|
||||
label="文件上传"
|
||||
name="import"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请上传文件',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<!-- <j-input v-model:value="formModel.upload">
|
||||
<template #addonAfter>
|
||||
<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"
|
||||
/>
|
||||
</j-upload>
|
||||
</template>
|
||||
</j-input> -->
|
||||
<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() }"
|
||||
>
|
||||
<j-button>
|
||||
<template #icon><AIcon type="UploadOutlined" /></template>
|
||||
上传文件
|
||||
</j-button>
|
||||
</j-upload>
|
||||
<div style="margin-left: 10px; color: rgba(0, 0, 0, .6);">支持扩展名:.json</div>
|
||||
</j-form-item>
|
||||
<j-form-item
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入物模型',
|
||||
},
|
||||
]"
|
||||
name="import"
|
||||
v-if="
|
||||
(type === 'device' || formModel.type === 'import') &&
|
||||
formModel.metadataType === 'script'
|
||||
"
|
||||
>
|
||||
<template #label>
|
||||
<j-space>
|
||||
物模型
|
||||
<j-tooltip title="在线编辑器中编写物模型脚本">
|
||||
<AIcon
|
||||
type="QuestionCircleOutlined"
|
||||
style="color: rgb(136, 136, 136)"
|
||||
/>
|
||||
</j-tooltip>
|
||||
</j-space>
|
||||
</template>
|
||||
<JMonacoEditor
|
||||
v-model:modelValue="formModel.import"
|
||||
theme="vs"
|
||||
style="height: 300px"
|
||||
lang="json"
|
||||
></JMonacoEditor>
|
||||
</j-form-item>
|
||||
</j-form>
|
||||
</j-modal>
|
||||
</template>
|
||||
<script setup lang="ts" name="Import">
|
||||
import { useForm } from 'ant-design-vue/es/form';
|
||||
import { saveMetadata } from '@/api/device/instance'
|
||||
import { queryNoPagingPost, convertMetadata, modify } from '@/api/device/product'
|
||||
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 } from '@/views/device/Product/typings'
|
||||
import { useInstanceStore } from '@/store/instance'
|
||||
import type {
|
||||
UploadProps,
|
||||
UploadFile,
|
||||
UploadChangeParam,
|
||||
} from 'ant-design-vue/es';
|
||||
import type { DeviceMetadata } from '@/views/device/Product/typings';
|
||||
import { useInstanceStore } from '@/store/instance';
|
||||
import { useProductStore } from '@/store/product';
|
||||
import { FILE_UPLOAD } from '@/api/comm';
|
||||
import { getToken, onlyMessage } from '@/utils/comm';
|
||||
import { useMetadataStore } from '@/store/metadata';
|
||||
import {omit} from "lodash-es";
|
||||
import { Modal } from 'jetlinks-ui-components'
|
||||
import { omit, uniqBy } from 'lodash-es';
|
||||
import { Modal } from 'jetlinks-ui-components';
|
||||
|
||||
const route = useRoute()
|
||||
const instanceStore = useInstanceStore()
|
||||
const productStore = useProductStore()
|
||||
const route = useRoute();
|
||||
const instanceStore = useInstanceStore();
|
||||
const productStore = useProductStore();
|
||||
|
||||
interface Props {
|
||||
visible: boolean,
|
||||
type: 'device' | 'product',
|
||||
visible: boolean;
|
||||
type: 'device' | 'product';
|
||||
}
|
||||
interface Emits {
|
||||
(e: 'update:visible', data: boolean): void;
|
||||
(e: 'submit', data: any): void;
|
||||
(e: 'update:visible', data: boolean): void;
|
||||
(e: 'submit', data: any): void;
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const emits = defineEmits<Emits>()
|
||||
const loading = ref(false)
|
||||
const props = defineProps<Props>();
|
||||
const emits = defineEmits<Emits>();
|
||||
const loading = ref(false);
|
||||
|
||||
const _visible = computed({
|
||||
get: () => {
|
||||
return props.visible;
|
||||
},
|
||||
set: (val: any) => {
|
||||
emits('update:visible', val);
|
||||
},
|
||||
})
|
||||
get: () => {
|
||||
return props.visible;
|
||||
},
|
||||
set: (val: any) => {
|
||||
emits('update:visible', val);
|
||||
},
|
||||
});
|
||||
|
||||
const close = () => {
|
||||
emits('update:visible', false);
|
||||
}
|
||||
emits('update:visible', false);
|
||||
};
|
||||
|
||||
/** form表单 */
|
||||
const formModel = reactive<Record<string, any>>({
|
||||
type: 'import',
|
||||
metadata: 'jetlinks',
|
||||
metadataType: 'script',
|
||||
})
|
||||
const rules = reactive({
|
||||
type: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择导入方式',
|
||||
},
|
||||
],
|
||||
copy: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择产品',
|
||||
},
|
||||
],
|
||||
metadata: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择物模型类型',
|
||||
},
|
||||
],
|
||||
metadataType: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择导入类型',
|
||||
},
|
||||
],
|
||||
upload: [
|
||||
{
|
||||
required: true,
|
||||
message: '请上传文件',
|
||||
},
|
||||
],
|
||||
import: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入物模型',
|
||||
},
|
||||
],
|
||||
})
|
||||
const { validate, validateInfos } = useForm(formModel, rules);
|
||||
const fileList = ref<UploadFile[]>([])
|
||||
const hasVirtualRule = ref(false)
|
||||
type: 'import',
|
||||
metadata: 'jetlinks',
|
||||
metadataType: 'script',
|
||||
});
|
||||
// const { validate, validateInfos } = useForm(formModel, rules);
|
||||
const fileList = ref<UploadFile[]>([]);
|
||||
const hasVirtualRule = ref(false);
|
||||
const formRef = ref();
|
||||
|
||||
const productList = ref<DefaultOptionType[]>([])
|
||||
const productList = ref<DefaultOptionType[]>([]);
|
||||
|
||||
const loadData = async () => {
|
||||
const { id } = route.params || {}
|
||||
const product = await queryNoPagingPost({
|
||||
paging: false,
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
terms: [{ column: 'id$not', value: id }],
|
||||
}) as any
|
||||
productList.value = product.result.filter((i: any) => i?.metadata).map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.metadata,
|
||||
key: item.id
|
||||
})) as DefaultOptionType[]
|
||||
}
|
||||
loadData()
|
||||
const { id } = route.params || {};
|
||||
const product = (await queryNoPagingPost({
|
||||
paging: false,
|
||||
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||
terms: [{ column: 'id$not', value: id }],
|
||||
})) as any;
|
||||
productList.value = product.result
|
||||
.filter((i: any) => i?.metadata)
|
||||
.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.metadata,
|
||||
key: item.id,
|
||||
})) as DefaultOptionType[];
|
||||
};
|
||||
loadData();
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = file => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(file);
|
||||
reader.onload = (json) => {
|
||||
formModel.import = json.target?.result;
|
||||
};
|
||||
}
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(file);
|
||||
reader.onload = (json) => {
|
||||
formModel.import = json.target?.result;
|
||||
};
|
||||
};
|
||||
const fileChange = (info: UploadChangeParam) => {
|
||||
if (info.file.status === 'done') {
|
||||
const { response } = info.file
|
||||
if (response.status === 200) {
|
||||
formModel.upload = response.result
|
||||
if (info.file.status === 'done') {
|
||||
const { response } = info.file;
|
||||
if (response.status === 200) {
|
||||
formModel.upload = response.result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const operateLimits = (mdata: DeviceMetadata) => {
|
||||
hasVirtualRule.value = false
|
||||
const obj: DeviceMetadata = { ...mdata };
|
||||
const old = JSON.parse(instanceStore.detail?.metadata || '{}');
|
||||
const fid = instanceStore.detail?.features?.map(item => item.id);
|
||||
if (fid?.includes('eventNotModifiable')) {
|
||||
obj.events = old?.events || [];
|
||||
}
|
||||
if (fid?.includes('propertyNotModifiable')) {
|
||||
obj.properties = old?.properties || [];
|
||||
}
|
||||
(obj?.events || []).map((item, index) => {
|
||||
return { ...item, sortsIndex: index };
|
||||
});
|
||||
(obj?.properties || []).map((item, index) => {
|
||||
if (item.expands?.source === 'rule') {
|
||||
hasVirtualRule.value = true
|
||||
item.expands = omit(item.expands, ['virtualRule'])
|
||||
hasVirtualRule.value = false;
|
||||
const obj: DeviceMetadata = { ...mdata };
|
||||
const old = JSON.parse(instanceStore.detail?.metadata || '{}');
|
||||
const fid = instanceStore.detail?.features?.map((item) => item.id);
|
||||
const _data: DeviceMetadata = {
|
||||
properties: [],
|
||||
events: [],
|
||||
functions: [],
|
||||
tags: []
|
||||
}
|
||||
return { ...item, sortsIndex: index };
|
||||
});
|
||||
(obj?.functions || []).map((item, index) => {
|
||||
return { ...item, sortsIndex: index };
|
||||
});
|
||||
(obj?.tags || []).map((item, index) => {
|
||||
return { ...item, sortsIndex: index };
|
||||
});
|
||||
return obj;
|
||||
_data.properties = uniqBy([...(obj?.properties || []), ...(old?.properties || [])], 'id')
|
||||
_data.events = uniqBy([...(obj?.events || []), ...(old?.events || [])], 'id')
|
||||
_data.functions = uniqBy([...(obj?.functions || []), ...(old?.functions || [])], 'id')
|
||||
_data.tags = uniqBy([...(obj?.tags || []), ...(old?.tags || [])], 'id')
|
||||
|
||||
if (fid?.includes('eventNotModifiable')) {
|
||||
_data.events = old?.events || [];
|
||||
}
|
||||
if (fid?.includes('propertyNotModifiable')) {
|
||||
_data.properties = old?.properties || [];
|
||||
}
|
||||
|
||||
(_data?.properties || []).map((item) => {
|
||||
if (item.expands?.source === 'rule') {
|
||||
hasVirtualRule.value = true;
|
||||
item.expands = omit(item.expands, ['virtualRule']);
|
||||
}
|
||||
return item
|
||||
});
|
||||
return _data;
|
||||
};
|
||||
const metadataStore = useMetadataStore()
|
||||
const metadataStore = useMetadataStore();
|
||||
|
||||
const handleImport = async () => {
|
||||
validate().then(async (data) => {
|
||||
loading.value = true
|
||||
const { id } = route.params || {}
|
||||
if (data.metadata === 'alink') {
|
||||
const res = await convertMetadata('from', 'alink', JSON.parse(data.import)).catch(err => err)
|
||||
if (res.status === 200) {
|
||||
const metadata = operateLimits(res.result)
|
||||
let result;
|
||||
if (props?.type === 'device') {
|
||||
result = await saveMetadata(id as string, metadata).catch(err => err)
|
||||
formRef.value.validate().then(async (data: any) => {
|
||||
const { id } = route.params || {};
|
||||
if (data.metadata === 'alink') {
|
||||
try {
|
||||
const _import = JSON.parse(data.import);
|
||||
loading.value = true;
|
||||
const res = await convertMetadata(
|
||||
'from',
|
||||
'alink',
|
||||
_import,
|
||||
).catch((err) => err);
|
||||
if (res.status === 200) {
|
||||
const metadata = operateLimits(res.result);
|
||||
let result;
|
||||
if (props?.type === 'device') {
|
||||
result = await saveMetadata(
|
||||
id as string,
|
||||
metadata,
|
||||
).catch((err) => err);
|
||||
} else {
|
||||
result = await modify(id as string, {
|
||||
id,
|
||||
metadata: JSON.stringify(metadata),
|
||||
}).catch((err) => err);
|
||||
}
|
||||
if (result.success) {
|
||||
onlyMessage('导入成功');
|
||||
}
|
||||
loading.value = false;
|
||||
} else {
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
if (props?.type === 'device') {
|
||||
await instanceStore.refresh(id as string);
|
||||
} else {
|
||||
await productStore.getDetail(id as string);
|
||||
}
|
||||
metadataStore.set('importMetadata', true);
|
||||
close();
|
||||
} catch (e) {
|
||||
onlyMessage(
|
||||
e === 'error'
|
||||
? '物模型数据不正确'
|
||||
: '上传json格式的物模型文件',
|
||||
'error',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
result = await modify(id as string, { id, metadata: JSON.stringify(metadata) }).catch(err => err)
|
||||
}
|
||||
if (result.success) {
|
||||
onlyMessage('导入成功')
|
||||
}
|
||||
loading.value = false
|
||||
} else {
|
||||
loading.value = false
|
||||
// onlyMessage('物模型数据不正确!', 'error')
|
||||
return
|
||||
}
|
||||
if (props?.type === 'device') {
|
||||
await instanceStore.refresh(id as string)
|
||||
} else {
|
||||
await productStore.getDetail(id as string)
|
||||
}
|
||||
metadataStore.set('importMetadata', true)
|
||||
// Store.set(SystemConst.GET_METADATA, true)
|
||||
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
|
||||
close()
|
||||
} else {
|
||||
try {
|
||||
const _object = JSON.parse(data[props?.type === 'device' ? 'import' : data?.type] || '{}')
|
||||
if (
|
||||
!(!!_object?.properties || !!_object?.events || !!_object?.functions || !!_object?.tags)
|
||||
) {
|
||||
onlyMessage('物模型数据不正确', 'error')
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
const { id } = route.params || {}
|
||||
const copyOperateLimits = operateLimits(_object as DeviceMetadata)
|
||||
try {
|
||||
const _object = JSON.parse(
|
||||
data[data?.type === 'copy' ? 'copy' : 'import'] ||
|
||||
'{}',
|
||||
);
|
||||
|
||||
const params = {
|
||||
id,
|
||||
metadata: JSON.stringify(copyOperateLimits),
|
||||
};
|
||||
const paramsDevice = copyOperateLimits
|
||||
|
||||
let resp = undefined
|
||||
if (props?.type === 'device') {
|
||||
resp = await saveMetadata(id as string, paramsDevice)
|
||||
} else {
|
||||
resp = await modify(id as string, params)
|
||||
if (
|
||||
!(
|
||||
!!_object?.properties ||
|
||||
!!_object?.events ||
|
||||
!!_object?.functions ||
|
||||
!!_object?.tags
|
||||
)
|
||||
) {
|
||||
onlyMessage('物模型数据不正确', 'error');
|
||||
loading.value = false;
|
||||
return;
|
||||
}
|
||||
const { id } = route.params || {};
|
||||
const copyOperateLimits = operateLimits(
|
||||
_object as DeviceMetadata,
|
||||
);
|
||||
const params = {
|
||||
id,
|
||||
metadata: JSON.stringify(copyOperateLimits),
|
||||
};
|
||||
const paramsDevice = copyOperateLimits;
|
||||
let resp = undefined;
|
||||
loading.value = true;
|
||||
if (props?.type === 'device') {
|
||||
resp = await saveMetadata(id as string, paramsDevice);
|
||||
} else {
|
||||
resp = await modify(id as string, params);
|
||||
}
|
||||
loading.value = false;
|
||||
if (resp.success) {
|
||||
onlyMessage('导入成功');
|
||||
if (hasVirtualRule.value) {
|
||||
setTimeout(() => {
|
||||
Modal.info({
|
||||
title: '导入数据存在虚拟属性,请及时添加虚拟属性计算规则。',
|
||||
okText: '确认',
|
||||
});
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
if (props?.type === 'device') {
|
||||
await instanceStore.refresh(id as string);
|
||||
} else {
|
||||
await productStore.getDetail(id as string);
|
||||
}
|
||||
metadataStore.set('importMetadata', true);
|
||||
close();
|
||||
} catch (e) {
|
||||
loading.value = false;
|
||||
onlyMessage(
|
||||
e === 'error'
|
||||
? '物模型数据不正确'
|
||||
: '上传json格式的物模型文件',
|
||||
'error',
|
||||
);
|
||||
}
|
||||
}
|
||||
loading.value = false
|
||||
if (resp.success) {
|
||||
onlyMessage('导入成功')
|
||||
if (hasVirtualRule.value) {
|
||||
setTimeout(() => {
|
||||
Modal.info({
|
||||
title: '导入数据存在虚拟属性,请及时添加虚拟属性计算规则。',
|
||||
okText: '确认'
|
||||
})
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
if (props?.type === 'device') {
|
||||
await instanceStore.refresh(id as string)
|
||||
} else {
|
||||
await productStore.getDetail(id as string)
|
||||
}
|
||||
metadataStore.set('importMetadata', true)
|
||||
close();
|
||||
} catch (e) {
|
||||
loading.value = false
|
||||
onlyMessage(e === 'error' ? '物模型数据不正确' : '上传json格式的物模型文件', 'error')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// const showProduct = computed(() => formModel.type === 'copy')
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.import-content {
|
||||
background: rgb(236, 237, 238);
|
||||
background: rgb(236, 237, 238);
|
||||
|
||||
.import-tip {
|
||||
padding: 10px;
|
||||
}
|
||||
.import-tip {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
width: 37px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0 -11px;
|
||||
width: 37px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin: 0 -11px;
|
||||
}
|
||||
</style>
|
|
@ -7,7 +7,7 @@
|
|||
<j-radio-group
|
||||
button-style="solid"
|
||||
v-model:value="data.type"
|
||||
@change="() => { getNetworkEcharts(data) }"
|
||||
@change="changeType"
|
||||
>
|
||||
<j-radio-button value="bytesRead">
|
||||
上行
|
||||
|
@ -109,7 +109,9 @@ const pickerTimeChange = (value: any) => {
|
|||
data.value.time.type = undefined;
|
||||
getNetworkEcharts(data.value);
|
||||
};
|
||||
|
||||
const changeType = (value:any) =>{
|
||||
getNetworkEcharts(data.value);
|
||||
}
|
||||
const getNetworkEcharts = async (val: any) => {
|
||||
loading.value = true;
|
||||
const resp: any = await dashboard(networkParams(val));
|
||||
|
@ -215,6 +217,7 @@ watch(
|
|||
() => data.value.time.type,
|
||||
(value) => {
|
||||
if (value === undefined) return;
|
||||
console.log(value);
|
||||
const date = getTimeByType(value);
|
||||
data.value.time.time = [dayjs(date), dayjs(new Date())];
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
}
|
||||
}"
|
||||
:fieldNames="{ key: 'id', title: 'name' }"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
:fieldNames="{ title: 'name', key: 'id' }"
|
||||
:selectedKeys="[deptId]"
|
||||
@select="onTreeSelect"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
</j-tree>
|
||||
<j-empty v-if="!deptTreeData.length" />
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
:height='450'
|
||||
:virtual='true'
|
||||
@select='treeSelect'
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name, description }">
|
||||
<j-space>
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
:height='450'
|
||||
:virtual='true'
|
||||
@select='treeSelect'
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name, description }">
|
||||
<j-space>
|
||||
|
|
|
@ -1773,7 +1773,7 @@ function clickSave() {
|
|||
}
|
||||
|
||||
//独立应用-api客户端 id?clientId:appId
|
||||
if (params.provider === 'internal-standalone') {
|
||||
if (['internal-standalone', 'third-party'].includes(params.provider)) {
|
||||
if (params.integrationModes.includes('apiClient')) {
|
||||
params.id = params.apiClient.authConfig.oauth2.clientId;
|
||||
}
|
||||
|
@ -1806,7 +1806,6 @@ function clickSave() {
|
|||
key: m.label,
|
||||
}));
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
const request = routeQuery.id
|
||||
? updateApp_api(routeQuery.id as string, params)
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
:fieldNames="{ key: 'code', title: 'name' }"
|
||||
@check="treeCheck"
|
||||
:height="300"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name }">
|
||||
<span>{{ name }}</span>
|
||||
|
|
|
@ -10,11 +10,12 @@
|
|||
<!-- 使用v-if用于解决异步加载数据后不展开的问题 -->
|
||||
<j-tree
|
||||
v-if="leftData.treeData.length > 0"
|
||||
showLine
|
||||
defaultExpandAll
|
||||
:tree-data="leftData.treeData"
|
||||
v-model:selectedKeys="leftData.selectedKeys"
|
||||
@select="onSelect"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ dataRef }">
|
||||
<div
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
v-model:selected-keys="selectedKeys"
|
||||
v-model:expandedKeys="expandedKeys"
|
||||
:fieldNames="{ key: 'id' }"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name, data }">
|
||||
<div class='department-tree-item-content'>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<j-scrollbar>
|
||||
<j-tree
|
||||
v-if="treeData.length !== 0"
|
||||
show-line
|
||||
defaultExpandAll
|
||||
multiple
|
||||
draggable
|
||||
|
@ -22,6 +21,8 @@
|
|||
:selectedKeys="selectedKeys"
|
||||
@drop="onDrop"
|
||||
@dragend="onDragend"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="row">
|
||||
<div class="tree-content">
|
||||
|
|
|
@ -69,9 +69,11 @@ onMounted(() => {
|
|||
iconUrl: iconMap.get(item.id),
|
||||
};
|
||||
});
|
||||
emit('update:value', options.value?.[0]?.value);
|
||||
emit('update:name', options.value?.[0]?.label);
|
||||
emit('change', {label: options.value?.[0]?.label, value: options.value?.[0]?.value});
|
||||
if(!props.value){
|
||||
emit('update:value', options.value?.[0]?.value);
|
||||
emit('update:name', options.value?.[0]?.label);
|
||||
emit('change', {label: options.value?.[0]?.label, value: options.value?.[0]?.value});
|
||||
}
|
||||
}
|
||||
loading.value = false;
|
||||
});
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
:tree-data="treeData"
|
||||
@select="clickSelectItem"
|
||||
v-model:selected-keys="selectedKeys"
|
||||
showLine
|
||||
class="left-tree-container"
|
||||
:showLine="{ showLeafIcon: false }"
|
||||
:show-icon="true"
|
||||
>
|
||||
<template #title="{ name }">
|
||||
{{ name }}
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="basis.recommend" class="bottom">
|
||||
<div v-if="basis.recommend === 'true'" class="bottom">
|
||||
<div class="view">
|
||||
JETLINKS团队全新力作可视化大屏系统
|
||||
</div>
|
||||
|
|
|
@ -94,7 +94,7 @@ export default defineConfig(({ mode}) => {
|
|||
[env.VITE_APP_BASE_API]: {
|
||||
// target: 'http://192.168.32.226:8844',
|
||||
// target: 'http://192.168.32.244:8881',
|
||||
// target: 'http://192.168.32.163:8844', //张季本地
|
||||
// target: 'http://192.168.32.163:8844', //张季本地
|
||||
// target: 'http://120.77.179.54:8844', // 120测试
|
||||
target: 'http://192.168.33.46:8844', // 本地开发环境
|
||||
ws: 'ws://192.168.33.46:8844',
|
||||
|
|
Loading…
Reference in New Issue