fix: bug#15992、15977;优化设备管理、运维管理、告警中心仪表盘

* fix: 修改jetlinks-store

* fix: 优化多余菜单显示

* fix: 设备管理、运维管理、告警中心仪表盘

* fix: bug#15992、15977

* fix: 修改角色管理-编辑接口请求类型
This commit is contained in:
XieYongHong 2023-07-20 13:37:11 +08:00 committed by GitHub
parent 9170030d25
commit bcc85f1dfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 754 additions and 415 deletions

View File

@ -8,6 +8,10 @@ export const delRole_api = (id: string): Promise<any> => server.remove(`/role/${
export const saveRole_api = (data: any): Promise<any> => server.post(`/role`, data); export const saveRole_api = (data: any): Promise<any> => server.post(`/role`, data);
// 更新角色信息 // 更新角色信息
export const updateRole_api = (data: any): Promise<any> => server.patch(`/role`, data); export const updateRole_api = (data: any): Promise<any> => server.patch(`/role`, data);
// 更新角色信息
export const editRole_api = (id: string, data: any): Promise<any> => server.put(`/role/${id}`, data);
// 获取角色详细信息 // 获取角色详细信息
export const getRoleDetails_api = (id: string): Promise<any> => server.get(`/role/${id}`); export const getRoleDetails_api = (id: string): Promise<any> => server.get(`/role/${id}`);
// 获取角色对应的权限树 // 获取角色对应的权限树

View File

@ -2,7 +2,7 @@ export const LoginPath = '/user/login'
export const InitHomePath = '/init-home' export const InitHomePath = '/init-home'
export const AccountCenterBindPath = '/account/center/bind' export const AccountCenterBindPath = '/account/center/bind'
export const InitLicense = '/init-license' export const InitLicense = '/init-license'
export const NotificationSubscriptionCode = 'account/NotificationSubscription' export const NotificationSubscriptionCode = 'message-subscribe'
export const NotificationRecordCode = 'account/NotificationRecord' export const NotificationRecordCode = 'account/NotificationRecord'
export const OauthPath = '/oauth' export const OauthPath = '/oauth'

View File

@ -5,7 +5,7 @@ import { cloneDeep, isArray } from 'lodash-es'
import { usePermissionStore } from './permission' import { usePermissionStore } from './permission'
import router from '@/router' import router from '@/router'
import { onlyMessage } from '@/utils/comm' import { onlyMessage } from '@/utils/comm'
// import { AccountMenu, NotificationRecordCode, NotificationSubscriptionCode } from '@/router/menu' import { AccountMenu, NotificationRecordCode, NotificationSubscriptionCode } from '@/router/menu'
import { USER_CENTER_MENU_CODE } from '@/utils/consts' import { USER_CENTER_MENU_CODE } from '@/utils/consts'
import {isNoCommunity} from "@/utils/utils"; import {isNoCommunity} from "@/utils/utils";
@ -109,6 +109,7 @@ export const useMenuStore = defineStore({
permission.permissions = {} permission.permissions = {}
const { menusData, silderMenus } = filterAsyncRouter(resultData) const { menusData, silderMenus } = filterAsyncRouter(resultData)
this.menus = findCodeRoute([...resultData]) // AccountMenu this.menus = findCodeRoute([...resultData]) // AccountMenu
Object.keys(this.menus).forEach((item) => { Object.keys(this.menus).forEach((item) => {
const _item = this.menus[item] const _item = this.menus[item]
@ -125,7 +126,7 @@ export const useMenuStore = defineStore({
} }
}) })
// menusData.push(AccountMenu) // menusData.push(AccountMenu)
this.siderMenus = silderMenus.filter((item: { name: string }) => ![USER_CENTER_MENU_CODE].includes(item.name)) this.siderMenus = silderMenus.filter((item: { name: string }) => ![USER_CENTER_MENU_CODE, NotificationRecordCode, NotificationSubscriptionCode].includes(item.name))
res(menusData) res(menusData)
} }
}) })

17
src/store/type.ts Normal file
View File

@ -0,0 +1,17 @@
import { defineStore } from "pinia";
export const useTypeStore = defineStore({
id: 'type',
state: () => ({
configRef: [] as any,
resourcesClusters: {} as any,
}),
actions: {
setConfigRef(current: any[]) {
this.configRef = current
},
setResourcesClusters(current: any) {
this.resourcesClusters = current
}
}
})

View File

@ -156,13 +156,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { save, update } from '@/api/data-collect/collector'; import { save, update } from '@/api/data-collect/collector';
import { Store } from 'jetlinks-store';
import { LeftTreeRules } from '../../data'; import { LeftTreeRules } from '../../data';
import type { FormInstance } from 'ant-design-vue'; import type { FormInstance } from 'ant-design-vue';
const loading = ref(false); const loading = ref(false);
const channelListAll = ref();
const channelList = ref();
const visibleEndian = ref(false); const visibleEndian = ref(false);
const visibleUnitId = ref(false); const visibleUnitId = ref(false);
@ -171,6 +168,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
channelListAll: {
type: Array,
default: () => []
}
}); });
const emit = defineEmits(['change']); const emit = defineEmits(['change']);
@ -178,6 +179,16 @@ const emit = defineEmits(['change']);
const id = props.data.id; const id = props.data.id;
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const _channelListAll = computed(() => {
return props.channelListAll || [];
})
const channelList = computed(() => {
return _channelListAll.value.map((item: any) => ({
value: item.id,
label: item.name,
}));
})
const endianData = computed(() => { const endianData = computed(() => {
const { endian, endianIn } = formData.value.configuration; const { endian, endianIn } = formData.value.configuration;
@ -213,7 +224,7 @@ const formData = ref({
const handleOk = async () => { const handleOk = async () => {
const data = await formRef.value?.validate(); const data = await formRef.value?.validate();
const { provider, name } = channelListAll.value.find( const { provider, name } = _channelListAll.value.find(
(item: any) => item.id === formData.value.channelId, (item: any) => item.id === formData.value.channelId,
); );
const params = { const params = {
@ -252,14 +263,6 @@ const changeCardSelectEndian = (value: Array<string>) => {
const changeCardSelectEndianIn = (value: Array<string>) => { const changeCardSelectEndianIn = (value: Array<string>) => {
formData.value.configuration.endianIn = value[0]; formData.value.configuration.endianIn = value[0];
}; };
const getChannelNoPaging = async () => {
channelListAll.value = Store.get('channelListAll');
channelList.value = channelListAll.value.map((item) => ({
value: item.id,
label: item.name,
}));
};
getChannelNoPaging();
const filterOption = (input: string, option: any) => { const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0; return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
@ -268,7 +271,7 @@ const filterOption = (input: string, option: any) => {
watch( watch(
() => formData.value.channelId, () => formData.value.channelId,
(value) => { (value) => {
const dt = channelListAll.value.find((item) => item.id === value); const dt = _channelListAll.value.find((item) => item.id === value);
visibleUnitId.value = visibleEndian.value = visibleUnitId.value = visibleEndian.value =
dt?.provider && dt?.provider === 'MODBUS_TCP'; dt?.provider && dt?.provider === 'MODBUS_TCP';
}, },

View File

@ -111,7 +111,7 @@
</j-tree> </j-tree>
<j-empty v-else description="暂无数据" /> <j-empty v-else description="暂无数据" />
</j-spin> </j-spin>
<Save v-if="visible" :data="current" @change="saveChange" /> <Save :channelListAll="channelListAll" v-if="visible" :data="current" @change="saveChange" />
</div> </div>
</template> </template>
@ -124,7 +124,6 @@ import {
} from '@/api/data-collect/collector'; } from '@/api/data-collect/collector';
import Save from './Save/index.vue'; import Save from './Save/index.vue';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { Store } from 'jetlinks-store';
import _ from 'lodash'; import _ from 'lodash';
import { colorMap } from '../data.ts'; import { colorMap } from '../data.ts';
@ -144,6 +143,7 @@ const searchValue = ref();
const visible = ref(false); const visible = ref(false);
const current = ref({}); const current = ref({});
const collectorAll = ref(); const collectorAll = ref();
const channelListAll = ref<any[]>([])
const root = [ const root = [
{ {
@ -274,8 +274,8 @@ const handleSearch = async (value: any) => {
}; };
const getChannelNoPaging = async () => { const getChannelNoPaging = async () => {
const res = await queryChannelNoPaging(); const res: any = await queryChannelNoPaging();
Store.set('channelListAll', res.result); channelListAll.value = res.result;
}; };
const treeSelect = (keys: string, e: any) => { const treeSelect = (keys: string, e: any) => {

View File

@ -15,11 +15,11 @@
:bodyStyle="{ padding: 0 }" :bodyStyle="{ padding: 0 }"
:defaultParams="defaultParams" :defaultParams="defaultParams"
> >
<template #rightExtraRender> <!-- <template #rightExtraRender>
<j-popconfirm title="确认全部已读?" @confirm="onAllRead"> <j-popconfirm title="确认全部已读?" @confirm="onAllRead">
<j-button type="primary">全部已读</j-button> <j-button type="primary">全部已读</j-button>
</j-popconfirm> </j-popconfirm>
</template> </template> -->
<template #topicProvider="slotProps"> <template #topicProvider="slotProps">
{{ slotProps.topicName }} {{ slotProps.topicName }}
</template> </template>
@ -240,14 +240,14 @@ watchEffect(() => {
} }
}); });
const onAllRead = async () => { // const onAllRead = async () => {
const resp = await changeAllStatus('_read', getType.value); // const resp = await changeAllStatus('_read', getType.value);
if (resp.status === 200) { // if (resp.status === 200) {
onlyMessage('操作成功!'); // onlyMessage('');
refresh(); // refresh();
user.updateAlarm(); // user.updateAlarm();
} // }
}; // };
onMounted(() => { onMounted(() => {
if (routerParams.params?.value.row) { if (routerParams.params?.value.row) {

View File

@ -82,11 +82,13 @@ const getTimeByType = (type: string) => {
case 'hour': case 'hour':
return dayjs().subtract(1, 'hours').valueOf(); return dayjs().subtract(1, 'hours').valueOf();
case 'week': case 'week':
return dayjs().subtract(6, 'days').valueOf(); return dayjs().subtract(6, 'days').startOf('day').valueOf();
case 'month': case 'month':
return dayjs().subtract(29, 'days').valueOf(); return dayjs().subtract(29, 'days').valueOf();
case 'year': case 'year':
return dayjs().subtract(365, 'days').valueOf(); return dayjs().subtract(365, 'days').valueOf();
case 'day':
return dayjs().subtract(24, 'hours').valueOf();
default: default:
return dayjs().startOf('day').valueOf(); return dayjs().startOf('day').valueOf();
} }

View File

@ -42,6 +42,11 @@
<template #extra> <template #extra>
<TimeSelect <TimeSelect
key="flow-static" key="flow-static"
:quickBtnList="[
{ label: '最近1小时', value: 'hour' },
{ label: '最近24小时', value: 'day' },
{ label: '近一周', value: 'week' },
]"
:type="'week'" :type="'week'"
@change="getEcharts" @change="getEcharts"
/> />
@ -539,20 +544,25 @@ const getDevice = () => {
}; };
const getEcharts = (data: any) => { const getEcharts = (data: any) => {
let _time = '1h'; let _time = '1m';
let format = 'HH'; let format = 'M月dd日 HH:mm';
let limit = 12; let limit = 12;
const dt = data.end - data.start; const dt = data.end - data.start;
const hour = 60 * 60 * 1000; const hour = 60 * 60 * 1000;
const days = hour * 24; const days = hour * 24;
const months = days * 30; const months = days * 30;
const year = 365 * days; const year = 365 * days;
if (dt <= days) { if (dt <= (hour + 10)) {
limit = Math.abs(Math.ceil(dt / hour)); limit = 60
format = 'HH:mm';
} else if (dt > hour && dt <= days) {
_time = '1h'
limit = 24;
} else if (dt > days && dt < year) { } else if (dt > days && dt < year) {
limit = Math.abs(Math.ceil(dt / days)) + 1; limit = Math.abs(Math.ceil(dt / days)) + 1;
_time = '1d'; _time = '1d';
format = 'M月dd日'; format = 'M月dd日 HH:mm:ss';
} else if (dt >= year) { } else if (dt >= year) {
limit = Math.abs(Math.floor(dt / months)); limit = Math.abs(Math.floor(dt / months));
_time = '1M'; _time = '1M';

View File

@ -88,7 +88,13 @@
</template> </template>
<script setup lang="ts" name="BindChildDevice"> <script setup lang="ts" name="BindChildDevice">
import { query, queryByParent, bindDevice, queryDeviceMapping, saveDeviceMapping } from '@/api/device/instance'; import {
query,
queryByParent,
bindDevice,
queryDeviceMapping,
saveDeviceMapping,
} from '@/api/device/instance';
import moment from 'moment'; import moment from 'moment';
import { useInstanceStore } from '@/store/instance'; import { useInstanceStore } from '@/store/instance';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@ -97,9 +103,9 @@ import { onlyMessage } from '@/utils/comm';
const props = defineProps({ const props = defineProps({
parentIds: { parentIds: {
type: Array, type: Array,
default: () => [] default: () => [],
} },
}) });
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
const { detail } = storeToRefs(instanceStore); const { detail } = storeToRefs(instanceStore);
@ -176,13 +182,16 @@ const handleSearch = (e: any) => {
const onSelectChange = (keys: string[], rows: string[]) => { const onSelectChange = (keys: string[], rows: string[]) => {
_selectedRowKeys.value = [...keys]; _selectedRowKeys.value = [...keys];
console.log(rows) console.log(rows);
_selectedRowMap.value = rows.map(item => ({ deviceId: item.id, deviceName: item.name})) _selectedRowMap.value = rows.map((item) => ({
deviceId: item.id,
deviceName: item.name,
}));
}; };
const cancelSelect = () => { const cancelSelect = () => {
_selectedRowKeys.value = []; _selectedRowKeys.value = [];
_selectedRowMap.value = [] _selectedRowMap.value = [];
}; };
const handleOk = () => { const handleOk = () => {
@ -191,28 +200,34 @@ const handleOk = () => {
return; return;
} }
btnLoading.value = true; btnLoading.value = true;
if (instanceStore.current.accessProvider === 'official-edge-gateway') { // if (instanceStore.current.accessProvider === 'official-edge-gateway') {
//
queryDeviceMapping(instanceStore.current.id) queryDeviceMapping(instanceStore.current.id)
.then(res => { .then((res) => {
const arr = bindDeviceRef.value?._dataSource.filter((item: any) => { const arr = bindDeviceRef.value?._dataSource
return _selectedRowKeys.value.includes(item.id); .filter((item) => {
}).map((item: any) => { return (
const _item = res.result?.[0]?.find((val: any) => val.deviceId === item.id) !res.result?.[0]?.find(
if(_item){ (val) => val.deviceId === item.id,
return { ) && _selectedRowKeys.value.includes(item.id)
id: _item.id, );
deviceId: _item.deviceId, })
deviceName: _item.deviceName .map((item) => {
}
}else {
return { return {
deviceId: item.id, deviceId: item.id,
deviceName: item.name deviceName: item.name,
} };
});
if(arr.length){
return saveDeviceMapping(instanceStore.current.id, {
info: arr,
});
} }
}) })
return saveDeviceMapping(instanceStore.current.id, {info: arr}) .then((res) => {
}).then(res => { return bindDevice(detail.value.id, _selectedRowKeys.value);
})
.then((res) => {
emit('change', true); emit('change', true);
cancelSelect(); cancelSelect();
onlyMessage('操作成功'); onlyMessage('操作成功');
@ -221,21 +236,21 @@ const handleOk = () => {
btnLoading.value = false; btnLoading.value = false;
}); });
} else { } else {
bindDevice(detail.value.id, _selectedRowKeys.value).then(res => { bindDevice(detail.value.id, _selectedRowKeys.value)
.then((res) => {
emit('change', true); emit('change', true);
cancelSelect(); cancelSelect();
onlyMessage('操作成功'); onlyMessage('操作成功');
}).finally(() => { })
.finally(() => {
btnLoading.value = false; btnLoading.value = false;
}); });
} }
}; };
const handleCancel = () => { const handleCancel = () => {
emit('change', false); emit('change', false);
}; };
</script> </script>
<style scoped lang="less"></style> <style scoped lang="less"></style>

View File

@ -16,9 +16,11 @@
<j-tree <j-tree
checkable checkable
:height="300" :height="300"
:tree-data="dataSource" :tree-data="treeList"
:checkedKeys="checkedKeys" :checkedKeys="checkedKeys"
:load-data="onLoadData"
@check="onCheck" @check="onCheck"
v-model:expandedKeys="expandedKeys"
/> />
</j-card> </j-card>
<div style="width: 100px"> <div style="width: 100px">
@ -56,8 +58,17 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { treeEdgeMap, saveEdgeMap, addDevice } from '@/api/device/instance'; import {
treeEdgeMap,
saveEdgeMap,
addDevice,
edgeChannel,
edgeCollector,
edgePoint,
saveDeviceMapping,
} from '@/api/device/instance';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import type { TreeProps } from 'ant-design-vue';
const _props = defineProps({ const _props = defineProps({
metaData: { metaData: {
type: Array, type: Array,
@ -74,6 +85,9 @@ const _props = defineProps({
deviceData: { deviceData: {
type: Object, type: Object,
}, },
text: {
type: String,
}
}); });
const _emits = defineEmits(['close', 'save']); const _emits = defineEmits(['close', 'save']);
@ -113,8 +127,10 @@ const handleSearch = async () => {
} }
}; };
const expandedKeys = ref<string[]>([]);
const onCheck = (keys: string[], e: any) => { const onCheck = (keys: string[], e: any) => {
checkedKeys.value = [...keys]; checkedKeys.value = [...keys];
expandedKeys.value.push(e.node.id);
leftList.value = e?.checkedNodes || []; leftList.value = e?.checkedNodes || [];
}; };
@ -123,6 +139,71 @@ const onRight = () => {
rightList.value = leftList.value; rightList.value = leftList.value;
}; };
const treeList = ref<any[]>([]);
const getChannel = async () => {
if (_props.edgeId) {
loading.value = true;
const resp: any = await edgeChannel(_props.edgeId);
loading.value = false;
if (resp.status === 200) {
treeList.value = resp.result?.[0]?.map((item: any) => ({
...item,
title: item.name,
key: item.id,
checkable: false,
type: 'channel',
parentId: '',
provider: item.provider,
}));
}
}
};
const onLoadData: TreeProps['loadData'] = (treeNode) => {
console.log(treeNode);
return new Promise(async (resolve) => {
if (treeNode.dataRef?.children) {
resolve();
return;
}
const params = {
terms: [
{
terms: [
{
column:
treeNode.type === 'channel'
? 'channelId'
: 'collectorId',
value: treeNode.key,
},
],
},
],
};
const res =
treeNode.type === 'channel'
? await edgeCollector(
<string>_props.edgeId,
params,
)
: await edgePoint(
<string>_props.edgeId,
params,
);
(<any>treeNode.dataRef).children = res.result?.[0].map((item: any) => ({
...item,
title: item.name,
key: item.id,
type: treeNode.type === 'channel' ? 'collector' : 'point',
parentId: treeNode.key,
checkable: treeNode.type === 'channel' ? true : false,
isLeaf: treeNode.type === 'channel' ? false : true,
}));
treeList.value = [...treeList.value];
resolve();
});
};
const _delete = (_key: string) => { const _delete = (_key: string) => {
const _index = rightList.value.findIndex((i) => i.key === _key); const _index = rightList.value.findIndex((i) => i.key === _key);
rightList.value.splice(_index, 1); rightList.value.splice(_index, 1);
@ -144,7 +225,7 @@ const handleClick = async () => {
metadataId: (_props.metaData as any[]).find( metadataId: (_props.metaData as any[]).find(
(i: any) => i.name === element.name, (i: any) => i.name === element.name,
)?.metadataId, )?.metadataId,
provider: dataSource.value.find( provider: treeList.value.find(
(it: any) => it.id === item.parentId, (it: any) => it.id === item.parentId,
).provider, ).provider,
})); }));
@ -167,13 +248,19 @@ const handleClick = async () => {
} }
} else { } else {
if (filterParms && filterParms.length !== 0) { if (filterParms && filterParms.length !== 0) {
const res = await addDevice(_props.deviceData); const res: any = await addDevice(_props.deviceData);
if (res.status === 200) { if (res.status === 200) {
const resq = await saveEdgeMap(_props.edgeId, { const resq: any = await saveEdgeMap(_props.edgeId, {
deviceId: res.result?.id, deviceId: res.result?.id,
provider: filterParms[0]?.provider, provider: filterParms[0]?.provider,
requestList: filterParms, requestList: filterParms,
}); });
const resp = await saveDeviceMapping(_props.edgeId, {
info: [{
deviceId: res.result?.id,
deviceName: res.result?.name,
}],
})
if (res.status === 200) { if (res.status === 200) {
onlyMessage('操作成功'); onlyMessage('操作成功');
_emits('save'); _emits('save');
@ -191,7 +278,8 @@ const handleClose = () => {
onMounted(() => { onMounted(() => {
if (_props.edgeId) { if (_props.edgeId) {
handleSearch(); // handleSearch();
getChannel();
} }
}); });
</script> </script>

View File

@ -20,6 +20,7 @@
:checkedKeys="checkedKeys" :checkedKeys="checkedKeys"
:load-data="onLoadData" :load-data="onLoadData"
@check="onCheck" @check="onCheck"
v-model:expandedKeys="expandedKeys"
/> />
</j-card> </j-card>
<div style="width: 100px"> <div style="width: 100px">
@ -120,7 +121,11 @@ const handleSearch = async () => {
} }
}; };
const expandedKeys = ref<string[]>([])
const onCheck = (keys: string[], e: any) => { const onCheck = (keys: string[], e: any) => {
// console.log(expandedKeys.push(e));
expandedKeys.value.push(e.node.id)
checkedKeys.value = [...keys]; checkedKeys.value = [...keys];
leftList.value = e?.checkedNodes || []; leftList.value = e?.checkedNodes || [];
}; };

View File

@ -51,9 +51,6 @@
<template #valueType="{ data }"> <template #valueType="{ data }">
{{ TypeStringMap[data.record.valueType?.type] }} {{ TypeStringMap[data.record.valueType?.type] }}
</template> </template>
<template #expands="{ data }">
{{ sourceMap?.[data.record?.expands?.source] || '' }}
</template>
<template #inputs="{ data }"> <template #inputs="{ data }">
<InputParams v-model:value="data.record.inputs" /> <InputParams v-model:value="data.record.inputs" />
</template> </template>
@ -66,6 +63,9 @@
<template #expands="{ data }" v-if="type === 'events'"> <template #expands="{ data }" v-if="type === 'events'">
{{ levelMap?.[data.record.expands?.level] || '-' }} {{ levelMap?.[data.record.expands?.level] || '-' }}
</template> </template>
<template v-else-if="type === 'properties'" #expands="{ data }">
{{ data.record.id && !data.record?.expands?.source ? '设备' : sourceMap?.[data.record?.expands?.source] || '' }}
</template>
<template #properties="{ data }"> <template #properties="{ data }">
<ConfigParams v-model:value="data.record.valueType" /> <ConfigParams v-model:value="data.record.valueType" />
</template> </template>
@ -80,7 +80,7 @@
<template #other="{ data }"> <template #other="{ data }">
<j-tooltip <j-tooltip
v-if="target === 'device' && productNoEdit.id?.includes?.(data.record._sortIndex)" v-if="target === 'device' && productNoEdit.id?.includes?.(data.record._sortIndex)"
title="继承自产品物模型的数据不支持删除" title="继承自产品物模型的数据不支持修改"
> >
<!-- <ModelButton :disabled="true"/>--> <!-- <ModelButton :disabled="true"/>-->
<j-button :disabled="true" type="link" style="padding-left: 0;"> <j-button :disabled="true" type="link" style="padding-left: 0;">

View File

@ -59,7 +59,6 @@ import { DataTypeList, FileTypeList } from '@/views/device/data';
import { DefaultOptionType, SelectValue } from 'ant-design-vue/es/select'; import { DefaultOptionType, SelectValue } from 'ant-design-vue/es/select';
import { PropType } from 'vue' import { PropType } from 'vue'
import { getUnit } from '@/api/device/instance'; import { getUnit } from '@/api/device/instance';
import { Store } from 'jetlinks-store';
import InputSelect from '@/components/InputSelect/index.vue'; import InputSelect from '@/components/InputSelect/index.vue';
import BooleanParam from '@/components/Metadata/BooleanParam/index.vue' import BooleanParam from '@/components/Metadata/BooleanParam/index.vue'
import EnumParam from '@/components/Metadata/EnumParam/index.vue' import EnumParam from '@/components/Metadata/EnumParam/index.vue'
@ -140,7 +139,6 @@ const unit = reactive({
value: item.id, value: item.id,
})); }));
// //
Store.set('units', _data);
unit.unitOptions = _data; unit.unitOptions = _data;
}) })
}, },

View File

@ -416,7 +416,7 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
name: Source, name: Source,
props: { props: {
noEdit: noEdit?.value?.source || [], noEdit: noEdit?.value?.source || [],
target: target target: target,
} }
}, },
doubleClick(record){ doubleClick(record){
@ -434,7 +434,6 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
rules: target !== 'device' ? [ rules: target !== 'device' ? [
{ {
callback: async (rule: any, value: any, dataSource: any[]) => { callback: async (rule: any, value: any, dataSource: any[]) => {
console.log('value', value)
const field = rule.field.split('.') const field = rule.field.split('.')
const fieldIndex = Number(field[1]) const fieldIndex = Number(field[1])
@ -455,24 +454,6 @@ export const useColumns = (type?: MetadataType, target?: 'device' | 'product', n
return Promise.reject('请选择属性来源'); return Promise.reject('请选择属性来源');
} }
// if (value.source) {
// if(value.source !== 'rule') {
// if(value.type?.length) {
// return Promise.resolve();
// } else {
// return Promise.reject('请选择读写类型');
// }
// } else {
// if(value.virtualRule?.script) {
// return Promise.resolve();
// }else {
// return Promise.reject('请配置规则');
// }
// }
// } else {
// return Promise.reject('请选择属性来源');
// }
// }
}, },
]: [] ]: []
}, },

View File

@ -28,7 +28,7 @@
</div> </div>
</j-scrollbar> </j-scrollbar>
</template> </template>
<j-button :disabled="!myValue" type="link" style="padding: 4px 8px"> <j-button style="padding: 4px 8px" type="link">
<AIcon type="EditOutlined" /> <AIcon type="EditOutlined" />
</j-button> </j-button>
</j-popconfirm-modal> </j-popconfirm-modal>
@ -146,7 +146,11 @@ const confirm = async () => {
watch( watch(
() => props.value, () => props.value,
() => { () => {
if (props.value.id && !props.value?.expands?.source) {
myValue.value = 'device';
} else {
myValue.value = props.value?.expands?.source || ''; myValue.value = props.value?.expands?.source || '';
}
type.value = props.value?.expands?.type || []; type.value = props.value?.expands?.type || [];
}, },
{ immediate: true }, { immediate: true },

View File

@ -23,14 +23,10 @@
<j-radio-button value="hour"> <j-radio-button value="hour">
最近1小时 最近1小时
</j-radio-button> </j-radio-button>
<j-radio-button value="today"> <j-radio-button value="day"> 最近24小时 </j-radio-button>
今日 <j-radio-button value="week"> 近一周 </j-radio-button>
</j-radio-button> </j-radio-group>
<j-radio-button value="week"> </template>
近一周
</j-radio-button>
</j-radio-group></template
>
</j-range-picker> </j-range-picker>
</div> </div>
<div> <div>
@ -38,18 +34,26 @@
v-if="isEmpty" v-if="isEmpty"
style="height: 200px; margin-top: 100px" style="height: 200px; margin-top: 100px"
/> />
<div <template v-else>
v-else <div style="height: 300px">
ref="chartRef" <Echarts
style="width: 100%; height: 300px" :options="echartsOptions"
></div> />
</div>
<ServerList
v-if="serverOptions.length > 1"
v-model:value="serverActive"
:options="serverOptions"
color="#2CB6E0"
/>
</template>
</div> </div>
</div> </div>
</j-spin> </j-spin>
</template> </template>
m m
<script lang="ts" setup name="Cpu"> <script lang="ts" setup name="Cpu">
import * as echarts from 'echarts';
import { dashboard } from '@/api/link/dashboard'; import { dashboard } from '@/api/link/dashboard';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { import {
@ -60,7 +64,8 @@ import {
typeDataLine, typeDataLine,
} from './tool.ts'; } from './tool.ts';
import { DataType } from '../typings'; import { DataType } from '../typings';
import ServerList from './ServerList.vue'
import Echarts from './echarts.vue'
const props = defineProps({ const props = defineProps({
serviceId: { serviceId: {
@ -80,10 +85,53 @@ const data = ref<DataType>({
time: [null, null], time: [null, null],
}); });
const isEmpty = ref(false); const isEmpty = ref(false);
const serverActive = ref<string[]>([])
const serverOptions = ref<string[]>([])
const serverData = reactive({
xAxis: [],
data: []
})
const pickerTimeChange = () => { const pickerTimeChange = () => {
data.value.type = undefined; data.value.type = undefined;
}; };
const echartsOptions = computed(() => {
const series = serverActive.value.length
? serverActive.value.map((key) => setOptions(serverData.data, key))
: typeDataLine
return {
xAxis: {
type: 'category',
boundaryGap: false,
data: arrayReverse(serverData.xAxis),
},
tooltip: {
trigger: 'axis',
valueFormatter: (value: any) => `${value}%`,
},
yAxis: {
type: 'value',
},
grid: {
left: '50px',
right: '50px',
},
dataZoom: [
{
type: 'inside',
start: 0,
end: data.value.type !== 'hour' ? 5 : 100,
},
{
start: 0,
end: data.value.type !== 'hour' ? 5 : 100,
},
],
color: ['#2CB6E0'],
series: series
};
})
const getCPUEcharts = async (val: any) => { const getCPUEcharts = async (val: any) => {
loading.value = true; loading.value = true;
const res: any = await dashboard(defulteParamsData('cpu', val)); const res: any = await dashboard(defulteParamsData('cpu', val));
@ -129,50 +177,12 @@ const setOptions = (optionsData: any, key: string) => ({
}); });
const handleCpuOptions = (optionsData: any, xAxis: any) => { const handleCpuOptions = (optionsData: any, xAxis: any) => {
if (optionsData.length === 0 && xAxis.length === 0) return;
const chart: any = chartRef.value;
if (chart) {
const myChart = echarts.init(chart);
const dataKeys = Object.keys(optionsData); const dataKeys = Object.keys(optionsData);
const options = { serverActive.value = dataKeys
xAxis: { serverOptions.value = dataKeys
type: 'category', serverData.xAxis = xAxis
boundaryGap: false, serverData.data = optionsData
data: arrayReverse(xAxis),
},
tooltip: {
trigger: 'axis',
valueFormatter: (value: any) => `${value}%`,
},
yAxis: {
type: 'value',
},
grid: {
left: '50px',
right: '50px',
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
color: ['#2CB6E0'],
series: dataKeys.length
? dataKeys.map((key) => setOptions(optionsData, key))
: typeDataLine,
};
myChart.setOption(options);
window.addEventListener('resize', function () {
myChart.resize();
});
} }
};
watch( watch(
() => data.value.type, () => data.value.type,
@ -180,18 +190,19 @@ watch(
if (value === undefined) return; if (value === undefined) return;
const date = getTimeByType(value); const date = getTimeByType(value);
data.value.time = [dayjs(date), dayjs(new Date())]; data.value.time = [dayjs(date), dayjs(new Date())];
if (props.isNoCommunity) {
getCPUEcharts(data.value);
}
}, },
{ immediate: true, deep: true }, { immediate: true, deep: true },
); );
watchEffect(() => { // watchEffect(() => {
const time = data.value.time // const time = data.value.time
if (time && Array.isArray(time) && time.length === 2 && time[0]) { // if (time && Array.isArray(time) && time.length === 2 && time[0]) {
if (!props.isNoCommunity || props.serviceId) { //
getCPUEcharts(data.value); // }
} // })
}
})
</script> </script>

View File

@ -23,12 +23,8 @@
<j-radio-button value="hour"> <j-radio-button value="hour">
最近1小时 最近1小时
</j-radio-button> </j-radio-button>
<j-radio-button value="today"> <j-radio-button value="day"> 最近24小时 </j-radio-button>
今日 <j-radio-button value="week"> 近一周 </j-radio-button>
</j-radio-button>
<j-radio-button value="week">
近一周
</j-radio-button>
</j-radio-group></template </j-radio-group></template
> >
</j-range-picker> </j-range-picker>
@ -38,18 +34,26 @@
v-if="isEmpty" v-if="isEmpty"
style="height: 200px; margin-top: 100px" style="height: 200px; margin-top: 100px"
/> />
<div <template v-else>
v-else <div style="height: 300px">
ref="chartRef" <Echarts
style="width: 100%; height: 300px" :options="echartsOptions"
></div> />
</div>
<ServerList
v-if="serverOptions.length > 1"
v-model:value="serverActive"
:options="serverOptions"
color="#60DFC7"
/>
</template>
</div> </div>
</div> </div>
</j-spin> </j-spin>
</template> </template>
<script lang="ts" setup name="Jvm"> <script lang="ts" setup name="Jvm">
import * as echarts from 'echarts';
import { dashboard } from '@/api/link/dashboard'; import { dashboard } from '@/api/link/dashboard';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { import {
@ -60,6 +64,8 @@ import {
defulteParamsData, defulteParamsData,
} from './tool.ts'; } from './tool.ts';
import { DataType } from '../typings'; import { DataType } from '../typings';
import ServerList from './ServerList.vue'
import Echarts from './echarts.vue'
const props = defineProps({ const props = defineProps({
serviceId: { serviceId: {
@ -79,6 +85,13 @@ const data = ref<DataType>({
time: [null, null], time: [null, null],
}); });
const isEmpty = ref(false); const isEmpty = ref(false);
const serverActive = ref<string[]>([])
const serverOptions = ref<string[]>([])
const serverData = reactive({
xAxis: [],
data: []
})
const pickerTimeChange = () => { const pickerTimeChange = () => {
data.value.type = undefined; data.value.type = undefined;
}; };
@ -131,16 +144,22 @@ const setOptions = (optionsData: any, key: string) => ({
areaStyle: areaStyleJvm, areaStyle: areaStyleJvm,
}); });
const handleJVMOptions = (optionsData: any, xAxis: any) => { const handleJVMOptions = (optionsData: any, xAxis: any) => {
if (optionsData.length === 0 && xAxis.length === 0) return;
const chart: any = chartRef.value;
if (chart) {
const myChart = echarts.init(chart);
const dataKeys = Object.keys(optionsData); const dataKeys = Object.keys(optionsData);
const options = { serverActive.value = dataKeys
serverOptions.value = dataKeys
serverData.xAxis = xAxis
serverData.data = optionsData
};
const echartsOptions = computed(() => {
const series = serverActive.value.length
? serverActive.value.map((key) => setOptions(serverData.data, key))
: typeDataLine
return {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: arrayReverse(xAxis), data: arrayReverse(serverData.xAxis),
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -157,24 +176,17 @@ const handleJVMOptions = (optionsData: any, xAxis: any) => {
{ {
type: 'inside', type: 'inside',
start: 0, start: 0,
end: 100, end: data.value.type !== 'hour' ? 10 : 100,
}, },
{ {
start: 0, start: 0,
end: 100, end: data.value.type !== 'hour' ? 10 : 100,
}, },
], ],
color: ['#60DFC7'], color: ['#60DFC7'],
series: dataKeys.length series: series
? dataKeys.map((key) => setOptions(optionsData, key))
: typeDataLine,
};
myChart.setOption(options);
window.addEventListener('resize', function () {
myChart.resize();
});
} }
}; })
watch( watch(
() => data.value.type, () => data.value.type,
@ -182,18 +194,20 @@ watch(
if (value === undefined) return; if (value === undefined) return;
const date = getTimeByType(value); const date = getTimeByType(value);
data.value.time = [dayjs(date), dayjs(new Date())]; data.value.time = [dayjs(date), dayjs(new Date())];
if (props.isNoCommunity) {
getJVMEcharts(data.value);
}
}, },
{ immediate: true, deep: true }, { immediate: true, deep: true },
); );
watchEffect(() => { // watchEffect(() => {
const time = data.value.time // const time = data.value.time
if (time && Array.isArray(time) && time.length === 2 && time[0]) { // if (time && Array.isArray(time) && time.length === 2 && time[0]) {
if (!props.isNoCommunity || props.serviceId) { //
getJVMEcharts(data.value); // }
} // })
}
})
</script> </script>

View File

@ -26,7 +26,7 @@
<j-radio-button value="hour"> <j-radio-button value="hour">
最近1小时 最近1小时
</j-radio-button> </j-radio-button>
<j-radio-button value="today"> 今日 </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
@ -47,11 +47,20 @@
v-if="isEmpty" v-if="isEmpty"
style="height: 250px; margin-top: 100px" style="height: 250px; margin-top: 100px"
/> />
<div <template v-else>
v-else <div style="height: 300px">
ref="chartRef" <Echarts
style="width: 100%; height: 350px" :options="echartsOptions"
></div> />
</div>
<ServerList
v-if="serverOptions.length > 1"
v-model:value="serverActive"
:options="serverOptions"
color="#979AFF"
/>
</template>
</div> </div>
</div> </div>
</j-spin> </j-spin>
@ -63,11 +72,12 @@ import {
getTimeByType, getTimeByType,
typeDataLine, typeDataLine,
areaStyle, areaStyle,
networkParams, networkParams, arrayReverse,
} from './tool.ts'; } from './tool.ts';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import * as echarts from 'echarts';
import { DataType } from '../typings.d'; import { DataType } from '../typings.d';
import ServerList from './ServerList.vue'
import Echarts from './echarts.vue'
const props = defineProps({ const props = defineProps({
serviceId: { serviceId: {
@ -86,6 +96,13 @@ const data = ref<DataType>({
}, },
}); });
const isEmpty = ref(false); const isEmpty = ref(false);
const serverActive = ref<string[]>([])
const serverOptions = ref<string[]>([])
const serverData = reactive({
xAxis: [],
data: []
})
const pickerTimeChange = (value: any) => { const pickerTimeChange = (value: any) => {
data.value.time.type = undefined; data.value.time.type = undefined;
}; };
@ -97,7 +114,8 @@ 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) {
const filterArray = resp.result.filter((item : any) => item.data?.clusterNodeId === props.serviceId) const filterArray = resp.result
// 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> = [];
@ -151,16 +169,22 @@ const setOptions = (data: any, key: string) => ({
}); });
const handleNetworkOptions = (optionsData: any, xAxis: any) => { const handleNetworkOptions = (optionsData: any, xAxis: any) => {
if (optionsData.length === 0 && xAxis.length === 0) return;
const chart: any = chartRef.value;
if (chart) {
const myChart = echarts.init(chart);
const dataKeys = Object.keys(optionsData); const dataKeys = Object.keys(optionsData);
const options = { serverActive.value = dataKeys
serverOptions.value = dataKeys
serverData.xAxis = xAxis
serverData.data = optionsData
};
const echartsOptions = computed(() => {
const series = serverActive.value.length
? serverActive.value.map((key) => setOptions(serverData.data, key))
: typeDataLine
return {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: xAxis, data: serverData.xAxis,
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
@ -170,7 +194,7 @@ const handleNetworkOptions = (optionsData: any, xAxis: any) => {
}, },
grid: { grid: {
left: '70px', left: '70px',
right: 10, right: data.value.time.type === 'week' ? 50 :10,
bottom: '24px', bottom: '24px',
top: 24 top: 24
}, },
@ -179,16 +203,9 @@ const handleNetworkOptions = (optionsData: any, xAxis: any) => {
formatter: (_value: any) => networkValueRender(_value[0]), formatter: (_value: any) => networkValueRender(_value[0]),
}, },
color: ['#979AFF'], color: ['#979AFF'],
series: dataKeys.length series: series
? dataKeys.map((key) => setOptions(optionsData, key))
: typeDataLine,
};
myChart.setOption(options);
window.addEventListener('resize', function () {
myChart.resize();
});
}
}; };
})
watch( watch(
() => data.value.time.type, () => data.value.time.type,
@ -196,16 +213,18 @@ watch(
if (value === undefined) return; if (value === undefined) return;
const date = getTimeByType(value); const date = getTimeByType(value);
data.value.time.time = [dayjs(date), dayjs(new Date())]; data.value.time.time = [dayjs(date), dayjs(new Date())];
getNetworkEcharts(data.value);
}, },
{ immediate: true, deep: true }, { immediate: true, deep: true },
); );
watchEffect(() => { // watchEffect(() => {
const time = data.value.time.time // const time = data.value.time.time
if (time && Array.isArray(time) && time.length === 2 && time[0] && props.serviceId) { // if (time && Array.isArray(time) && time.length === 2 && time[0] && props.serviceId) {
getNetworkEcharts(data.value); //
} // }
}) // })
</script> </script>

View File

@ -0,0 +1,79 @@
<template>
<div class="server-list-warp">
<j-scrollbar>
<div class="server-list-items">
<div
v-for="item in options" :class="['server-item', myValue.includes(item) ? 'active' : '']"
@click="() => change(item)"
>
<j-badge :color=" myValue.includes(item) ? color : '#a3a3a3'" :text="item" />
</div>
</div>
</j-scrollbar>
</div>
</template>
<script lang="ts" name="ServerList" setup>
const props = defineProps({
options: {
type: Array,
default: () => []
},
value: {
type: Array,
default: () => []
},
color: {
type: String,
default: '#979AFF'
}
})
const emit = defineEmits(['update:value'])
const myValue = ref<any[]>([])
const change = (id: string) => {
const ids = new Set<string>(myValue.value)
console.log(ids)
if (ids.has(id)) {
ids.delete(id)
} else {
ids.add(id)
}
myValue.value = [...ids.values()]
emit('update:value', myValue.value)
}
watch(() => JSON.stringify(props.value), () => {
myValue.value = props.value
}, { immediate: true })
</script>
<style lang="less" scoped>
.server-list-warp {
padding: 0 12px;
margin-top: 12px;
.server-list-items {
display: flex;
gap: 24px;
.server-item {
cursor: pointer;
:deep(.ant-badge-status-text) {
color: #a3a3a3;
transition: color .3s;
}
&.active {
:deep(.ant-badge-status-text) {
color: #000;
}
}
}
}
}
</style>

View File

@ -1,44 +1,48 @@
<template> <template>
<div> <div>
<div class="dash-board">
<j-select <j-select
v-if="serverNodeOptions.length > 1"
:options="serverNodeOptions"
:value="serverId"
style="width: 300px; margin-bottom: 20px" style="width: 300px; margin-bottom: 20px"
@change="serverIdChange" @change="serverIdChange"
:value="serverId"
:options="serverNodeOptions"
v-if="serverNodeOptions.length > 1"
></j-select> ></j-select>
<div class="dash-board"> <div class="dash-board-items">
<div class="dash-board-item"> <div class="dash-board-item">
<TopEchartsItemNode title="CPU使用率" :value="topValues.cpu" /> <TopEchartsItemNode :value="topValues.cpu" title="CPU使用率" />
</div> </div>
<div class="dash-board-item"> <div class="dash-board-item">
<TopEchartsItemNode <TopEchartsItemNode
title="JVM内存"
:max="topValues.jvmTotal"
:bottom="`总JVM内存 ${topValues.jvmTotal}G`" :bottom="`总JVM内存 ${topValues.jvmTotal}G`"
formatter="G" :max="topValues.jvmTotal"
:value="topValues.jvm" :value="topValues.jvm"
formatter="G"
title="JVM内存"
/> />
</div> </div>
<div class="dash-board-item"> <div class="dash-board-item">
<TopEchartsItemNode <TopEchartsItemNode
title="磁盘占用"
:max="topValues.usageTotal"
:bottom="`总磁盘大小 ${topValues.usageTotal}G`" :bottom="`总磁盘大小 ${topValues.usageTotal}G`"
formatter="G" :max="topValues.usageTotal"
:value="topValues.usage" :value="topValues.usage"
formatter="G"
title="磁盘占用"
/> />
</div> </div>
<div class="dash-board-item"> <div class="dash-board-item">
<TopEchartsItemNode <TopEchartsItemNode
title="系统内存"
:max="topValues.systemUsageTotal"
:bottom="`系统内存 ${topValues.systemUsageTotal}G`" :bottom="`系统内存 ${topValues.systemUsageTotal}G`"
formatter="G" :max="topValues.systemUsageTotal"
:value="topValues.systemUsage" :value="topValues.systemUsage"
formatter="G"
title="系统内存"
/> />
</div> </div>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -115,6 +119,7 @@ const getData = () => {
}; };
onMounted(() => { onMounted(() => {
console.log('isNoCommunity')
if (isNoCommunity) { if (isNoCommunity) {
serverNode().then((resp: any) => { serverNode().then((resp: any) => {
if (resp.success) { if (resp.success) {
@ -143,19 +148,21 @@ watch(
emit('serviceChange', val) emit('serviceChange', val)
}, },
); );
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.dash-board { .dash-board {
background-color: #fff;
padding: 24px;
.dash-board-items {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
height: 100%;
background-color: #fff;
// box-shadow: 0px 2.73036px 5.46071px rgba(31, 89, 245, 0.2);
border-radius: 2px; border-radius: 2px;
justify-content: space-between; justify-content: space-between;
padding: 24px;
gap: 24px; gap: 24px;
}
.dash-board-item { .dash-board-item {
flex: 1; flex: 1;
//margin: 24px 12px; //margin: 24px 12px;

View File

@ -0,0 +1,56 @@
<template>
<div ref="echartsDom" class="echarts-warp"></div>
</template>
<script lang="ts" name="Echarts" setup>
import * as echarts from 'echarts';
import {onUnmounted, watch} from "vue";
const props = defineProps({
options: {
type: Object,
default: undefined
}
})
const echartsDom = ref<HTMLElement>()
const myChart = ref()
const echartsRender = () => {
if (!echartsDom.value) return
if (!myChart.value) {
myChart.value = echarts.init(echartsDom.value)
toRaw(myChart.value).setOption(props.options);
} else {
toRaw(myChart.value).setOption(props.options, true);
}
}
const echartsResize = () => {
toRaw(myChart.value)?.resize?.()
}
onMounted(() => {
window.addEventListener('resize', echartsResize)
})
onUnmounted(() => {
window.removeEventListener('resize', echartsResize)
})
watch(() => props.options, () => {
if (props.options) {
nextTick(() => {
echartsRender()
})
}
}, { deep: true })
</script>
<style scoped>
.echarts-warp {
width: 100%;
height: 100%;
}
</style>

View File

@ -1,4 +1,4 @@
import dayjs from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
// export const getInterval = (type: string) => { // export const getInterval = (type: string) => {
@ -36,11 +36,13 @@ export const getTimeByType = (type: string) => {
case 'hour': case 'hour':
return dayjs().subtract(1, 'hours'); return dayjs().subtract(1, 'hours');
case 'week': case 'week':
return dayjs().subtract(6, 'days'); return dayjs().subtract(6, 'days').startOf('day');
case 'month': case 'month':
return dayjs().subtract(29, 'days'); return dayjs().subtract(29, 'days');
case 'year': case 'year':
return dayjs().subtract(365, 'days'); return dayjs().subtract(365, 'days');
case 'day':
return dayjs().subtract(24, 'hours');
default: default:
return dayjs().startOf('day'); return dayjs().startOf('day');
} }
@ -57,26 +59,24 @@ export const arrayReverse = (data: string) => {
export const networkParams = (val: any) => { export const networkParams = (val: any) => {
let _time = '1h'; let _time = '1h';
let _limit = 12; let _limit = 12;
let format = 'HH'; let format = 'M月dd日 HH:mm';
// @ts-ignore
const dt = Number(val.time.time[1]) - Number(val.time.time[0]); const dt = dayjs(val.time.time[1]) - dayjs(val.time.time[0])
const hour = 60 * 60 * 1000; const hour = 60 * 60 * 1000;
const days = hour * 24; const days = hour * 24;
const months = days * 30; const months = days * 30;
const year = 365 * days; const year = 365 * days;
if (dt <= hour) { if (dt <= (hour + 10)) {
format = 'mm:ss';
_time = '1m';
_limit = 30;
} else if (dt > hour && dt <= days) {
_limit = Math.abs(Math.ceil(dt / hour));
_limit = 24;
format = 'HH:mm'; format = 'HH:mm';
_time = '1m';
_limit = 60;
} else if (dt > hour && dt <= days) {
_limit = 24;
} else if (dt > days && dt <= months * 3) { } else if (dt > days && dt <= months * 3) {
_limit = Math.abs(Math.ceil(dt / days)) + 1; _limit = Math.abs(Math.ceil(dt / days)) + 1;
_time = '1d'; _time = '1d';
format = 'M月dd日'; format = 'M月dd日 HH:mm:ss';
} else if (dt > months * 3 && dt < year) { } else if (dt > months * 3 && dt < year) {
_limit = Math.abs(Math.ceil(dt / months)) + 1; _limit = Math.abs(Math.ceil(dt / months)) + 1;
_time = '1M'; _time = '1M';
@ -99,7 +99,7 @@ export const networkParams = (val: any) => {
from: Number(val.time.time[0]), from: Number(val.time.time[0]),
to: Number(val.time.time[1]), to: Number(val.time.time[1]),
limit: _limit, limit: _limit,
format: 'YYYY-MM-dd HH:mm', format: format,
}, },
}, },
]; ];

View File

@ -12,8 +12,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Store } from "jetlinks-store"
import { resourceClustersById } from "@/api/link/type" import { resourceClustersById } from "@/api/link/type"
import { useTypeStore } from "@/store/type"
import { cloneDeep } from "lodash-es"
import { storeToRefs } from "pinia"
const _typeStore = useTypeStore()
const { resourcesClusters } = storeToRefs(_typeStore)
const props = defineProps({ const props = defineProps({
value: { value: {
@ -36,7 +41,7 @@ const host = ref<string>()
const options = ref<any[]>([]) const options = ref<any[]>([])
const getResourcesClustersById = async (id: string) => { const getResourcesClustersById = async (id: string) => {
const _value = Store.get('resourcesClusters')?.[id] const _value = resourcesClusters.value?.[id]
if(!_value){ if(!_value){
const resp = await resourceClustersById(id) const resp = await resourceClustersById(id)
if (resp.status === 200) { if (resp.status === 200) {
@ -44,15 +49,15 @@ const getResourcesClustersById = async (id: string) => {
const checkedHost = [{ value: checked?.host, label: checked?.host }]; const checkedHost = [{ value: checked?.host, label: checked?.host }];
options.value = checked ? checkedHost : [] options.value = checked ? checkedHost : []
const resourcesClusters = Store.get('resourcesClusters') || {} const _resourcesClusters = cloneDeep(resourcesClusters.value)
resourcesClusters[id] = resp.result _resourcesClusters[id] = resp.result
Store.set('resourcesClusters', resourcesClusters) _typeStore.setResourcesClusters(_resourcesClusters)
emit('valueChange', props.value) emit('valueChange', props.value)
} else { } else {
options.value = [] options.value = []
} }
} else { } else {
const checked = Store.get('resourcesClusters')?.[id]?.[0] const checked = resourcesClusters.value?.[id]?.[0]
const checkedHost = [{ value: checked?.host, label: checked?.host }]; const checkedHost = [{ value: checked?.host, label: checked?.host }];
options.value = checked ? checkedHost : [] options.value = checked ? checkedHost : []
} }

View File

@ -1143,9 +1143,10 @@ import {
} from '../data'; } from '../data';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import type { FormData2Type, FormDataType } from '../type'; import type { FormData2Type, FormDataType } from '../type';
import { Store } from 'jetlinks-store';
import LocalAddressSelect from './LocalAddressSelect.vue'; import LocalAddressSelect from './LocalAddressSelect.vue';
import { isNoCommunity } from '@/utils/utils'; import { isNoCommunity } from '@/utils/utils';
import { useTypeStore } from '@/store/type';
import { storeToRefs } from 'pinia';
const route = useRoute(); const route = useRoute();
const NetworkType = route.query.type as string; const NetworkType = route.query.type as string;
@ -1157,6 +1158,9 @@ const formRef1 = ref<FormInstance>();
const formRef2 = ref<FormInstance>(); const formRef2 = ref<FormInstance>();
const shareCluster = ref(true); const shareCluster = ref(true);
const _typeStore = useTypeStore()
const { configRef, resourcesClusters } = storeToRefs(_typeStore)
const formData = ref<FormDataType>({ const formData = ref<FormDataType>({
...FormStates, ...FormStates,
}); });
@ -1198,7 +1202,7 @@ const filterPortOption = (input: string, option: any) => {
const getPortList = (list: any[], id: string) => { const getPortList = (list: any[], id: string) => {
const keys = dynamicValidateForm?.cluster?.map?.(item => item.configuration?.port) || [] const keys = dynamicValidateForm?.cluster?.map?.(item => item.configuration?.port) || []
console.log(dynamicValidateForm?.cluster, id, keys) // console.log(dynamicValidateForm?.cluster, id, keys)
return (list || []).filter(item => item.value === id || !keys.includes(item.value) ) return (list || []).filter(item => item.value === id || !keys.includes(item.value) )
} }
@ -1251,7 +1255,7 @@ const changeType = (value: string) => {
const updateClustersListIndex = () => { const updateClustersListIndex = () => {
const { cluster } = dynamicValidateForm; const { cluster } = dynamicValidateForm;
const filters = cluster?.map((item) => item.serverId); const filters = cluster?.map((item) => item.serverId);
const newConfigRef = shareCluster.value ? Store.get('configRef')?.filter( const newConfigRef = shareCluster.value ? (configRef.value || [])?.filter(
(item: any) => !filters.includes(item.clusterNodeId), (item: any) => !filters.includes(item.clusterNodeId),
) : configClustersList.value?.filter( ) : configClustersList.value?.filter(
(item: any) => !filters.includes(item.id), (item: any) => !filters.includes(item.id),
@ -1299,7 +1303,7 @@ const changeHost = (
if(!flag){ if(!flag){
configuration.port = undefined; configuration.port = undefined;
} }
const checked = Store.get('resourcesClusters')?.[serverId || ''] const checked = resourcesClusters.value?.[serverId || '']
if(checked){ if(checked){
getPortOptions(checked, index) getPortOptions(checked, index)
} }
@ -1387,14 +1391,15 @@ const getCertificates = async () => {
}; };
const getResourcesCurrent = () => { const getResourcesCurrent = () => {
resourcesCurrent().then((resp) => { resourcesCurrent().then((resp: any) => {
if (resp.status === 200) { if (resp.status === 200) {
_typeStore.setConfigRef(resp.result || [])
const clusterNodeId = resp.result?.[0]?.clusterNodeId const clusterNodeId = resp.result?.[0]?.clusterNodeId
const resourcesClusters = Store.get('resourcesClusters') || {} const _resourcesClusters = cloneDeep(resourcesClusters.value || {})
resourcesClusters[clusterNodeId] = resp.result _resourcesClusters[clusterNodeId] = resp.result
Store.set('resourcesClusters', resourcesClusters) _typeStore.setResourcesClusters(_resourcesClusters)
Store.set('configRef', resp.result); getPortOptions(resp.result);
getPortOptions(Store.get('resourcesClusters')?.[clusterNodeId]);
} }
}); });
}; };
@ -1422,11 +1427,6 @@ const getDetail = () => {
...cloneDeep(Configuration), /// ...cloneDeep(Configuration), ///
...configuration, ...configuration,
}; };
// const configRef = Store.get('configRef').filter(
// (item: any) => item.host === '0.0.0.0',
// );
// getPortOptions(configRef); //
} else { } else {
dynamicValidateForm.cluster = cluster; dynamicValidateForm.cluster = cluster;
// const arr = cluster.map((item: any) => item.configuration.serverId) // const arr = cluster.map((item: any) => item.configuration.serverId)
@ -1479,7 +1479,7 @@ watch(
(value) => { (value) => {
formData.value.shareCluster = value; formData.value.shareCluster = value;
value value
? getPortOptions(Store.get('configRef')) ? getPortOptions(configRef.value)
: (portOptionsIndex.value[0] = []); : (portOptionsIndex.value[0] = []);
updateClustersListIndex(); updateClustersListIndex();
}, },

View File

@ -89,7 +89,7 @@
告警级别 告警级别
</div> </div>
<div> <div>
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title || {{ (defaultLevel || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level }} slotProps.level }}
</div> </div>
</j-col> </j-col>
@ -124,11 +124,11 @@
<template #level="slotProps"> <template #level="slotProps">
<j-tooltip <j-tooltip
placement="topLeft" placement="topLeft"
:title="(Store.get('default-level') || []).find((item) => item?.level === slotProps.level)?.title || :title="(defaultLevel || []).find((item) => item?.level === slotProps.level)?.title ||
slotProps.level" slotProps.level"
> >
<div class="ellipsis"> <div class="ellipsis">
{{ (Store.get('default-level') || []).find((item) => item?.level === slotProps.level)?.title || {{ (defaultLevel || []).find((item) => item?.level === slotProps.level)?.title ||
slotProps.level }} slotProps.level }}
</div> </div>
</j-tooltip> </j-tooltip>
@ -196,7 +196,6 @@ import {
getScene, getScene,
} from '@/api/rule-engine/configuration'; } from '@/api/rule-engine/configuration';
import { queryLevel } from '@/api/rule-engine/config'; import { queryLevel } from '@/api/rule-engine/config';
import { Store } from 'jetlinks-store';
import type { ActionsType } from '@/components/Table/index.vue'; import type { ActionsType } from '@/components/Table/index.vue';
import { getImage, onlyMessage } from '@/utils/comm'; import { getImage, onlyMessage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
@ -352,6 +351,8 @@ const columns = [
const visible = ref<boolean>(false); const visible = ref<boolean>(false);
const current = ref<any>({}); const current = ref<any>({});
const defaultLevel = ref<any[]>([]);
const map = { const map = {
product: '产品', product: '产品',
device: '设备', device: '设备',
@ -380,7 +381,7 @@ const handleSearch = (e: any) => {
const queryDefaultLevel = () => { const queryDefaultLevel = () => {
queryLevel().then((res) => { queryLevel().then((res) => {
if (res.status === 200) { if (res.status === 200) {
Store.set('default-level', res.result?.levels || []); defaultLevel.value = res.result?.levels || [];
} }
}); });
}; };

View File

@ -30,13 +30,11 @@
<j-descriptions-item label="告警级别" :span="1"> <j-descriptions-item label="告警级别" :span="1">
<j-tooltip <j-tooltip
placement="topLeft" placement="topLeft"
:title="(Store.get('default-level') || []).find((item: any) => item?.level === data?.level) :title="_level"
?.title || props.data?.level"
> >
<Ellipsis> <Ellipsis>
<span> <span>
{{(Store.get('default-level') || []).find((item: any) => item?.level === data?.level) {{_level}}
?.title || props.data?.level}}
</span> </span>
</Ellipsis> </Ellipsis>
</j-tooltip> </j-tooltip>
@ -60,8 +58,8 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { queryLevel } from '@/api/rule-engine/config';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { Store } from 'jetlinks-store';
import JsonViewer from 'vue-json-viewer'; import JsonViewer from 'vue-json-viewer';
const props = defineProps({ const props = defineProps({
data: Object, data: Object,
@ -70,11 +68,24 @@ const props = defineProps({
const data = computed(()=>{ const data = computed(()=>{
return JSON.parse(props.data?.alarmInfo); return JSON.parse(props.data?.alarmInfo);
}) })
const defaultLevel = ref<any[]>([])
const emit = defineEmits(['close']); const emit = defineEmits(['close']);
const closeModal = () => { const closeModal = () => {
emit('close'); emit('close');
}; };
const _level = computed(() => {
return (defaultLevel.value || []).find((item: any) => item?.level === props.data?.level)?.title || props.data?.level
})
onMounted(() => {
queryLevel().then((res)=>{
if(res.status === 200 ){
defaultLevel.value = res.result?.levels || [];
}
})
})
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
</style> </style>

View File

@ -138,7 +138,6 @@ import { queryLevel } from '@/api/rule-engine/config';
import Search from '@/components/Search'; import Search from '@/components/Search';
import { useAlarmStore } from '@/store/alarm'; import { useAlarmStore } from '@/store/alarm';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { Store } from 'jetlinks-store';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import type { ActionsType } from '@/components/Table'; import type { ActionsType } from '@/components/Table';
import SolveComponent from '../SolveComponent/index.vue'; import SolveComponent from '../SolveComponent/index.vue';
@ -149,10 +148,10 @@ const menuStory = useMenuStore();
const tableRef = ref(); const tableRef = ref();
const alarmStore = useAlarmStore(); const alarmStore = useAlarmStore();
const { data } = storeToRefs(alarmStore); const { data } = storeToRefs(alarmStore);
const getDefaulitLevel = () => { const getDefaulitLevel = () => {
queryLevel().then((res) => { queryLevel().then((res) => {
if (res.status === 200) { if (res.status === 200) {
Store.set('default-level', res.result?.levels || []);
data.value.defaultLevel = res.result?.levels || []; data.value.defaultLevel = res.result?.levels || [];
} }
}); });

View File

@ -9,7 +9,6 @@ import { isNoCommunity } from '@/utils/utils';
import { useAlarmStore } from '@/store/alarm'; import { useAlarmStore } from '@/store/alarm';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { queryLevel } from '@/api/rule-engine/config'; import { queryLevel } from '@/api/rule-engine/config';
import { Store } from 'jetlinks-store';
import TableComponents from './TabComponent/index.vue'; import TableComponents from './TabComponent/index.vue';
const list = [ const list = [
{ {
@ -56,7 +55,6 @@ const { data } = storeToRefs(alarmStore);
const getDefaulitLevel = () => { const getDefaulitLevel = () => {
queryLevel().then((res)=>{ queryLevel().then((res)=>{
if(res.status === 200 ){ if(res.status === 200 ){
Store.set('default-level', res.result?.levels || []);
data.value.defaultLevel = res.result?.levels || []; data.value.defaultLevel = res.result?.levels || [];
} }
}) })

View File

@ -86,6 +86,8 @@ const getTimeByType = (type: string) => {
return dayjs().subtract(29, 'days').valueOf(); return dayjs().subtract(29, 'days').valueOf();
case 'year': case 'year':
return dayjs().subtract(365, 'days').valueOf(); return dayjs().subtract(365, 'days').valueOf();
case 'day':
return dayjs().subtract(24, 'hours').valueOf();
default: default:
return dayjs().startOf('day').valueOf(); return dayjs().startOf('day').valueOf();
} }

View File

@ -42,6 +42,11 @@
<TimeSelect <TimeSelect
key="flow-static" key="flow-static"
:type="'week'" :type="'week'"
:quickBtnList="[
{ label: '最近1小时', value: 'hour' },
{ label: '最近24小时', value: 'day' },
{ label: '近一周', value: 'week' },
]"
@change="initQueryTime" @change="initQueryTime"
/> />
</template> </template>
@ -238,6 +243,7 @@ const getDashBoard = () => {
.filter((item) => item.group === '15day') .filter((item) => item.group === '15day')
.map((item) => item.data) .map((item) => item.data)
.sort((a, b) => b.timestamp - a.timestamp); .sort((a, b) => b.timestamp - a.timestamp);
state.fifteenOptions = { state.fifteenOptions = {
xAxis: { xAxis: {
type: 'category', type: 'category',
@ -355,20 +361,25 @@ const initQueryTime = (data: any) => {
selectChange(); selectChange();
}; };
const selectChange = () => { const selectChange = () => {
let time = '1h'; let time = '1m';
let format = 'HH'; let format = 'M月dd日 HH:mm';
let limit = 12; let limit = 12;
const dt = queryCodition.endTime - queryCodition.startTime; const dt = queryCodition.endTime - queryCodition.startTime;
const hour = 60 * 60 * 1000; const hour = 60 * 60 * 1000;
const day = hour * 24; const day = hour * 24;
const month = day * 30; const month = day * 30;
const year = 365 * day; const year = 365 * day;
if (dt <= day) {
limit = Math.abs(Math.ceil(dt / hour)); if (dt <= (hour + 10)) {
limit = 60
format = 'HH:mm';
} else if (dt > hour && dt <= day) {
time = '1h'
limit = 24;
} else if (dt > day && dt < year) { } else if (dt > day && dt < year) {
limit = Math.abs(Math.ceil(dt / day)) + 1; limit = Math.abs(Math.ceil(dt / day)) + 1;
time = '1d'; time = '1d';
format = 'M月dd日'; format = 'M月dd日 HH:mm:ss';
} else if (dt >= year) { } else if (dt >= year) {
limit = Math.abs(Math.floor(dt / month)); limit = Math.abs(Math.floor(dt / month));
time = '1M'; time = '1M';
@ -429,7 +440,7 @@ const selectChange = () => {
.filter((item: any) => item.group === 'alarmTrend') .filter((item: any) => item.group === 'alarmTrend')
.forEach((item: any) => { .forEach((item: any) => {
xData.push(item.data.timeString); xData.push(item.data.timeString);
sData.push(item.data.value * 100000); sData.push(item.data.value);
}); });
const maxY = sData.sort((a,b)=>{ const maxY = sData.sort((a,b)=>{
return b-a return b-a
@ -452,7 +463,7 @@ const selectChange = () => {
grid: { grid: {
top: '2%', top: '2%',
bottom: '5%', bottom: '5%',
left: maxY < 1000 ? '40px' : maxY.toString().length * 10, left: maxY < 1000 ? 50 : maxY.toString().length * 10,
right: '48px', right: '48px',
}, },
series: [ series: [

View File

@ -56,6 +56,7 @@ import { useMenuStore } from '@/store/menu';
import { import {
getRoleDetails_api, getRoleDetails_api,
updateRole_api, updateRole_api,
editRole_api,
updatePrimissTree_api, updatePrimissTree_api,
} from '@/api/system/role'; } from '@/api/system/role';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
@ -83,7 +84,7 @@ const form = reactive({
}, },
clickSave: () => { clickSave: () => {
formRef.value?.validate().then(() => { formRef.value?.validate().then(() => {
const updateRole = updateRole_api(form.data); const updateRole = editRole_api(roleId, form.data);
const updateTree = updatePrimissTree_api(roleId, { const updateTree = updatePrimissTree_api(roleId, {
menus: form.menus, menus: form.menus,
}); });

View File

@ -112,6 +112,7 @@ import {
} from '@/utils/consts' } from '@/utils/consts'
import { isNoCommunity } from '@/utils/utils' import { isNoCommunity } from '@/utils/utils'
import {permissionsGranted, useIndirectMenusMap} from "@/views/system/Role/Detail/components/util"; import {permissionsGranted, useIndirectMenusMap} from "@/views/system/Role/Detail/components/util";
import {NotificationSubscriptionCode} from "@/router/menu";
const emits = defineEmits(['update:selectItems']); const emits = defineEmits(['update:selectItems']);
const route = useRoute(); const route = useRoute();
@ -279,12 +280,8 @@ function getAllPermiss() {
getPrimissTree_api(id).then((resp) => { getPrimissTree_api(id).then((resp) => {
const _result = resp.result const _result = resp.result
// //
tableData.value = _result.map((item: { code: string , buttons: any[], granted: boolean}) => { tableData.value = _result.filter((item: { code: string , buttons: any[], granted: boolean}) => {
// if (item.code === USER_CENTER_MENU_CODE) { return (item.code !== NotificationSubscriptionCode)
// item.granted = true
// item.buttons = item.buttons.map( b => ({...b, granted: true, enabled: true}))
// }
return item
}); });
treeToSimple(tableData.value); // treeToSimple(tableData.value); //

View File

@ -3837,8 +3837,8 @@ jetlinks-ui-components@^1.0.23:
jetlinks-ui-components@^1.0.25: jetlinks-ui-components@^1.0.25:
version "1.0.25" version "1.0.25"
resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.25.tgz#b783da3fe05c1420b2ee5707868a67baa90559f7" resolved "http://registry.jetlinks.cn/jetlinks-ui-components/-/jetlinks-ui-components-1.0.25.tgz#fa730dc39f4072f35c34c00d41d343b0da4a99a5"
integrity sha512-4HJM9Wi8gFfBgYFPjCO7JpmEAXVtDUf5u5lnXTQUt1QkGh0QCzFSBGBIStFs6HE5oY3oIIS3ZWoAjvXElpnNZg== integrity sha512-/iz4p86BxmEAPxgTNkr7RqnMdRHQ6vEUKzIlyddtQIvQjuZXTxImh+Ik+V6yxtQVElI8Fjk3l7fiYZZ0E68MSw==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
"@vueuse/router" "^9.13.0" "@vueuse/router" "^9.13.0"