fix:多选改checkbox
This commit is contained in:
@@ -251,14 +251,14 @@ function fnGetListTitle() {
|
|||||||
|
|
||||||
// 获取表头文字
|
// 获取表头文字
|
||||||
getKPITitle(state.neType[0])
|
getKPITitle(state.neType[0])
|
||||||
.then(res => {
|
.then(res => {//处理getKPITitle返回的结果
|
||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {//检查值
|
||||||
tableColumns.value = [];
|
tableColumns.value = [];//设为空数组
|
||||||
const columns: ColumnsType = [];
|
const columns: ColumnsType = [];//初始化,构建新表头
|
||||||
for (const item of res.data) {
|
for (const item of res.data) {//遍历res.data
|
||||||
const kpiDisplay = item[`${language}Title`];
|
const kpiDisplay = item[`${language}Title`];//提取标题kpiDisplay和ID标识kpiValue
|
||||||
const kpiValue = item[`kpiId`];
|
const kpiValue = item[`kpiId`];
|
||||||
columns.push({
|
columns.push({//
|
||||||
title: kpiDisplay,
|
title: kpiDisplay,
|
||||||
dataIndex: kpiValue,
|
dataIndex: kpiValue,
|
||||||
align: 'left',
|
align: 'left',
|
||||||
@@ -297,7 +297,7 @@ function fnGetListTitle() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {//result是前一个.then返回的值(true or false)
|
||||||
result && fnGetList();
|
result && fnGetList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -334,27 +334,27 @@ function fnChangShowType() {
|
|||||||
|
|
||||||
/**绘制图表 */
|
/**绘制图表 */
|
||||||
function fnRanderChart() {
|
function fnRanderChart() {
|
||||||
const container: HTMLElement | undefined = kpiChartDom.value;
|
const container: HTMLElement | undefined = kpiChartDom.value;//获取图表容器DOM元素
|
||||||
if (!container) return;
|
if (!container) return;//若没有,则退出函数
|
||||||
kpiChart.value = markRaw(echarts.init(container, 'light'));
|
kpiChart.value = markRaw(echarts.init(container, 'light'));
|
||||||
|
//初始化Echarts图表实例,应用light主题,并赋值给kpiChart.value,markRaw是vue函数,用于标记对象为不可响应
|
||||||
const option: EChartsOption = {
|
const option: EChartsOption = {//定义图表的配置对象,tooltip的出发方式为axis
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
position: function (pt: any) {
|
position: function (pt: any) {
|
||||||
return [pt[0], '10%'];
|
return [pt[0], '10%'];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {//x类别轴
|
||||||
type: 'category',
|
type: 'category',
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: [], // 数据x轴
|
data: [], // 数据x轴
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {//y类别轴
|
||||||
type: 'value',
|
type: 'value',
|
||||||
boundaryGap: [0, '100%'],
|
boundaryGap: [0, '100%'],
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {//图例垂直滚动
|
||||||
type: 'scroll',
|
type: 'scroll',
|
||||||
orient: 'vertical',
|
orient: 'vertical',
|
||||||
top: 40,
|
top: 40,
|
||||||
@@ -367,13 +367,13 @@ function fnRanderChart() {
|
|||||||
icon: 'circle',
|
icon: 'circle',
|
||||||
selected: {},
|
selected: {},
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {//网格区域边距
|
||||||
left: '10%',
|
left: '10%',
|
||||||
right: '30%',
|
right: '30%',
|
||||||
bottom: '20%',
|
bottom: '20%',
|
||||||
},
|
},
|
||||||
dataZoom: [
|
dataZoom: [
|
||||||
{
|
{//启用图表的数据缩放,范围90%-100%
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
start: 90,
|
start: 90,
|
||||||
end: 100,
|
end: 100,
|
||||||
@@ -385,9 +385,9 @@ function fnRanderChart() {
|
|||||||
],
|
],
|
||||||
series: [], // 数据y轴
|
series: [], // 数据y轴
|
||||||
};
|
};
|
||||||
kpiChart.value.setOption(option);
|
kpiChart.value.setOption(option);//设置图表配置项,应用到kpiChart实例上
|
||||||
|
|
||||||
// 创建 ResizeObserver 实例
|
// 创建 ResizeObserver 实例 监听图表容器大小变化,并在变化时调整图表大小
|
||||||
var observer = new ResizeObserver(entries => {
|
var observer = new ResizeObserver(entries => {
|
||||||
if (kpiChart.value) {
|
if (kpiChart.value) {
|
||||||
kpiChart.value.resize();
|
kpiChart.value.resize();
|
||||||
@@ -452,6 +452,7 @@ function fnRanderChartData() {
|
|||||||
|
|
||||||
// 用降序就反转
|
// 用降序就反转
|
||||||
let orgData = tableState.data;
|
let orgData = tableState.data;
|
||||||
|
console.log(orgData);
|
||||||
if (queryParams.sortOrder === 'desc') {
|
if (queryParams.sortOrder === 'desc') {
|
||||||
orgData = orgData.toReversed();
|
orgData = orgData.toReversed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,15 @@ 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';
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
const { t, currentLocale } = useI18n();
|
const { t, currentLocale } = useI18n();
|
||||||
|
|
||||||
const neInfoStore = useNeInfoStore();
|
const neInfoStore = useNeInfoStore();
|
||||||
|
|
||||||
//WebSocket连接
|
//WebSocket连接
|
||||||
const ws = ref<WS | null>(null);
|
const ws = ref<WS | null>(null);
|
||||||
|
|
||||||
//添加实时数据开关状态
|
//添加实时数据开关状态
|
||||||
const realTimeEnabled = ref(false);
|
const realTimeEnabled = ref(false);
|
||||||
//实时数据开关
|
//实时数据开关
|
||||||
@@ -28,20 +32,27 @@ const handleRealTimeSwitch = (checked: any) => {
|
|||||||
fnRealTimeSwitch(!!checked);
|
fnRealTimeSwitch(!!checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// 定义所有可能的网元类型
|
// 定义所有可能的网元类型
|
||||||
const ALL_NE_TYPES = ['ims', 'amf', 'udm', 'smf', 'pcf','upf','mme','mocngw','smsc','cbc','ausf'] as const;
|
const ALL_NE_TYPES = ['ims', 'amf', 'udm', 'smf', 'pcf','upf','mme','mocngw','smsc','cbc','ausf'] as const;
|
||||||
type AllChartType = typeof ALL_NE_TYPES[number];
|
type AllChartType = typeof ALL_NE_TYPES[number];
|
||||||
|
|
||||||
|
// 在 ALL_NE_TYPES 定义之后添加
|
||||||
|
const neTypeOptions = ALL_NE_TYPES.map(type => ({
|
||||||
|
label: type.toUpperCase(),
|
||||||
|
value: type
|
||||||
|
}));
|
||||||
|
|
||||||
// 使用 ref 来使 networkElementTypes 变为响应式,并使用 ALL_NE_TYPES 初始化
|
// 使用 ref 来使 networkElementTypes 变为响应式,并使用 ALL_NE_TYPES 初始化
|
||||||
const networkElementTypes = ref<AllChartType[]>([...ALL_NE_TYPES]);
|
const networkElementTypes = ref<AllChartType[]>([...ALL_NE_TYPES]);
|
||||||
|
|
||||||
// 添加选择的网元类型,也使用 ALL_NE_TYPES 初始化
|
// 添加选择的网元类型
|
||||||
const selectedNeTypes = ref<AllChartType[]>([...ALL_NE_TYPES]);
|
const selectedNeTypes = ref<AllChartType[]>([]);
|
||||||
|
|
||||||
// 临时状态 存储最新的选择
|
// 添加一个临时状态来存储最新的选择
|
||||||
const latestSelectedTypes = ref<AllChartType[]>([]);
|
const latestSelectedTypes = ref<AllChartType[]>([]);
|
||||||
|
|
||||||
// watch 函数
|
// 修改 watch 函数
|
||||||
watch(selectedNeTypes, (newTypes) => {
|
watch(selectedNeTypes, (newTypes) => {
|
||||||
console.log('Selected types changed:', newTypes);
|
console.log('Selected types changed:', newTypes);
|
||||||
// 立即更新 UI
|
// 立即更新 UI
|
||||||
@@ -52,11 +63,11 @@ watch(selectedNeTypes, (newTypes) => {
|
|||||||
debouncedUpdateCharts();
|
debouncedUpdateCharts();
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
|
|
||||||
// 防抖函数
|
// 修改防抖函数
|
||||||
const debouncedUpdateCharts = useDebounceFn(() => {
|
const debouncedUpdateCharts = useDebounceFn(() => {
|
||||||
// 比较当前选择和最新选择
|
// 比较当前选择和最新选择
|
||||||
if (JSON.stringify(latestSelectedTypes.value) !== JSON.stringify(selectedNeTypes.value)) {
|
if (JSON.stringify(latestSelectedTypes.value) !== JSON.stringify(selectedNeTypes.value)) {
|
||||||
// 如果不一致,以最新选择为准
|
// 如果不致,以最新选择为准
|
||||||
selectedNeTypes.value = latestSelectedTypes.value;
|
selectedNeTypes.value = latestSelectedTypes.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +103,7 @@ const debouncedUpdateCharts = useDebounceFn(() => {
|
|||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
// initCharts 函数
|
// 修改 initCharts 函数
|
||||||
const initCharts = async () => {
|
const initCharts = async () => {
|
||||||
console.log('Initializing charts for:', networkElementTypes.value);
|
console.log('Initializing charts for:', networkElementTypes.value);
|
||||||
|
|
||||||
@@ -132,7 +143,7 @@ const initCharts = async () => {
|
|||||||
localStorage.setItem('chartOrder', JSON.stringify(chartOrder.value));
|
localStorage.setItem('chartOrder', JSON.stringify(chartOrder.value));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 类型定义
|
// 添加类型定义
|
||||||
interface LayoutItem {
|
interface LayoutItem {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
@@ -148,7 +159,7 @@ const chartOrder = ref<Layout>(
|
|||||||
JSON.parse(localStorage.getItem('chartOrder') || 'null') ||
|
JSON.parse(localStorage.getItem('chartOrder') || 'null') ||
|
||||||
networkElementTypes.value.map((type, index) => ({
|
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, // 使用网元类型作为唯一标识
|
||||||
@@ -238,7 +249,7 @@ const rangePicker = reactive<RangePicker>({
|
|||||||
// dayjs('2024-09-20 23:59:59').valueOf().toString()
|
// dayjs('2024-09-20 23:59:59').valueOf().toString()
|
||||||
// ]
|
// ]
|
||||||
[
|
[
|
||||||
dayjs().startOf('day').valueOf().toString(), // 当天 0 点 0 分 0 秒
|
dayjs().startOf('day').valueOf().toString(), // 天 0 点 0 分 0 秒
|
||||||
dayjs().valueOf().toString() // 当前时间
|
dayjs().valueOf().toString() // 当前时间
|
||||||
]
|
]
|
||||||
])) as Record<AllChartType, [string, string]>,
|
])) as Record<AllChartType, [string, string]>,
|
||||||
@@ -334,7 +345,7 @@ const initChart = (type: AllChartType) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 观察图表容器
|
// 开始观察图表容器
|
||||||
state.observer.value.observe(container);
|
state.observer.value.observe(container);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -408,13 +419,13 @@ function fnRealTimeSwitch(bool: boolean) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 接收数据后错误回调
|
// 接收数据后错误回
|
||||||
function wsError() {
|
function wsError() {
|
||||||
|
|
||||||
message.error(t('common.websocketError'));
|
message.error(t('common.websocketError'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// wsMessage 数据回调
|
// 修改 wsMessage 数
|
||||||
function wsMessage(res: Record<string, any>) {
|
function wsMessage(res: Record<string, any>) {
|
||||||
const { code, data } = res;
|
const { code, data } = res;
|
||||||
if (code === RESULT_CODE_ERROR) {
|
if (code === RESULT_CODE_ERROR) {
|
||||||
@@ -573,7 +584,7 @@ onMounted(async () => {
|
|||||||
ws.value = new WS();
|
ws.value = new WS();
|
||||||
await neInfoStore.fnNelist();
|
await neInfoStore.fnNelist();
|
||||||
|
|
||||||
// 从本地存储中读取选中的网类型
|
// 从本地存储中读取选中的网元类型
|
||||||
const savedSelectedNeTypes = localStorage.getItem('selectedNeTypes');
|
const savedSelectedNeTypes = localStorage.getItem('selectedNeTypes');
|
||||||
if (savedSelectedNeTypes) {
|
if (savedSelectedNeTypes) {
|
||||||
const parsedSelectedNeTypes = JSON.parse(savedSelectedNeTypes) as AllChartType[];
|
const parsedSelectedNeTypes = JSON.parse(savedSelectedNeTypes) as AllChartType[];
|
||||||
@@ -625,6 +636,8 @@ onUnmounted(() => {
|
|||||||
state.observer.value.disconnect();
|
state.observer.value.disconnect();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 不需要显式取消防抖函数
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -642,16 +655,7 @@ onUnmounted(() => {
|
|||||||
<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-form-item :label="t('views.ne.common.neType')" class="ne-type-select">
|
||||||
<a-select
|
<a-checkbox-group v-model:value="selectedNeTypes" :options="neTypeOptions" />
|
||||||
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-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-card>
|
</a-card>
|
||||||
@@ -682,31 +686,31 @@ onUnmounted(() => {
|
|||||||
:min-h="3"
|
:min-h="3"
|
||||||
:is-draggable="true"
|
:is-draggable="true"
|
||||||
:is-resizable="true"
|
:is-resizable="true"
|
||||||
:resizable-handles="['ne']"
|
:resizable-handles="['se']"
|
||||||
drag-allow-from=".drag-handle"
|
drag-allow-from=".ant-card-head"
|
||||||
drag-ignore-from=".no-drag"
|
drag-ignore-from=".no-drag"
|
||||||
class="grid-item"
|
class="grid-item"
|
||||||
>
|
>
|
||||||
<div class="drag-handle">
|
<div class="date-picker-wrapper">
|
||||||
<DragOutlined />
|
<a-range-picker
|
||||||
|
v-model:value="rangePicker[item.i]"
|
||||||
|
:allow-clear="false"
|
||||||
|
bordered
|
||||||
|
:show-time="{ format: 'HH:mm:ss' }"
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
value-format="x"
|
||||||
|
:placeholder="rangePicker.placeholder"
|
||||||
|
:ranges="rangePicker.ranges"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="() => fetchData(item.i)"
|
||||||
|
></a-range-picker>
|
||||||
</div>
|
</div>
|
||||||
<a-card :bordered="false" class="card-container">
|
<a-card :bordered="false" class="card-container">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="no-drag">{{ item.i.toUpperCase() }}</span>
|
<div class="card-title">
|
||||||
</template>
|
<DragOutlined />
|
||||||
<template #extra>
|
<span>{{ item.i.toUpperCase() }}</span>
|
||||||
<a-range-picker
|
</div>
|
||||||
v-model:value="rangePicker[item.i]"
|
|
||||||
:allow-clear="false"
|
|
||||||
bordered
|
|
||||||
:show-time="{ format: 'HH:mm:ss' }"
|
|
||||||
format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
value-format="x"
|
|
||||||
:placeholder="rangePicker.placeholder"
|
|
||||||
:ranges="rangePicker.ranges"
|
|
||||||
style="width: 100%"
|
|
||||||
@change="() => fetchData(item.i)"
|
|
||||||
></a-range-picker>
|
|
||||||
</template>
|
</template>
|
||||||
<div class='chart'>
|
<div class='chart'>
|
||||||
<div :ref="el => { if (el && chartStates[item.i]) 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>
|
||||||
@@ -732,12 +736,37 @@ onUnmounted(() => {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-picker-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: -40px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.card-container {
|
.card-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
margin-right: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.chart {
|
.chart {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
@@ -756,28 +785,31 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.drag-handle {
|
.drag-handle {
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
|
||||||
background-color: rgba(24, 144, 255, 0.1);
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: move;
|
cursor: move;
|
||||||
z-index: 100;
|
|
||||||
transition: background-color 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
.anticon {
|
||||||
background-color: rgba(24, 144, 255, 0.2);
|
margin-right: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ne-type-select {
|
.ne-type-select {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
|
:deep(.ant-checkbox-group) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep {
|
:deep {
|
||||||
@@ -806,5 +838,9 @@ onUnmounted(() => {
|
|||||||
.ant-select {
|
.ant-select {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-card-head {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user