feat:自定义布局保存,WS数据追加
This commit is contained in:
@@ -42,7 +42,6 @@
|
|||||||
"vue-i18n": "^9.13.1",
|
"vue-i18n": "^9.13.1",
|
||||||
"vue-router": "^4.4.0",
|
"vue-router": "^4.4.0",
|
||||||
"vue3-smooth-dnd": "^0.0.6",
|
"vue3-smooth-dnd": "^0.0.6",
|
||||||
"vuedraggable": "^4.1.0",
|
|
||||||
"xlsx": "~0.18.5"
|
"xlsx": "~0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ import useI18n from '@/hooks/useI18n';
|
|||||||
import { parseDateToStr } from '@/utils/date-utils';
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import dayjs, { Dayjs } from 'dayjs';
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import { message, Switch, Form } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
import { ColumnsType } from 'ant-design-vue/es/table';
|
import { ColumnsType } from 'ant-design-vue/es/table';
|
||||||
import { generateColorRGBA } from '@/utils/generate-utils';
|
import { generateColorRGBA } from '@/utils/generate-utils';
|
||||||
import { LineSeriesOption } from 'echarts/charts';
|
import { LineSeriesOption } from 'echarts/charts';
|
||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
|
import { Select } from 'ant-design-vue';
|
||||||
const { t, currentLocale } = useI18n();
|
const { t, currentLocale } = useI18n();
|
||||||
|
|
||||||
const neInfoStore = useNeInfoStore();
|
const neInfoStore = useNeInfoStore();
|
||||||
@@ -31,10 +32,92 @@ const handleRealTimeSwitch = (checked: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 网元数组
|
// 定义所有可能的网元类型
|
||||||
const networkElementTypes = ['udm', 'upf', 'amf', 'smf', 'ims','ausf'] as const;
|
const ALL_NE_TYPES = ['ims', 'amf', 'udm', 'smf', 'pcf','upf','mme','mocngw','smsc','cbc','ausf'] as const;
|
||||||
// 定义 ChartType
|
type AllChartType = typeof ALL_NE_TYPES[number];
|
||||||
type ChartType = typeof networkElementTypes[number]; // 将 i 的类型改为 ChartType
|
|
||||||
|
// 使用 ref 来使 networkElementTypes 变为响应式,并使用 ALL_NE_TYPES 初始化
|
||||||
|
const networkElementTypes = ref<AllChartType[]>([...ALL_NE_TYPES]);
|
||||||
|
|
||||||
|
// 添加选择的网元类型,也使用 ALL_NE_TYPES 初始化
|
||||||
|
const selectedNeTypes = ref<AllChartType[]>([...ALL_NE_TYPES]);
|
||||||
|
|
||||||
|
// 监听 selectedNeTypes 的变化
|
||||||
|
watch(selectedNeTypes, (newTypes) => {
|
||||||
|
//console.log('Selected types changed:', newTypes);
|
||||||
|
if (JSON.stringify(newTypes) !== JSON.stringify(networkElementTypes.value)) {
|
||||||
|
networkElementTypes.value = newTypes;
|
||||||
|
|
||||||
|
// 更新 chartOrder
|
||||||
|
chartOrder.value = chartOrder.value.filter(item => newTypes.includes(item.i));
|
||||||
|
|
||||||
|
newTypes.forEach((type) => {
|
||||||
|
if (!chartOrder.value.some(item => item.i === type)) {
|
||||||
|
chartOrder.value.push({
|
||||||
|
x: (chartOrder.value.length % 2) * 6,
|
||||||
|
y: Math.floor(chartOrder.value.length / 2) * 4,
|
||||||
|
w: 6,
|
||||||
|
h: 4,
|
||||||
|
i: type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 确保 chartStates 包含新的网元类型
|
||||||
|
if (!chartStates[type]) {
|
||||||
|
chartStates[type] = createChartState();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log('Updated chartOrder:', chartOrder.value);
|
||||||
|
|
||||||
|
// 保存选中的网元类型到本地存储
|
||||||
|
localStorage.setItem('selectedNeTypes', JSON.stringify(newTypes));
|
||||||
|
|
||||||
|
// 重新初始化图表
|
||||||
|
nextTick(() => {
|
||||||
|
initCharts();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
// 初始化所有图表的函数
|
||||||
|
const initCharts = async () => {
|
||||||
|
//console.log('Initializing charts for:', networkElementTypes.value);
|
||||||
|
|
||||||
|
// 清除不再需要的图表
|
||||||
|
Object.keys(chartStates).forEach((key) => {
|
||||||
|
if (!networkElementTypes.value.includes(key as AllChartType)) {
|
||||||
|
const state = chartStates[key as AllChartType];
|
||||||
|
if (state.chart.value) {
|
||||||
|
state.chart.value.dispose();
|
||||||
|
}
|
||||||
|
if (state.observer.value) {
|
||||||
|
state.observer.value.disconnect();
|
||||||
|
}
|
||||||
|
delete chartStates[key as AllChartType];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化或更新需要的图表
|
||||||
|
for (const type of networkElementTypes.value) {
|
||||||
|
//console.log('Initializing chart for:', type);
|
||||||
|
if (!chartStates[type]) {
|
||||||
|
chartStates[type] = createChartState();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await fetchKPITitle(type);
|
||||||
|
await nextTick();
|
||||||
|
initChart(type);
|
||||||
|
await fetchData(type);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error initializing chart for ${type}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('Finished initializing charts');
|
||||||
|
|
||||||
|
// 保存更新后的布局
|
||||||
|
localStorage.setItem('chartOrder', JSON.stringify(chartOrder.value));
|
||||||
|
};
|
||||||
|
|
||||||
// 添加类型定义
|
// 添加类型定义
|
||||||
interface LayoutItem {
|
interface LayoutItem {
|
||||||
@@ -42,17 +125,18 @@ interface LayoutItem {
|
|||||||
y: number;
|
y: number;
|
||||||
w: number;
|
w: number;
|
||||||
h: number;
|
h: number;
|
||||||
i: ChartType; // 将 i 的类型改为 ChartType
|
i: AllChartType; // 将 ChartType 改为 AllChartType
|
||||||
}
|
}
|
||||||
|
|
||||||
type Layout = LayoutItem[];
|
type Layout = LayoutItem[];
|
||||||
|
|
||||||
//构建响应式数组储存图表类型数据
|
//构建响应式数组储存图表类型数据
|
||||||
const chartOrder = ref<Layout>(
|
const chartOrder = ref<Layout>(
|
||||||
networkElementTypes.map((type, index) => ({
|
JSON.parse(localStorage.getItem('chartOrder') || 'null') ||
|
||||||
|
networkElementTypes.value.map((type, index) => ({
|
||||||
x: index % 2 * 6, // 每行两个图表,宽度为6
|
x: index % 2 * 6, // 每行两个图表,宽度为6
|
||||||
y: Math.floor(index / 2) * 4, // 每个图表占据 4 个单位高度
|
y: Math.floor(index / 2) * 4, // 每个图表占据 4 个单位高度
|
||||||
w: 6, // 宽度为6个单位
|
w: 6, // 宽度为6单位
|
||||||
h: 4, // 高度为4个单位
|
h: 4, // 高度为4个单位
|
||||||
i: type, // 使用网元类型作为唯一标识符
|
i: type, // 使用网元类型作为唯一标识符
|
||||||
}))
|
}))
|
||||||
@@ -60,15 +144,20 @@ const chartOrder = ref<Layout>(
|
|||||||
|
|
||||||
// 改变布局触发更新
|
// 改变布局触发更新
|
||||||
const handleLayoutUpdated = (newLayout: Layout) => {
|
const handleLayoutUpdated = (newLayout: Layout) => {
|
||||||
chartOrder.value = newLayout;
|
const filteredLayout = newLayout.filter(item => networkElementTypes.value.includes(item.i));
|
||||||
|
if (JSON.stringify(filteredLayout) !== JSON.stringify(chartOrder.value)) {
|
||||||
|
chartOrder.value = filteredLayout;
|
||||||
|
// 保存布局到 localStorage
|
||||||
|
localStorage.setItem('chartOrder', JSON.stringify(chartOrder.value));
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
newLayout.forEach((item) => {
|
chartOrder.value.forEach((item) => {
|
||||||
const state = chartStates[item.i];
|
const state = chartStates[item.i];
|
||||||
if (state.chart.value) {
|
if (state?.chart.value) {
|
||||||
state.chart.value.resize();
|
state.chart.value.resize();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听 chartOrder 的变化
|
// 监听 chartOrder 的变化
|
||||||
@@ -116,26 +205,30 @@ const createChartState = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// 为每种图表类型创建状态
|
// 为每种图表类型创建状
|
||||||
const chartStates: Record<ChartType, ReturnType<typeof createChartState>> = Object.fromEntries(
|
const chartStates: Record<AllChartType, ReturnType<typeof createChartState>> = Object.fromEntries(
|
||||||
networkElementTypes.map(type => [type, createChartState()])
|
networkElementTypes.value.map(type => [type, createChartState()])
|
||||||
) as Record<ChartType, ReturnType<typeof createChartState>>;
|
) as Record<AllChartType, ReturnType<typeof createChartState>>;
|
||||||
|
|
||||||
//日期选择器
|
//日期选择器
|
||||||
interface RangePicker extends Record<ChartType, [string, string]> {
|
interface RangePicker extends Record<AllChartType, [string, string]> {
|
||||||
placeholder: [string, string];
|
placeholder: [string, string];
|
||||||
ranges: Record<string, [Dayjs, Dayjs]>;
|
ranges: Record<string, [Dayjs, Dayjs]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建日期选择器状态
|
// 创建日期选择器状态
|
||||||
const rangePicker = reactive<RangePicker>({
|
const rangePicker = reactive<RangePicker>({
|
||||||
...Object.fromEntries(networkElementTypes.map(type => [
|
...Object.fromEntries(networkElementTypes.value.map(type => [
|
||||||
type,
|
type,
|
||||||
|
// [
|
||||||
|
// dayjs('2024-09-20 00:00:00').valueOf().toString(),//拟数据的日期设2024.9.20
|
||||||
|
// dayjs('2024-09-20 23:59:59').valueOf().toString()
|
||||||
|
// ]
|
||||||
[
|
[
|
||||||
dayjs('2024-09-20 00:00:00').valueOf().toString(),//模拟数据的日期设为默认日期
|
dayjs().startOf('day').valueOf().toString(), // 当天 0 点 0 分 0 秒
|
||||||
dayjs('2024-09-20 23:59:59').valueOf().toString()
|
dayjs().valueOf().toString() // 当前时间
|
||||||
]
|
]
|
||||||
])) as Record<ChartType, [string, string]>,
|
])) as Record<AllChartType, [string, string]>,
|
||||||
placeholder: [t('views.monitor.monitor.startTime'), t('views.monitor.monitor.endTime')] as [string, string],
|
placeholder: [t('views.monitor.monitor.startTime'), t('views.monitor.monitor.endTime')] as [string, string],
|
||||||
ranges: {
|
ranges: {
|
||||||
[t('views.monitor.monitor.yesterday')]: [dayjs().subtract(1, 'day').startOf('day'), dayjs().subtract(1, 'day').endOf('day')],
|
[t('views.monitor.monitor.yesterday')]: [dayjs().subtract(1, 'day').startOf('day'), dayjs().subtract(1, 'day').endOf('day')],
|
||||||
@@ -146,13 +239,30 @@ const rangePicker = reactive<RangePicker>({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 创建可复用的图表初始化函数
|
// 创建可复用的图表初始化函数
|
||||||
const initChart = (type: ChartType) => {
|
const initChart = (type: AllChartType) => {
|
||||||
|
const tryInit = (retries = 3) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const state = chartStates[type];
|
const state = chartStates[type];
|
||||||
|
if (!state) {
|
||||||
|
console.warn(`Chart state for ${type} not found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const container = state.chartDom.value;
|
const container = state.chartDom.value;
|
||||||
if (!container) return;
|
if (!container) {
|
||||||
|
if (retries > 0) {
|
||||||
|
console.warn(`Chart container for ${type} not found, retrying... (${retries} attempts left)`);
|
||||||
|
setTimeout(() => tryInit(retries - 1), 100);
|
||||||
|
} else {
|
||||||
|
console.error(`Chart container for ${type} not found after multiple attempts`);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
state.chart.value = markRaw(echarts.init(container, 'light'));
|
if (state.chart.value) {
|
||||||
|
state.chart.value.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
state.chart.value = markRaw(echarts.init(container));
|
||||||
const option: echarts.EChartsOption = {
|
const option: echarts.EChartsOption = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
@@ -202,6 +312,9 @@ const initChart = (type: ChartType) => {
|
|||||||
state.chart.value.resize(); // 确保图表正确调整大小
|
state.chart.value.resize(); // 确保图表正确调整大小
|
||||||
|
|
||||||
// 创建 ResizeObserver 实例
|
// 创建 ResizeObserver 实例
|
||||||
|
if (state.observer.value) {
|
||||||
|
state.observer.value.disconnect();
|
||||||
|
}
|
||||||
state.observer.value = new ResizeObserver(() => {
|
state.observer.value = new ResizeObserver(() => {
|
||||||
if (state.chart.value) {
|
if (state.chart.value) {
|
||||||
state.chart.value.resize();
|
state.chart.value.resize();
|
||||||
@@ -211,28 +324,15 @@ const initChart = (type: ChartType) => {
|
|||||||
// 开始观察图表容器
|
// 开始观察图表容器
|
||||||
state.observer.value.observe(container);
|
state.observer.value.observe(container);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//结束拖拽事件
|
tryInit();
|
||||||
const onDragEnd = () => {
|
|
||||||
nextTick(() => {
|
|
||||||
chartOrder.value.forEach((type:any) => {
|
|
||||||
const state = chartStates[type as ChartType];
|
|
||||||
if (state.chart.value) {
|
|
||||||
state.chart.value.resize(); // 调整图表大小
|
|
||||||
// 重新设置图表选项,保留原有数
|
|
||||||
state.chart.value.setOption({
|
|
||||||
xAxis: { data: state.chartDataXAxisData },
|
|
||||||
series: state.chartDataYSeriesData,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 可复用的数据获取函数
|
|
||||||
const fetchData = async (type: ChartType) => {
|
// 可复用的数据获函数
|
||||||
|
const fetchData = async (type: AllChartType) => {
|
||||||
const state = chartStates[type]; // 直接使用 type
|
const state = chartStates[type]; // 直接使用 type
|
||||||
const neId = '001';
|
const neId = '001';
|
||||||
state.tableState.loading = true;
|
state.tableState.loading = true;
|
||||||
@@ -250,11 +350,12 @@ const fetchData = async (type: ChartType) => {
|
|||||||
});
|
});
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
state.tableState.data = res.data;
|
state.tableState.data = res.data;
|
||||||
nextTick(() => {
|
await nextTick(() => {
|
||||||
renderChart(type);
|
renderChart(type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log("123")
|
||||||
console.error(error);
|
console.error(error);
|
||||||
message.error(t('common.getInfoFail'));
|
message.error(t('common.getInfoFail'));
|
||||||
} finally {
|
} finally {
|
||||||
@@ -278,7 +379,7 @@ function fnRealTimeSwitch(bool: boolean) {
|
|||||||
const options: OptionsType = {
|
const options: OptionsType = {
|
||||||
url: '/ws',
|
url: '/ws',
|
||||||
params: {
|
params: {
|
||||||
subGroupID: networkElementTypes.map(type => `10_${type.toUpperCase()}_001`).join(','),
|
subGroupID: networkElementTypes.value.map(type => `10_${type.toUpperCase()}_001`).join(','),
|
||||||
},
|
},
|
||||||
onmessage: wsMessage,
|
onmessage: wsMessage,
|
||||||
onerror: wsError,
|
onerror: wsError,
|
||||||
@@ -295,58 +396,61 @@ function fnRealTimeSwitch(bool: boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 接收数据后错误回调
|
// 接收数据后错误回
|
||||||
function wsError() {
|
function wsError() {
|
||||||
|
|
||||||
message.error(t('common.websocketError'));
|
message.error(t('common.websocketError'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 接收数据后回调
|
// 修改 wsMessage 数
|
||||||
function wsMessage(res: Record<string, any>) {
|
function wsMessage(res: Record<string, any>) {
|
||||||
//const res = JSON.parse(event.data);
|
|
||||||
const { code, data } = res;
|
const { code, data } = res;
|
||||||
if (code === RESULT_CODE_ERROR) {
|
if (code === RESULT_CODE_ERROR) {
|
||||||
console.warn(res.msg);
|
console.warn(res.msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 订阅组信息
|
|
||||||
if (!data?.groupId) {
|
if (!data?.groupId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理四个图表的数据
|
networkElementTypes.value.forEach((type) => {
|
||||||
networkElementTypes.forEach((type) => {
|
|
||||||
const state = chartStates[type];
|
const state = chartStates[type];
|
||||||
const kpiEvent:any = data.data[type.toUpperCase()];
|
const kpiEvent:any = data.data[type.toUpperCase()];
|
||||||
|
|
||||||
if (kpiEvent) {
|
if (kpiEvent) {
|
||||||
// 更新 X 轴数据
|
|
||||||
if (kpiEvent.timeGroup) {
|
if (kpiEvent.timeGroup) {
|
||||||
state.chartDataXAxisData.push(parseDateToStr(+kpiEvent.timeGroup));
|
const newTime = parseDateToStr(+kpiEvent.timeGroup);
|
||||||
|
state.chartDataXAxisData.push(newTime);
|
||||||
if (state.chartDataXAxisData.length > 100) {
|
if (state.chartDataXAxisData.length > 100) {
|
||||||
state.chartDataXAxisData.shift();
|
state.chartDataXAxisData.shift();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 更新 Y 轴数据
|
// 使用 appendData 方法追加数据
|
||||||
state.chartDataYSeriesData.forEach(series => {
|
state.chartDataYSeriesData.forEach(series => {
|
||||||
if (kpiEvent[series.customKey as string] !== undefined) {
|
if (kpiEvent[series.customKey as string] !== undefined) {
|
||||||
series.data.push(+kpiEvent[series.customKey as string]);
|
const newValue = +kpiEvent[series.customKey as string];
|
||||||
|
if (state.chart.value) {
|
||||||
|
state.chart.value.appendData({
|
||||||
|
seriesIndex: state.chartDataYSeriesData.indexOf(series),
|
||||||
|
data: [[newTime, newValue]]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 保持数据长度不超过100
|
||||||
if (series.data.length > 100) {
|
if (series.data.length > 100) {
|
||||||
series.data.shift();
|
series.data.shift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 更新图表
|
// 更新 X 轴
|
||||||
if (state.chart.value) {
|
if (state.chart.value) {
|
||||||
state.chart.value.setOption({
|
state.chart.value.setOption({
|
||||||
xAxis: { data: state.chartDataXAxisData },
|
xAxis: { data: state.chartDataXAxisData }
|
||||||
series: state.chartDataYSeriesData,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +463,7 @@ interface CustomSeriesOption extends Omit<LineSeriesOption, 'data'> {
|
|||||||
data: (number | LineDataItem)[];
|
data: (number | LineDataItem)[];
|
||||||
}
|
}
|
||||||
// 创建可复用的图表渲染函数
|
// 创建可复用的图表渲染函数
|
||||||
const renderChart = (type: ChartType) => {
|
const renderChart = (type: AllChartType) => {
|
||||||
const state = chartStates[type];
|
const state = chartStates[type];
|
||||||
if (state.chart.value == null) {
|
if (state.chart.value == null) {
|
||||||
return;
|
return;
|
||||||
@@ -426,11 +530,12 @@ const renderChart = (type: ChartType) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 获取表头数据
|
// 获取头数据
|
||||||
const fetchKPITitle = async (type: ChartType) => {
|
const fetchKPITitle = async (type: AllChartType) => {
|
||||||
const language = currentLocale.value.split('_')[0] === 'zh' ? 'cn' : currentLocale.value.split('_')[0];
|
const language = currentLocale.value.split('_')[0] === 'zh' ? 'cn' : currentLocale.value.split('_')[0];
|
||||||
try {
|
try {
|
||||||
const res = await getKPITitle(type.toUpperCase());
|
const res = await getKPITitle(type.toUpperCase());
|
||||||
|
console.log(res);
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||||
chartStates[type].tableColumns.value = res.data.map(item => ({
|
chartStates[type].tableColumns.value = res.data.map(item => ({
|
||||||
title: item[`${language}Title`],
|
title: item[`${language}Title`],
|
||||||
@@ -444,21 +549,57 @@ const fetchKPITitle = async (type: ChartType) => {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log("321")
|
||||||
console.error(error);
|
console.error(error);
|
||||||
message.warning(t('common.getInfoFail'));
|
message.warning(t('common.getInfoFail'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化所有图表
|
// 定义默认选择的网元类型
|
||||||
|
const DEFAULT_NE_TYPES: AllChartType[] = ['udm', 'amf', 'upf', 'ims'];
|
||||||
|
|
||||||
|
// 在 onMounted 钩子中
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
ws.value = new WS();
|
ws.value = new WS();
|
||||||
await neInfoStore.fnNelist();
|
await neInfoStore.fnNelist();
|
||||||
for (const type of networkElementTypes) {
|
|
||||||
await fetchKPITitle(type);
|
// 从本地存储中读取选中的网元类型
|
||||||
initChart(type);
|
const savedSelectedNeTypes = localStorage.getItem('selectedNeTypes');
|
||||||
fetchData(type); // 确保这行存在
|
if (savedSelectedNeTypes) {
|
||||||
|
const parsedSelectedNeTypes = JSON.parse(savedSelectedNeTypes) as AllChartType[];
|
||||||
|
selectedNeTypes.value = parsedSelectedNeTypes;
|
||||||
|
networkElementTypes.value = parsedSelectedNeTypes;
|
||||||
|
} else {
|
||||||
|
// 如果没有保存的选中网元类型,则使用默认选择
|
||||||
|
selectedNeTypes.value = [...DEFAULT_NE_TYPES];
|
||||||
|
networkElementTypes.value = [...DEFAULT_NE_TYPES];
|
||||||
|
// 保存这个默认选择到本地存储
|
||||||
|
localStorage.setItem('selectedNeTypes', JSON.stringify(DEFAULT_NE_TYPES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化或更新 chartOrder
|
||||||
|
const savedLayout = localStorage.getItem('chartOrder');
|
||||||
|
if (savedLayout) {
|
||||||
|
const parsedLayout = JSON.parse(savedLayout);
|
||||||
|
// 只保留当前选中的网元类型的布局
|
||||||
|
chartOrder.value = parsedLayout.filter((item: LayoutItem) => networkElementTypes.value.includes(item.i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 chartOrder 为空或者不包含所有选中的网元,重新创建布局
|
||||||
|
if (chartOrder.value.length === 0 || chartOrder.value.length !== networkElementTypes.value.length) {
|
||||||
|
chartOrder.value = networkElementTypes.value.map((type, index) => ({
|
||||||
|
x: index % 2 * 6,
|
||||||
|
y: Math.floor(index / 2) * 4,
|
||||||
|
w: 6,
|
||||||
|
h: 4,
|
||||||
|
i: type,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('Initialized networkElementTypes:', networkElementTypes.value);
|
||||||
|
//console.log('Initialized chartOrder:', chartOrder.value);
|
||||||
|
|
||||||
|
await initCharts();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 在组件卸载时销毁图表实例
|
// 在组件卸载时销毁图表实例
|
||||||
@@ -479,7 +620,7 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<div class="control-row">
|
<a-card :bordered="false" class="control-card">
|
||||||
<a-form layout="inline">
|
<a-form layout="inline">
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-switch
|
<a-switch
|
||||||
@@ -490,9 +631,21 @@ onUnmounted(() => {
|
|||||||
<a-form-item>
|
<a-form-item>
|
||||||
<span class="switch-label">{{ realTimeEnabled ? t('views.dashboard.cdr.realTimeDataStart') : t('views.dashboard.cdr.realTimeDataStop') }}</span>
|
<span class="switch-label">{{ realTimeEnabled ? t('views.dashboard.cdr.realTimeDataStart') : t('views.dashboard.cdr.realTimeDataStop') }}</span>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 这里可以添加更多的表单项 -->
|
<a-form-item :label="t('views.ne.common.neType')" class="ne-type-select">
|
||||||
|
<a-select
|
||||||
|
v-model:value="selectedNeTypes"
|
||||||
|
mode="multiple"
|
||||||
|
style="min-width: 200px; width: 100%"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
>
|
||||||
|
<a-select-option v-for="type in ALL_NE_TYPES" :key="type" :value="type">
|
||||||
|
{{ type.toUpperCase() }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</div>
|
</a-card>
|
||||||
|
|
||||||
<GridLayout
|
<GridLayout
|
||||||
v-model:layout="chartOrder"
|
v-model:layout="chartOrder"
|
||||||
:col-num="12"
|
:col-num="12"
|
||||||
@@ -508,7 +661,7 @@ onUnmounted(() => {
|
|||||||
class="charts-container"
|
class="charts-container"
|
||||||
>
|
>
|
||||||
<GridItem
|
<GridItem
|
||||||
v-for="item in chartOrder"
|
v-for="item in chartOrder.filter(i => networkElementTypes.includes(i.i))"
|
||||||
:key="item.i"
|
:key="item.i"
|
||||||
:x="item.x"
|
:x="item.x"
|
||||||
:y="item.y"
|
:y="item.y"
|
||||||
@@ -546,7 +699,7 @@ onUnmounted(() => {
|
|||||||
></a-range-picker>
|
></a-range-picker>
|
||||||
</template>
|
</template>
|
||||||
<div class='chart'>
|
<div class='chart'>
|
||||||
<div :ref="el => { if (el) chartStates[item.i].chartDom.value = el as HTMLElement }"></div>
|
<div :ref="el => { if (el && chartStates[item.i]) chartStates[item.i].chartDom.value = el as HTMLElement }"></div>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
</GridItem>
|
</GridItem>
|
||||||
@@ -555,6 +708,10 @@ onUnmounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
.control-card {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.charts-container {
|
.charts-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
@@ -581,15 +738,6 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.control-row {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 16px;
|
|
||||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
|
||||||
border: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.switch-label {
|
.switch-label {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -599,8 +747,8 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.drag-handle {
|
.drag-handle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0;
|
||||||
right: 0px;
|
right: 0;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -617,12 +765,17 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ne-type-select {
|
||||||
|
flex-grow: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
:deep {
|
:deep {
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 12px !important;
|
padding: 16px !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,5 +792,9 @@ onUnmounted(() => {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-select {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user