diff --git a/public/neDataImput/import_amf_imeiWhitelist_template.xlsx b/public/neDataImput/import_amf_imeiWhitelist_template.xlsx new file mode 100644 index 00000000..eadaf9b6 Binary files /dev/null and b/public/neDataImput/import_amf_imeiWhitelist_template.xlsx differ diff --git a/public/neDataImput/import_amf_whitelist_template.xlsx b/public/neDataImput/import_amf_whitelist_template.xlsx new file mode 100644 index 00000000..8408803f Binary files /dev/null and b/public/neDataImput/import_amf_whitelist_template.xlsx differ diff --git a/public/neDataImput/import_mme_imeiWhitelist_template.xlsx b/public/neDataImput/import_mme_imeiWhitelist_template.xlsx new file mode 100644 index 00000000..9d37feff Binary files /dev/null and b/public/neDataImput/import_mme_imeiWhitelist_template.xlsx differ diff --git a/src/views/ne/neConfig/components/Base.vue b/src/views/ne/neConfig/components/Base.vue index 8de2fa72..3c8f633c 100644 --- a/src/views/ne/neConfig/components/Base.vue +++ b/src/views/ne/neConfig/components/Base.vue @@ -5,7 +5,6 @@ import { Form, message } from 'ant-design-vue/es'; import useI18n from '@/hooks/useI18n'; import useNeInfoStore from '@/store/modules/neinfo'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; -import { addNeHost, updateNeHost } from '@/api/ne/neHost'; import { getNeConfigData, addNeConfigData, @@ -208,14 +207,14 @@ watch( // =============== 处理函数 -const supportMapper = { +const supportMapper: Record = { AMF: [ { type: 'array', name: 'guami', display: 'GUAMI List', key: ['plmnId'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; return { index: index, @@ -231,7 +230,7 @@ const supportMapper = { name: 'tai', display: 'TAI List', key: ['plmnId'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; return { index: index, @@ -245,7 +244,7 @@ const supportMapper = { name: 'slice', display: 'Slice List', key: ['plmnId'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; const sdStr = param.snssai.sd.padStart(6, '0'); return { @@ -263,7 +262,7 @@ const supportMapper = { name: 'plmn', display: 'PLMN List', key: ['mcc', 'mnc'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; const mccDomain = param.plmnId.mcc.padStart(3, '0'); const domain = `ims.mnc${param.plmnId.mnc}.mcc${mccDomain}.3gppnetwork.org`; @@ -295,7 +294,7 @@ const supportMapper = { name: 'gummei', display: 'Gummei List', key: ['plmnId'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; return Object.assign(lastItem, { index: index, @@ -308,7 +307,7 @@ const supportMapper = { name: 'tai', display: 'TAI List', key: ['plmnId'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; return { index: index, @@ -322,7 +321,7 @@ const supportMapper = { name: 'hss', display: 'HSS List', key: ['imsiPre'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; return Object.assign(lastItem, { index: index, @@ -335,7 +334,7 @@ const supportMapper = { name: 'sgw', display: 'SGW List', key: ['plmnId'], - item: (index, param, lastItem) => { + item: (index: any, param: any, lastItem: any) => { const plmn = `${param.plmnId.mcc}${param.plmnId.mnc}`; return Object.assign(lastItem, { index: index, @@ -429,7 +428,7 @@ async function toConfig( vArr.push(item[rule.key]); } if (vArr.includes(plmn)) { - const item = res.data.find(s => s[rule.key] == plmn); + const item = res.data.find((s: any) => s[rule.key] == plmn); if (!item) { // console.log('没有找到', rule.name, index); errMsgArr.push(`${ntType}_${neId} ${rule.display} not found`); @@ -450,7 +449,7 @@ async function toConfig( errMsgArr.push(`${ntType}_${neId} ${rule.display} modify ${state}`); } else { let lastIndex = 0; - const arr = res.data.sort((a, b) => b.index - a.index); + const arr = res.data.sort((a: any, b: any) => b.index - a.index); if (arr.length != 0) { lastIndex = arr[0].index + 1; } diff --git a/src/views/ne/neConfig/hooks/useArrayBatchDel.ts b/src/views/ne/neConfig/hooks/useArrayBatchDel.ts new file mode 100644 index 00000000..55fc99b5 --- /dev/null +++ b/src/views/ne/neConfig/hooks/useArrayBatchDel.ts @@ -0,0 +1,85 @@ +import { delNeConfigData } from '@/api/ne/neConfig'; +import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; +import { message } from 'ant-design-vue'; +import { reactive } from 'vue'; + +/** + * 批量删除array + * @param param 父级传入 { t, neTypeSelect, fnActiveConfigNode } + * @returns + */ +export default function useArrayBatch({ + t, + neTypeSelect, + fnActiveConfigNode, +}: any) { + /**状态属性 */ + const batchState = reactive({ + open: false, + loading: false, //批量删除 + paramName: '', + startIndex: 1, + num: 1, + }); + + /**对话框表格信息导入弹出窗口 */ + function modalBatchOpen(paramName: string) { + batchState.paramName = paramName; + batchState.open = true; + } + function modalBatchClose() { + if (batchState.loading) { + message.error({ + content: 'Delete is in progress, please wait for it to complete', + duration: 3, + }); + return; + } + batchState.open = false; + batchState.loading = false; + batchState.startIndex = 1; + batchState.num = 1; + fnActiveConfigNode('#'); + } + + async function modalBatchOk() { + let okNum = 0; + let failNum = 0; + const endIndex = batchState.startIndex + batchState.num - 1; + for (let i = endIndex; i >= batchState.startIndex; i--) { + const res = await delNeConfigData({ + neType: neTypeSelect.value[0], + neId: neTypeSelect.value[1], + paramName: batchState.paramName, + loc: `${i}`, + }); + if (res.code === RESULT_CODE_SUCCESS) { + okNum++; + } else { + failNum++; + break; + } + } + + if (okNum > 0) { + message.success({ + content: `Successfully deleted ${okNum} items`, + duration: 3, + }); + } + if (failNum > 0) { + message.error({ + content: `Delete failed, please check the index range`, + duration: 3, + }); + } + modalBatchClose(); + } + + return { + batchState, + modalBatchOpen, + modalBatchClose, + modalBatchOk, + }; +} diff --git a/src/views/ne/neConfig/hooks/useArrayImport.ts b/src/views/ne/neConfig/hooks/useArrayImport.ts new file mode 100644 index 00000000..68d2ecd4 --- /dev/null +++ b/src/views/ne/neConfig/hooks/useArrayImport.ts @@ -0,0 +1,205 @@ +import { addNeConfigData, editNeConfigData } from '@/api/ne/neConfig'; +import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; +import { readSheet } from '@/utils/execl-utils'; +import { message } from 'ant-design-vue'; +import { reactive } from 'vue'; +import saveAs from 'file-saver'; + +/** + * 导入文件加array + * @param param 父级传入 { t, neTypeSelect, arrayState, fnActiveConfigNode } + * @returns + */ +export default function useArrayImport({ + t, + neTypeSelect, + arrayState, + fnActiveConfigNode, +}: any) { + /**网元导入模板解析 */ + const m: Record = { + AMF: { + imeiWhitelist: { + filename: 'import_amf_imeiWhitelist_template', + fileetx: '.xlsx', + itemKey: 'imeiPrefixValue', + item: (row: Record) => { + return { + imeiPrefixValue: row['IMEI Prefix'], + index: 0, + }; + }, + }, + whitelist: { + filename: 'import_amf_whitelist_template', + fileetx: '.xlsx', + itemKey: 'imsiValue', + item: (row: Record) => { + return { + imsiValue: row['IMSI Value'], + imeiValue: row['IMEI Value/Prefix'], + index: 0, + }; + }, + }, + }, + MME: { + white_list: { + filename: 'import_mme_imeiWhitelist_template', + fileetx: '.xlsx', + itemKey: 'imei', + item: (row: Record) => { + return { + imei: row['IMEI'], + index: 0, + }; + }, + }, + }, + }; + + /**状态属性 */ + const importState = reactive({ + open: false, + msgArr: [] as string[], + loading: false, //开始导入 + itemKey: '', // 解析item的key + item: null as any, // 解析item方法 + paramName: '', + filename: '', + fileetx: '', + }); + + /**对话框表格信息导入弹出窗口 */ + function modalImportOpen(neType: string, paramName: string) { + const tmpM = m[neType][paramName]; + importState.itemKey = tmpM.itemKey; + importState.item = tmpM.item; + importState.paramName = paramName; + importState.filename = tmpM.filename; + importState.fileetx = tmpM.fileetx; + importState.open = true; + } + function modalImportClose() { + if (importState.loading) { + message.error({ + content: 'Import is in progress, please wait for it to complete', + duration: 3, + }); + return; + } + importState.open = false; + importState.msgArr = []; + importState.loading = false; + fnActiveConfigNode('#'); + } + + /**对话框表格信息导入上传 */ + async function modalImportUpload(file: File) { + const hide = message.loading(t('common.loading'), 0); + const [neType, neId] = neTypeSelect.value; + importState.msgArr = []; + + // 获取最大index + let index = 0; + if (arrayState.columnsData.length <= 0) { + index = 0; + } else { + const last = arrayState.columnsData[arrayState.columnsData.length - 1]; + index = last.index.value + 1; + } + + const reader = new FileReader(); + reader.onload = function (e: any) { + const arrayBuffer = e.target.result; + readSheet(arrayBuffer).then(async rows => { + if (rows.length <= 0) { + hide(); + message.error({ + content: t('views.neData.baseStation.importDataEmpty'), + duration: 3, + }); + return; + } + // 开始导入 + importState.loading = true; + for (const row of rows) { + const rowItem = importState.item(row); + const rowKey = rowItem[importState.itemKey]; + let result: any = null; + // 检查index是否定义 + const has = arrayState.columnsData.find( + (item: any) => item[importState.itemKey].value === rowKey + ); + if (has) { + // 已定义则更新 + rowItem.index = has.index.value; + result = await editNeConfigData({ + neType: neType, + neId: neId, + paramName: importState.paramName, + paramData: rowItem, + loc: `${rowItem.index}`, + }); + let msg = `index:${rowItem.index} update fail`; + if (result.code === RESULT_CODE_SUCCESS) { + msg = `index:${rowItem.index} update success`; + } + importState.msgArr.push(msg); + } else { + // 未定义则新增 + result = await addNeConfigData({ + neType: neType, + neId: neId, + paramName: importState.paramName, + paramData: Object.assign(rowItem, { index }), + loc: `${index}`, + }); + let msg = `index:${index} add fail`; + if (result.code === RESULT_CODE_SUCCESS) { + msg = `index:${index} add success`; + index += 1; + } + importState.msgArr.push(msg); + } + } + + hide(); + importState.loading = false; + }); + }; + reader.onerror = function (e) { + hide(); + console.error('reader file error:', e); + }; + reader.readAsArrayBuffer(file); + } + + /**对话框表格信息导入模板 */ + function modalImportTemplate() { + const hide = message.loading(t('common.loading'), 0); + + const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL; + const templateUrl = `${ + baseUrl.length === 1 && baseUrl.indexOf('/') === 0 + ? '' + : baseUrl.indexOf('/') === -1 + ? '/' + baseUrl + : baseUrl + }/neDataImput`; + saveAs( + `${templateUrl}/${importState.filename}${importState.fileetx}`, + `${importState.filename}_${Date.now()}${importState.fileetx}` + ); + + hide(); + } + + return { + importState, + modalImportOpen, + modalImportClose, + modalImportUpload, + modalImportTemplate, + }; +} diff --git a/src/views/ne/neConfig/index.vue b/src/views/ne/neConfig/index.vue index 294fe584..96fc5e5b 100644 --- a/src/views/ne/neConfig/index.vue +++ b/src/views/ne/neConfig/index.vue @@ -5,7 +5,6 @@ import { ProModal } from 'antdv-pro-modal'; import { message } from 'ant-design-vue/es'; import { DataNode } from 'ant-design-vue/es/tree'; import useI18n from '@/hooks/useI18n'; -import Base from './components/Base.vue'; import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import useNeInfoStore from '@/store/modules/neinfo'; @@ -13,8 +12,10 @@ import useOptions from './hooks/useOptions'; import useConfigList from './hooks/useConfigList'; import useConfigArray from './hooks/useConfigArray'; import useConfigArrayChild from './hooks/useConfigArrayChild'; +import useArrayImport from './hooks/useArrayImport'; +import useArrayBatchDel from './hooks/useArrayBatchDel'; import { getAllNeConfig, getNeConfigData } from '@/api/ne/neConfig'; -const neInfoStore = useNeInfoStore(); +const neListStore = useNeInfoStore(); const { t } = useI18n(); const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({ t, @@ -233,10 +234,13 @@ function fnGetNeConfig() { } else { paramPerms = ['post', 'put', 'delete']; } + const title = item.paramDisplay; + // 处理字符串开头特殊字符 + item.paramDisplay = title.replace(/[└─]+/, ''); arr.push({ ...item, children: undefined, - title: item.paramDisplay, + title: title, key: item.paramName, paramPerms, }); @@ -370,58 +374,50 @@ const { arrayEditClose, }); -const baseOpen = ref(false); -function fnBaseOpen() { - baseOpen.value = !baseOpen.value; -} +const { + importState, + modalImportOpen, + modalImportClose, + modalImportUpload, + modalImportTemplate, +} = useArrayImport({ t, neTypeSelect, arrayState, fnActiveConfigNode }); + +const { batchState, modalBatchOpen, modalBatchClose, modalBatchOk } = + useArrayBatchDel({ + t, + neTypeSelect, + fnActiveConfigNode, + }); onMounted(() => { - neInfoStore.fnNelist().then(res => { - if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) { - if (res.data.length > 0) { - // 过滤不可用的网元 - neCascaderOptions.value = neInfoStore.getNeSelectOtions.filter( - (item: any) => { - return !['LMF', 'NEF'].includes(item.value); - } - ); - if (neCascaderOptions.value.length === 0) { - message.warning({ - content: t('common.noData'), - duration: 2, - }); - return; - } - // 默认选择AMF - const item = neCascaderOptions.value.find(s => s.value === 'AMF'); - if (item && item.children) { - const info = item.children[0]; - neTypeSelect.value = [info.neType, info.neId]; - } else { - const info = neCascaderOptions.value[0].children[0]; - neTypeSelect.value = [info.neType, info.neId]; - } - fnGetNeConfig(); - } - } else { - message.warning({ - content: t('common.noData'), - duration: 2, - }); + // 获取网元网元列表 + neCascaderOptions.value = neListStore.getNeCascaderOptions.filter( + (item: any) => { + return !['LMF', 'NEF'].includes(item.value); // 过滤不可用的网元 } - }); + ); + if (neCascaderOptions.value.length === 0) { + message.warning({ + content: t('common.noData'), + duration: 2, + }); + return; + } + // 默认选择AMF + const item = neCascaderOptions.value.find(s => s.value === 'AMF'); + if (item && item.children) { + const info = item.children[0]; + neTypeSelect.value = [info.neType, info.neId]; + } else { + const info = neCascaderOptions.value[0].children[0]; + neTypeSelect.value = [info.neType, info.neId]; + } + fnGetNeConfig(); }); @@ -765,7 +794,6 @@ onMounted(() => { { {{ JSON.parse(text['filter'])[text.value] }} @@ -936,8 +964,83 @@ onMounted(() => { - - + + + + + + + + + + + + + + + + + + + + + +