feat: 网元配置多网元同时配置HA功能优化选择

This commit is contained in:
TsMask
2024-12-19 20:24:29 +08:00
parent 302ea84cde
commit 6e7402fd63
7 changed files with 154 additions and 337 deletions

View File

@@ -629,6 +629,7 @@ export default {
neTypePleace: "Please select the network element type",
neIdSyncPleace: "Please select the synchronized network element",
noConfigData: "No data on configuration items",
noConfigdDisabled: "The configuration item is not normal",
updateValue: "[ {num} ] parameter value modified successfully.",
updateValueErr: "Attribute value modification failure",
updateItem: "Modify Index to {num}.",
@@ -647,12 +648,6 @@ export default {
updateItemTip: "Confirm updating the data item with Index [{num}]?",
delItemTip: "Confirm deleting the data item with Index [{num}]?",
arrayMore: "Expand",
checkSync: {
sync: "Sync",
tip: "Synchronize regional network elements",
title: "Select All/Select None",
selectProvince: "Select",
}
},
neConfigBackup: {
name: "Name",

View File

@@ -629,6 +629,7 @@ export default {
neTypePleace: "请选择网元类型",
neIdSyncPleace: "请选择同步网元",
noConfigData: "暂无配置项数据",
noConfigdDisabled: "配置项网元未正常服务",
updateValue: "【 {num} 】 属性值修改成功",
updateValueErr: "属性值修改失败",
updateItem: "修改 Index 为 {num} 记录成功",
@@ -647,12 +648,6 @@ export default {
updateItemTip: "确认更新Index为 【{num}】 的数据项?",
delItemTip: "确认删除Index为 【{num}】 的数据项?",
arrayMore: "展开",
checkSync: {
sync: "同步",
tip: "同步区域网元",
title: "全选/全不选",
selectProvince: "选择区域",
}
},
neConfigBackup: {
name: "名称",

View File

@@ -1,191 +0,0 @@
<script setup lang="ts">
import { computed, nextTick, reactive, watch } from 'vue';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();
const emit = defineEmits(['province', 'update:province', 'update:checks']);
const props = defineProps({
/**
* 可选类型下的网元列表 neSelectOptions
*/
selects: {
type: Array<any>,
required: true,
},
/**
* 选择区域
*/
province: {
type: String,
default: '',
},
/**
* 选择勾选的同步网元neId
*/
checks: {
type: Array<string>,
default: () => [],
},
});
/**表格字段列勾选状态 */
const state = reactive<{
indeterminate: boolean;
/**是否全选 */
checkAll: boolean;
/**勾选列表 */
checks: string[];
}>({
indeterminate: false,
checkAll: true,
checks: props.checks,
});
watch(
() => props.checks,
val => {
state.checks = val;
}
);
/**列全选操作 */
function fnCheckAllChange(e: any) {
state.indeterminate = false;
state.checks = [];
const checked = e.target.checked;
if (checked) {
const group = selectGroup.value;
const arr = group[props.province];
for (const v of arr) {
if (v.disabled) {
continue;
}
state.checks.push(`${v.neId}`);
}
}
emit('update:checks', state.checks);
}
/**列勾选字段变化 */
function fnUpdateCheck(_: any) {
// 同区域全选
const selects: string[] = [];
const group = selectGroup.value;
const arr = group[props.province];
for (const v of arr) {
if (v.disabled) {
continue;
}
selects.push(`${v.neId}`);
}
// 判断是否全选
const len = state.checks.length;
state.indeterminate = !!len && len < selects.length;
state.checkAll = len === selects.length;
emit('update:checks', state.checks);
}
/**
* 选择的网元分组
*/
const selectGroup = computed(() => {
const group: Record<string, any> = {};
for (const element of props.selects) {
const key = element['province'];
if (group[key]) {
group[key].push(element);
} else {
group[key] = [element];
}
}
return group;
});
/**
* 选择的网元分组
*/
function fnProvinceCheck(province: string) {
emit('update:province', province);
nextTick(() => {
fnCheckAllChange({ target: { checked: true } });
}).finally(() => {
emit('province', province);
});
}
</script>
<template>
<a-tooltip placement="topRight">
<template #title>
{{ t('views.ne.neConfig.checkSync.tip') }}
</template>
<a-popover trigger="click" placement="bottomRight">
<template #title>
<div class="title">
<a-checkbox
v-model:checked="state.checkAll"
:indeterminate="state.indeterminate"
@change="fnCheckAllChange"
>
{{ t('views.ne.neConfig.checkSync.title') }}
</a-checkbox>
</div>
</template>
<template #content>
<a-checkbox-group
v-model:value="state.checks"
@change="fnUpdateCheck"
style="width: 200px; max-height: 450px; overflow-y: auto"
>
<template v-for="(v, k) in selectGroup" :key="k">
<div class="item-title">
<span> {{ k }} </span>
<a-button size="small" type="dashed" @click="fnProvinceCheck(k)">
{{ t('views.ne.neConfig.checkSync.selectProvince') }}
</a-button>
</div>
<div class="item" v-for="i in v">
<a-checkbox
:value="i.neId"
:disabled="i.disabled || k !== province"
>
{{ i.neName }}
</a-checkbox>
</div>
<a-divider style="margin: 0"> </a-divider>
</template>
</a-checkbox-group>
</template>
<a-tag
:color="state.checks.length > 0 ? 'processing' : 'warning'"
style="cursor: pointer"
>
<template #icon> <SyncOutlined /> </template>
{{ t('views.ne.neConfig.checkSync.sync') }}
</a-tag>
</a-popover>
</a-tooltip>
</template>
<style lang="less" scoped>
.title {
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
margin-left: 4px;
}
.item-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 4px;
}
.item {
display: flex;
align-items: center;
width: 100%;
padding: 4px;
}
</style>

View File

@@ -133,17 +133,7 @@ export default function useConfigArray({
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
editNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc: loc,
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
editNeConfigData({
@@ -155,6 +145,16 @@ export default function useConfigArray({
})
);
}
} else {
reqArr.push(
editNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc: loc,
})
);
}
// 无请求提示
if (reqArr.length === 0) {
@@ -207,16 +207,7 @@ export default function useConfigArray({
onOk() {
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
delNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
loc: loc,
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
delNeConfigData({
@@ -227,6 +218,15 @@ export default function useConfigArray({
})
);
}
} else {
reqArr.push(
delNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
loc: loc,
})
);
}
// 无请求提示
if (reqArr.length === 0) {
@@ -336,17 +336,7 @@ export default function useConfigArray({
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
addNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc: `${from['index']['value']}`,
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
addNeConfigData({
@@ -358,6 +348,16 @@ export default function useConfigArray({
})
);
}
} else {
reqArr.push(
addNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc: `${from['index']['value']}`,
})
);
}
// 无请求提示
if (reqArr.length === 0) {

View File

@@ -201,17 +201,7 @@ export default function useConfigArrayChild({
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
editNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc,
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
editNeConfigData({
@@ -223,6 +213,16 @@ export default function useConfigArrayChild({
})
);
}
} else {
reqArr.push(
editNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc,
})
);
}
// 无请求提示
if (reqArr.length === 0) {
@@ -276,16 +276,7 @@ export default function useConfigArrayChild({
onOk() {
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
delNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
loc,
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
delNeConfigData({
@@ -296,6 +287,15 @@ export default function useConfigArrayChild({
})
);
}
} else {
reqArr.push(
delNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
loc,
})
);
}
// 无请求提示
if (reqArr.length === 0) {
@@ -381,17 +381,7 @@ export default function useConfigArrayChild({
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
addNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc,
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
addNeConfigData({
@@ -403,6 +393,16 @@ export default function useConfigArrayChild({
})
);
}
} else {
reqArr.push(
addNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: data,
loc,
})
);
}
// 无请求提示
if (reqArr.length === 0) {

View File

@@ -86,18 +86,7 @@ export default function useConfigList({
// 请求
const reqArr = [];
if (neTypeSelect.value[1] !== 'SYNC') {
reqArr.push(
editNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: {
[from['name']]: from['value'],
},
})
);
} else {
if (neTypeSelect.value[1].startsWith('SYNC')) {
for (const neId of neIdSelect.value) {
reqArr.push(
editNeConfigData({
@@ -110,6 +99,17 @@ export default function useConfigList({
})
);
}
} else {
reqArr.push(
editNeConfigData({
neType: neTypeSelect.value[0],
neId: neTypeSelect.value[1],
paramName: treeState.selectNode.paramName,
paramData: {
[from['name']]: from['value'],
},
})
);
}
// 无请求提示
if (reqArr.length === 0) {

View File

@@ -1,20 +1,11 @@
<script setup lang="ts">
import {
reactive,
ref,
onMounted,
toRaw,
watch,
nextTick,
computed,
} from 'vue';
import { reactive, ref, onMounted, toRaw, watch, computed } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { ProModal } from 'antdv-pro-modal';
import { message } from 'ant-design-vue/es';
import { message, TreeSelect, type TreeSelectProps } from 'ant-design-vue/es';
import { DataNode } from 'ant-design-vue/es/tree';
import useI18n from '@/hooks/useI18n';
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
import CheckSyncNe from './components/CheckSyncNe/index.vue';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo';
import useOptions from './hooks/useOptions';
@@ -30,14 +21,13 @@ const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
/**网元类型 type,[](type,id) */
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**网元类型 [](type,id) */
let neSelectOptions = ref<Record<string, any>[]>([]);
/**网元类型 [](label,value,children) */
let neSelectTreeDate = ref<TreeSelectProps['treeData']>([]);
/**网元类型选择 type,id */
let neTypeSelect = ref<string[]>(['', '']);
/**网元类型选择 id */
let neIdSelect = ref<string[]>([]);
let neTypeSelectStatus = ref(true);
let neTypeSelectProvince = ref('-');
/**网元类型neType选择 */
async function fnSelectNeType(_: any, info: any) {
if (!info) return;
@@ -57,29 +47,50 @@ async function fnSelectNeType(_: any, info: any) {
treeState.selectLoading = true;
neTypeSelectStatus.value = true;
neIdSelect.value = [];
// 检查下级网元是否可用
// 构建可选树形数据
if (Array.isArray(info.children) && info.children.length > 0) {
neSelectOptions.value = info.children.concat();
for (let index = 0; index < neSelectOptions.value.length; index++) {
const v = neSelectOptions.value[index];
const neArr = info.children.concat();
for (let index = 0; index < neArr.length; index++) {
const v = neArr[index];
const ne = {
label: v.neName,
value: v.neId,
disabled: false,
};
// 检查下级网元是否可用
const res = await getNeConfigData({
neType: v.neType,
neId: v.neId,
paramName: `${treeState.data[0].key}`,
});
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
neSelectOptions.value[index].disabled = !res.data.length;
ne.disabled = !res.data.length;
} else {
ne.disabled = true;
}
// 添加到树形数据
const root = neSelectTreeDate.value?.find(s => s.label === v.province);
if (root && Array.isArray(root.children)) {
root.children.push(ne);
} else {
neSelectTreeDate.value?.push({
label: v.province,
value: 'SYNC_' + v.province,
children: [ne],
});
}
const key = 'SYNC_' + v.province;
// 初始区域
if (neIdSelect.value.length === 0) {
neTypeSelectProvince.value = v.province;
neTypeSelect.value[1] = key;
}
// 同区域内添加
if (neTypeSelectProvince.value === v.province) {
if (neTypeSelect.value[1] === key) {
neIdSelect.value.push(v.neId);
}
} else {
neSelectOptions.value[index].disabled = true;
}
}
}
fnActiveConfigNode(treeState.data[0].key);
@@ -87,20 +98,23 @@ async function fnSelectNeType(_: any, info: any) {
}
/**网元类型neId选择 */
function fnSelectNeId(_: any, info: any) {
if (!info) {
neTypeSelect.value[1] = 'SYNC';
if (info.children && Array.isArray(info.children)) {
const okArr = info.children.filter((item: any) => !item.disabled);
if (Array.isArray(okArr) && okArr.length === 0) {
message.warning({
content: `${t('views.ne.neConfig.noConfigdDisabled')}`,
duration: 3,
});
neIdSelect.value = [];
return;
}
neTypeSelect.value[1] = info.value;
neIdSelect.value = okArr.map((item: any) => item.value);
} else {
neTypeSelect.value[1] = info.neId;
neTypeSelect.value[1] = info.value;
}
fnActiveConfigNode(treeState.data[0].key);
}
/**网元服务地区选择 */
function fnSelectProvince(province: string) {
// neTypeSelectProvince.value = province;
nextTick(() => {
fnActiveConfigNode(treeState.data[0].key);
});
}
/**左侧导航是否可收起 */
let collapsible = ref<boolean>(true);
@@ -181,7 +195,7 @@ function fnActiveConfigNode(key: string | number) {
let neId = neTypeSelect.value[1];
// 无neId时取首个可连接的
if (neId === 'SYNC') {
if (neId.startsWith('SYNC')) {
const oneNeId = neIdSelect.value[0];
if (oneNeId) {
neId = oneNeId;
@@ -253,7 +267,7 @@ async function fnGetNeConfig(neType: string) {
/**过滤可见项 */
const treeStateData = computed(() => {
// 公共
if (neTypeSelect.value[1] === 'SYNC') {
if (neTypeSelect.value[1].startsWith('SYNC')) {
return treeState.data.filter(item => item.visible === 'public');
}
// 具体网元
@@ -295,7 +309,7 @@ function fnGetNeConfigData(
if (param.paramType === 'list') {
// 过滤可见规则项
let ruleArrFilter: Record<string, any>[] = [];
if (neTypeSelect.value[1] === 'SYNC') {
if (neTypeSelect.value[1].startsWith('SYNC')) {
ruleArrFilter = ruleArr.filter(item => item['visible'] === 'public');
} else {
ruleArrFilter = ruleArr.filter(item => item['visible'] === 'self');
@@ -461,7 +475,12 @@ watch(
val => {
// SMF需要选择配置的UPF id
if (val && neTypeSelect.value[0] === 'SMF') {
if (neTypeSelect.value[1].startsWith('SYNC')) {
smfByUPFIdLoadData(neTypeSelect.value[1]);
return;
} else {
smfByUPFIdLoadData(neTypeSelect.value[1]);
}
}
}
);
@@ -533,12 +552,10 @@ onMounted(() => {
// 默认选择AMF
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
if (item && item.children) {
neSelectOptions.value = item.children.concat();
fnSelectNeType(null, item);
// const info = item.children[0];
// neTypeSelect.value = [info.neType, info.neId];
} else {
neSelectOptions.value = neCascaderOptions.value[0].children.concat();
fnSelectNeType(null, neCascaderOptions.value[0]);
// const info = neCascaderOptions.value[0].children[0];
// neTypeSelect.value = [info.neType, info.neId];
@@ -581,15 +598,23 @@ onMounted(() => {
style="width: 40%"
>
</a-select>
<a-select
<a-tree-select
v-model:value="neTypeSelect[1]"
:status="neIdSelect.length === 0 ? 'warning' : ''"
:disabled="treeState.selectLoading"
:value="neTypeSelect[1]"
:options="neSelectOptions"
:allow-clear="true"
@change="fnSelectNeId"
:tree-data="neSelectTreeDate"
:maxTagCount="1"
:show-search="true"
:allow-clear="false"
:tree-default-expand-all="true"
:tree-checkable="false"
:show-checked-strategy="TreeSelect.SHOW_PARENT"
placement="bottomRight"
tree-node-filter-prop="label"
style="width: 60%"
@select="fnSelectNeId"
>
</a-select>
</a-tree-select>
</a-input-group>
</a-form-item>
<a-form-item name="treeStateData">
@@ -632,13 +657,6 @@ onMounted(() => {
</template>
<template #extra>
<a-space :size="8" align="center" v-show="!treeState.selectLoading">
<CheckSyncNe
v-if="neTypeSelect[1] === 'SYNC'"
:selects="neSelectOptions"
v-model:checks="neIdSelect"
v-model:province="neTypeSelectProvince"
@province="fnSelectProvince"
></CheckSyncNe>
<a-tooltip placement="topRight">
<template #title>{{ t('common.reloadText') }}</template>
<a-button