| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- <template>
- <v-dialog v-model="props.isExcelUploadModal" persistent width="32.8125rem">
- <div class="v-common-dialog-wrapper custom-dialog">
- <div class="modal-tit">
- <strong>엑셀업로드</strong>
- <button class="btn-close" @click="$emit('closeModal')"></button>
- </div>
- <div class="v-common-dialog-content">
- <div class="excel-step">
- <div class="excel-step-box">
- <div class="excel-step-top">
- <span class="step" style="width:3.9375rem">Step1</span>
- <strong>양식 다운로드</strong>
- </div>
- <div class="excel-step-btm">
- <div class="excel--inner--content">
- <div class="ico"></div>
- <div class="desc">
- <p>일괄 등록 양식을 다운로드 받아 양식에 맞게 데이터를 입력 하고 하단의 첨부파일 등록을 통해 일괄 등록 신청을 진행하세요.</p>
- <v-btn class="custom-btn mini btn-gray" @click="fnExcelFormDownload">엑셀 다운로드</v-btn>
- </div>
- </div>
- </div>
- </div>
- <div class="excel-step-box">
- <div class="excel-step-top">
- <span class="step">Step2</span>
- <strong>엑셀 일괄 업로드</strong>
- </div>
- <div class="excel-step-btm">
- <div class="step-bg-box type2">
- <p>양식에 맞게 작성을 하였다면 해당 파일을 업로드하세요.</p>
- <p class="txt2">(파일 등록 시 STEP 03에서 결과 확인 가능)</p>
- <div class="add-file">
- <v-file-input
- hide-details
- @change="fnFileChange"
- @click:clear="fnClearFile"
- >
- <template v-slot:label>
- <v-btn class="custom-btn mini btn-gray" style="max-width:7.0625rem!important; height:2.25rem;">엑셀 일괄 등록</v-btn>
- </template>
- </v-file-input>
- </div>
- </div>
- </div>
- </div>
- <div class="excel-step-box">
- <div class="excel-step-top">
- <span class="step">Step3</span>
- <strong>일괄 등록 결과 확인</strong>
- </div>
- <div class="excel-step-btm">
- <div class="tbl-wrapper">
- <div class="tbl-wrap">
- <!-- ag grid -->
- <ag-grid-vue
- style="width:100%; height:calc(5 * 3.15rem);"
- class="ag-theme-quartz"
- :gridOptions="gridOptions2"
- :defaultColDef="defaultColDef"
- :columnDefs="tblHeaders2"
- :rowData="tblItems2"
- :suppressPaginationPanel="true"
- :overlayNoRowsTemplate="getExcelResultMsg"
- @grid-ready="fnOnGridReady"
- >
- </ag-grid-vue>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="btn-wrap">
- <v-btn
- class="custom-btn btn-white mini"
- @click="$emit('closeModal')"
- >
- <i class="ico"></i>
- 취소
- </v-btn>
- <v-btn class="custom-btn btn-blue mini" :disabled="isUploadStep3 === false" @click="fnUploadProc">
- <i class="ico"></i>
- 확인
- </v-btn>
- </div>
- </div>
- </v-dialog>
- </template>
- <script setup>
- /***********************
- * import
- ************************/
- import { read, utils, writeFile } from "xlsx";
- import { useI18n } from "vue-i18n"
- import useUtil from "@/composables/useUtil"
- import useValid from "@/composables/useValid"
- import "ag-grid-community/styles/ag-grid.css"
- import "ag-grid-community/styles/ag-theme-quartz.css"
- import { AgGridVue } from "ag-grid-vue3"
- import customTextDiv from '@/components/design/customTextDiv'
- /***********************
- * plugins inject
- ************************/
- const { $toast, $log, $dayjs, $eventBus } = useNuxtApp()
- // props
- const props = defineProps({
- isExcelUploadModal: Boolean,
- menu: String,
- imsiPrefixList: Array
- });
- // 참조가능 데이터 설정
- defineExpose({
- fnInit,
- })
- // 발신 이벤트 선언
- const emit = defineEmits(["closeModal", "uploadProc"])
- const i18n = useI18n()
- /***********************
- * data & created
- ************************/
- const tblHeaders2 = ref([
- { headerName: 'No', field: 'no'},
- { headerName: '엑셀 시트', field: 'headerName'},
- { headerName: '엑셀 행', field: 'cellNum'},
- { headerName: '실패 원인', field: 'errorMsg', cellRenderer : customTextDiv},
- ])
- const tblItems2 = ref([])
- const excelFileNames = ref([])
- const invalidData = ref([]) // 등록실패 데이터
- const isUploadStep2 = ref(false) // 파일 등록 여부
- const isUploadStep3 = ref(false) // 파일 데이터 유효성 통과 여부
- const uploadParams = ref(null)
- const remToPx = () => parseFloat(getComputedStyle(document.documentElement).fontSize);
- const rowHeightRem = 2.65; // 원하는 rem 값
- const rowHeightPx = rowHeightRem * remToPx();
- // gridOption2
- const gridOptions2 = {
- columnDefs: tblHeaders2.value,
- rowData: tblItems2.value, // 테이블 데이터
- rowSelection : 'multiple',
- autoSizeStrategy: {
- type: "fitGridWidth", // width맞춤
- },
- headerHeight : rowHeightPx,
- rowHeight: rowHeightPx,
- pagination: true,
- // overlayNoRowsTemplate: '<span class="no--rows--custom"><i class="ico-excel"></i>※ 엑셀 파일을 일괄 등록하세요.</span>',
- suppressPaginationPanel: true, // 하단 default 페이징 컨트롤 숨김
- suppressRowClickSelection: true, // 행 클릭 체크박스 무시
- localeText: {
- noRowsToShow: i18n.t('common.noData')
- },
- }
- const excelResultMsg = ref('<span class="no--rows--custom"><i class="ico-excel"></i>※ 엑셀 파일을 일괄 등록하세요.</span>')
- // grid default 옵션
- const defaultColDef = ref({
- lockVisible: true, // 열을 그리드 밖으로 꺼내지 않음
- })
- const gridApi = shallowRef()
- const isExcel = ref(false)
- const getExcelResultMsg = computed(() => {
- if(!isExcel.value) {
- return '<span class="no--rows--custom"><i class="ico-excel"></i>※ 엑셀 파일을 일괄 등록하세요.</span>'
- }else{
- return '<span class="no--rows--custom"><i class="ico-excel"></i>※ 등록한 파일의 데이터가 정상입니다.</span>'
- }
- })
- /***********************
- * Methods
- ************************/
- function fnInit() {
- tblItems2.value = []
- isUploadStep2.value = false
- isUploadStep3.value = false
- uploadParams.value = null
- invalidData.value = []
- }
- /**
- * 엑셀 양식 다운로드
- */
- function fnExcelFormDownload(){
- let arrForm = ''
- let arrGuide = ''
- let sheetTitle = ''
- let fileName = ''
- if(props.menu === 'userMgmt') {
- arrForm = fnSetUserInsertForm()
- arrGuide = fnSetUserGuideForm()
- sheetTitle = 'USERS'
- fileName = '가입자일괄등록양식'
- }else{
- arrForm = fnSetNeInsertForm()
- arrGuide = fnSetNeGuideForm()
- sheetTitle = 'NE'
- fileName = 'NE일괄등록양식'
- }
- useUtil.fnExcelFormDown(arrForm, arrGuide, sheetTitle, fileName)
- }
- // 가입자등록 양식 데이터
- function fnSetUserInsertForm() {
- let arr = []
- arr.push([
- "tenantName",
- "imsi",
- "msisdns",
- "skey",
- "opc",
- "uplink",
- "downlink",
- "singleNssais",
- "defaultNssais",
- "dnnConf_1_nssai",
- "dnnConf_1_dnn",
- "dnnConf_2_nssai",
- "dnnConf_2_dnn",
- "dnnConf_3_nssai",
- "dnnConf_3_dnn",
- "dnnConf_4_nssai",
- "dnnConf_4_dnn",
- "dnnConf_5_nssai",
- "dnnConf_5_dnn",
- "dnnConf_6_nssai",
- "dnnConf_6_dnn",
- "dnnConf_7_nssai",
- "dnnConf_7_dnn",
- "dnnConf_8_nssai",
- "dnnConf_8_dnn",
- "dnnConf_9_nssai",
- "dnnConf_9_dnn",
- "dnnConf_10_nssai",
- "dnnConf_10_dnn",
- ])
- arr.push(["KT", "45043000", "", "", "", ""])
- return arr
- }
- // 가입자등록 양식 유효성 데이터
- function fnSetUserGuideForm() {
- let arr = []
- arr.push(["COLUMN NAME", "입력 설명"])
- arr.push(["tenantName", "테넌트 이름"])
- arr.push(["imsi","IMSI, 앞 자리 값은 테넌트에 할당된 번호여야 하고 테넌트 이름과 함께 유효성 체크를 한다.",])
- arr.push(["msisdns","pattern: '(msisdn-[0-9]{5,15}|extid-.+@.+|.+)' 콤마(,)로 구분하여 여러개 입력이 가능하다. -- ex) 1000,2000,3000",])
- arr.push(["skey", ""])
- arr.push(["opc", ""])
- arr.push(["uplink","subscribed-UeAmbr Uplink, pattern: '^\\d+(\\.\\d+)? (bps|Kbps|Mbps|Gbps|Tbps)$' -- ex) 1024 Mbps",])
- arr.push(["downlink","subscribed-UeAmbr Downlink, pattern: '^\\d+(\\.\\d+)? (bps|Kbps|Mbps|Gbps|Tbps)$' -- ex) 1024 Mbps",])
- arr.push(["singleNssais","List of non default Single Nssais. 콤마(,)로 구분하여 여러개 입력이 가능하다. -- ex) 1000,2000,3000",])
- arr.push(["defaultNssais","A list of Single Nssais used as default. 콤마(,)로 구분하여 여러개 입력이 가능하다. -- ex) 1000,2000,3000",])
- arr.push(["dnnConf/{index}/nssai","dnnConf는 최대 5개의 nssai 와 dnn 쌍으로 입력 가능하다.",])
- arr.push(["dnnConf/{index}/dnn","반드시 1쌍 이상으로 index를 유의해서 입력해야한다. 쌍이 성립되지 않으면 데이터는 처리하지 않는다.",])
- return arr
- }
- // NE등록 양식 데이터
- function fnSetNeInsertForm(){
- let arr = []
- arr.push([
- 'NE Name',
- 'Tenant Name',
- 'NE Group Name',
- 'NE Type',
- 'NE ID',
- 'Connected UPF',
- 'EMS Name',
- 'NE Address',
- 'NE Location (Latitude)',
- 'NE Location (Longitude)',
- 'Description'
- ])
- arr.push(["nename01", "", "", "", "", "", "", "", "", "", ""])
- return arr
- }
- // NE등록 양식 유효성 데이터
- function fnSetNeGuideForm(){
- let arr = []
- arr.push(["COLUMN NAME", "입력 설명"])
- arr.push(["NE Name", "NE 이름"])
- arr.push(["Tenant Name","테넌트 이름",])
- arr.push(["NE Group Name","NE 그룹 이름",])
- arr.push(["NE Type", "NE 유형"])
- arr.push(["NE ID", ""])
- arr.push(["Connected UPF","연동 UPF",])
- arr.push(["EMS Name","수집 시스템",])
- arr.push(["NE Address","NE 주소",])
- arr.push(["NE Location (Latitude)","NE 주소 위도",])
- arr.push(["NE Location (Longitude)","NE 주소 경도",])
- arr.push(["Description","설명",])
- return arr
- }
- /**
- * 파일 업로드 이벤트
- */
- function fnFileChange(event) {
- let isFiles = event.target.files.length > 0
- if(isFiles) {
- isUploadStep2.value = true // 파일 업로드한 상태
- isUploadStep3.value = false
- let excelFileName = event.target.files[0].name;
- excelFileNames.value = excelFileName
- if (excelFileName.includes("xlsx") === true ||excelFileName.includes("xls") === true) {
- const file = event.target.files[0]
- let reader = new FileReader()
- reader.onload = () => {
- let data = reader.result
- let workbook
- try {
- workbook = read(data, { type: "binary" })
- } catch (error) {
- alert("파일을 읽을 수 없습니다.")
- return;
- }
- let sheetName = workbook.SheetNames[0]
- let worksheet = workbook.Sheets[sheetName]
- const rowObject = utils.sheet_to_json(worksheet)
- // 엑셀 데이터를 JSON으로 변환하면서 셀 위치 정보를 추가
- const jsonData = utils.sheet_to_json(worksheet, { header: 1 })
-
- console.log('%c rowObject########' ,'color:#bada55', rowObject)
- console.log('%c jsonData' ,'color:#bada55', jsonData)
- // 빈배열제거
- const newData = jsonData.filter(el => el.length)
- const headers = newData[0]
- let rowData = newData.slice(1).map((row, rowIndex) => {
- const obj = {}
- headers.forEach((header, colIndex) => {
- const cell = row[colIndex] !== undefined ? row[colIndex] : '' // 값을 설정하고 빈 값은 빈 문자열로
- obj[header] = {
- value: cell,
- cell: utils.encode_cell({ r: rowIndex + 1, c: colIndex }),
- }
- })
- return obj
- })
-
- let invalidDataList = []
- if(props.menu === 'userMgmt') {
- // 사용자 일괄 등록
- invalidDataList = userValidateData(headers, rowData)
- if(invalidDataList.length === 0){
- // 유효성 모두 통과
- let param = fnUserMakeParam(rowData)
- uploadParams.value = _cloneDeep(param)
- } else {
- uploadParams.value = null
- }
- }else{
- // NE 일괄 등록
- invalidDataList = neValidateData(headers, rowData)//neValidateData(rowData)
- if(invalidDataList.length === 0){
- let param = fnNeMakeParam(rowData)
- uploadParams.value = _cloneDeep(param)
- } else {
- uploadParams.value = null
- }
- }
- // 유효성 체크 리스트
- invalidData.value = _cloneDeep(invalidDataList)
- if(invalidDataList.length === 0) {
- isExcel.value = true
- // gridApi.value.api.setRowData(rowData.value);
- setTimeout(() => {
- gridApi.value.showNoRowsOverlay();
- }, 1);
- }else{
- isExcel.value = false
- }
- // 양식에러 테이블 데이터 목록
- tblItems2.value = _cloneDeep(invalidData.value)
- isUploadStep3.value = invalidData.value.length === 0
- }
- reader.readAsBinaryString(file)
- } else {
- alert("파일 확장자를 확인하세요(.xlsx, .xls)")
- }
- }
- else{
- isUploadStep2.value = false
- isUploadStep3.value = false
- fnClearFile()
- }
- }
- /**
- * 사용자 일괄등록 유효성 검사
- */
- function userValidateData(headers, data) {
- let invalidData = [];
-
- // 유효성 체크 항목들
- let regexMap = {
- tenantName: fnBusinessNameChk, // 테넌트명 체크
- uplink: fnLinkValidChk, // 업로드 속도값 체크
- downlink: fnLinkValidChk, // 다운로드 속도값 체크
- imsi: fnImsiChk, // IMSI체크
- msisdns: fnMsisdnsChk, // MSISDN 체크
- // defaultNssais: fnDefaultNssaisChk, // Default NSSAI 체크
- };
- const dnnConf = [
- 'dnnConf_1_nssai', 'dnnConf_1_dnn',
- 'dnnConf_2_nssai', 'dnnConf_2_dnn',
- 'dnnConf_3_nssai', 'dnnConf_3_dnn',
- 'dnnConf_4_nssai', 'dnnConf_4_dnn',
- 'dnnConf_5_nssai', 'dnnConf_5_dnn',
- 'dnnConf_6_nssai', 'dnnConf_6_dnn',
- 'dnnConf_7_nssai', 'dnnConf_7_dnn',
- 'dnnConf_8_nssai', 'dnnConf_8_dnn',
- 'dnnConf_9_nssai', 'dnnConf_9_dnn',
- 'dnnConf_10_nssai', 'dnnConf_10_dnn',
- ]
- // dnnConf키 수집 수
- let dnnConfKeyCnt = 0
- // 필수 키값 목록
- const requiredFields = ['tenantName', 'imsi', 'msisdns', 'skey', 'opc', 'uplink', 'downlink', 'singleNssais', 'defaultNssais']
- // IMSI 중복체크 데이터
- const imsiList = data.map(row => {
- if(row.hasOwnProperty('imsi')) {
- return row.imsi.value.toString()
- }else return []
- })
- // flatMap으로 평탄화 작업
- let num = 0
- invalidData = data.flatMap((item, index) => {
- // row 한바퀴 수행 후 초기화
- dnnConfKeyCnt = 0
- validDnnConf.value = []
- dnnConfigCnt.value = 0
- return Object.entries(item).flatMap(([key, { value, cell }]) => {
- // 필수 값 체크 dnnConf키가 아니고 필수키가 없는 경우
- if (!dnnConf.includes(key) && !requiredFields.includes(key)) {
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: '형식에러' }
- }
- if (requiredFields.includes(key) && useUtil.isNull(value)) {
- // 헤더 키는 존재하나 데이터가 없는 경우
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: 'noData' }
- }
-
- if(dnnConf.includes(key)) {
- dnnConfKeyCnt++
- }
- if(dnnConfKeyCnt == 19) {
- const result = fnDnnValidation(item)
- if(result !==true){
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: result }
- }
- }
- // IMSI 중복 체크
- if (key === 'imsi') {
- const result = fnImsiDupChk(item, key, imsiList);
- if (result !== true) {
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: result }
- }
- }
- const regex = regexMap[key];
- if (regex) {
- const result = regex(item, key);
-
- if (result !== true) {
- // 정규식 통과 실패
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: result }
- }
- }
- return []
- })
- })
- return invalidData
- }
- /**
- * 사용자일괄등록 param목록
- */
- function fnUserMakeParam(rowData){
- let params = []
- rowData.forEach((row, idx) => {
- let msisdnsArray = row.msisdns.value.toString().replace(/ /g, "").split(",") // 공백제거 후, split
- let singleNssaisArray = []
- if (row.singleNssais.value != undefined)
- singleNssaisArray = row.singleNssais.value.toString().replace(/ /g, "").split(",")
- let defaultNssaisArray = row.defaultNssais.value.toString().replace(/ /g, "").split(",")
- let item = {
- accountId: useAuthStore().getAccountId,
- tenantName: row.tenantName.value,
- imsi: row.imsi.value.toString(),
- msisdns: msisdnsArray, //item.msisdns,
- skey: row.skey.value.toString(),
- opc: row.opc.value.toString(),
- singleNssais: singleNssaisArray, //item.singleNssais,
- defaultNssais: defaultNssaisArray, //item.defaultNssais,
- uplink: row.uplink.value,
- downlink: row.downlink.value,
- dnnConf: row.dnnConf
- }
- params.push(item)
- })
- return params
- }
- /**
- * 사업자명 체크
- */
- function fnBusinessNameChk(row, key){
- const userPriority = useAuthStore().getAccountRole
- const userBusinessInfo = useAuthStore().getAuth.tenantName
- if (userPriority == "ADMIN") {
- // ADMIN 권한인 경우 등록가능, 테넌트 명이 존재하고 나의 테넌트명과 다르면 등록안된다.
- if (userBusinessInfo.length > 0 && userBusinessInfo != row[key].value) {
- return 'invalid_tenantName'
- }else{
- return true
- }
- // return true
- }else{
- return 'No permission'
- }
- }
- /**
- * 업다운링크 체크
- */
- function fnLinkValidChk(row, key){
- let linkRegex = /^\d+(\.\d+)? (bps|Kbps|Mbps|Gbps|Tbps)$/
- return linkRegex.test(row[key].value) ? true : 'Invalid link'
- }
- // 현재 업로드한 엑셀파일 데이터에서 imsi값 중복체크
- function fnImsiDupChk(row, key, imsiList ){
- const imsiValue = row[key].value.toString()
- return imsiList.indexOf(imsiValue) !== imsiList.lastIndexOf(imsiValue) ? 'Duplicate IMSI' : true
- }
- /**
- * imsi체크
- * key = 'imsi'
- */
- function fnImsiChk(row, key){
- let imsiPrefix = row[key].value.toString().substr(0, 8) // 엑셀에 입력한 imsi값 앞에서 8자리 가져온다
- let notMatchFlag = false
- props.imsiPrefixList.some((element) => {
- if (element.key == row.tenantName.value) {
- // imsiPrefix의 테넌트명과 엑셀에 입력된 테넌트명이 같은 경우
- if (imsiPrefix == element.value) {
- // 입력한 고정imsi값이 imsiPrefix값과 같은 경우
- notMatchFlag = false
- }
- return true
- }
- })
- return notMatchFlag ? 'Invalid_imsi' : true
- }
- function fnMsisdnsChk(row, key){
- const regex = /(msisdn-\d{5,15}|extid-.+@.+|.+)/
- const items = row[key].value.split(',').map(item => item.trim())
- for (const item of items) {
- if (!regex.test(item)) {
- return `Invalid entry found: "${item}"`
- }
- }
- return true
- }
- /**
- * dnnConfig 유효성 검사
- */
- const validDnnConf = ref([])
- const dnnConfigCnt = ref(0)
- function fnDnnValidation(row){
- const pairs = [
- { key1: 'dnnConf_1_nssai', key2: 'dnnConf_1_dnn' },
- { key1: 'dnnConf_2_nssai', key2: 'dnnConf_2_dnn' },
- { key1: 'dnnConf_3_nssai', key2: 'dnnConf_3_dnn' },
- { key1: 'dnnConf_4_nssai', key2: 'dnnConf_4_dnn' },
- { key1: 'dnnConf_5_nssai', key2: 'dnnConf_5_dnn' },
- { key1: 'dnnConf_6_nssai', key2: 'dnnConf_6_dnn' },
- { key1: 'dnnConf_7_nssai', key2: 'dnnConf_7_dnn' },
- { key1: 'dnnConf_8_nssai', key2: 'dnnConf_8_dnn' },
- { key1: 'dnnConf_9_nssai', key2: 'dnnConf_9_dnn' },
- { key1: 'dnnConf_10_nssai', key2: 'dnnConf_10_dnn' },
- ]
- pairs.forEach((item, idx) => {
- if (!useUtil.isNull(row[item.key1].value) && !useUtil.isNull(row[item.key2].value)) {
- validDnnConf.value[dnnConfigCnt.value++] = {
- nssai: row[item.key1].value.toString(),
- dnn: row[item.key2].value.toString(),
- }
- }
- })
- if (dnnConfigCnt.value < 1) {
- return 'one NSSAI-DNN pair required'
- }else{
- row.dnnConf=_cloneDeep(validDnnConf.value)
- }
- return true
- }
- /**
- * ne일괄등록 param목록
- */
- function fnNeMakeParam(rowData){
- let params = []
- rowData.forEach((row, idx) => {
- let item = {
- accountId: useAuthStore().getAccountId,
- accountName: useAuthStore().getAccountName,
- tenantName: row['Tenant Name'].value,
- neGroup: row['NE Group Name'].value,
- neName: row['NE Name'].value,
- neId: row['NE ID'].value,
- neType: row['NE Type'].value,
- upfNum: row['Connected UPF'].value,
- emsName: row['EMS Name'].value,
- neAddress: row['NE Address'].value,
- neLocLatitude: row['NE Location (Latitude)'].value,
- neLocLongitude: row['NE Location (Longitude)'].value,
- description: row['Description'].value
- }
- params.push(item)
- })
- return params
- }
- /**
- * ne일괄등록 유효성 검사
- */
- function neValidateData(headers, rowData){
- let invalidData = []
- const requiredFields = ['NE Name', 'Tenant Name', 'NE Group Name', 'NE Type', 'NE ID', 'Connected UPF', 'EMS Name', 'NE Address', 'NE Location (Latitude)', 'NE Location (Longitude)', 'Description']
- // flatMap으로 평탄화 작업
- let num = 0
- invalidData = rowData.flatMap((item, index) => {
- return Object.entries(item).flatMap(([key, { value, cell }]) => {
- // 필수 값 체크
- if(!requiredFields.includes(key)){
- // 양식에 맞지 않는 키값
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: '형식에러' };
- }
- if (requiredFields.includes(key) && useUtil.isNull(value)) {
- // 키는 존재하나 데이터가 없는 경우
- return { no: ++num, ROW_NUM: index + 2, headerName: key, value, cellNum: cell, errorMsg: '형식에러' };
- }
- return [];
- })
- })
- return invalidData
- }
- /**
- * 업로드 요청하기 - 각 부모컴포넌트로 이벤트 전달
- */
- function fnUploadProc(){
- emit('uploadProc', uploadParams.value)
- }
- function fnClearFile(e){
- //
- fnInit()
- isExcel.value = false
- setTimeout(() => {
- gridApi.value.showNoRowsOverlay();
- }, 1);
- }
- // Grid 데이터 바인딩
- function fnOnGridReady(params){
- gridApi.value = params.api
- }
- function fnMakeNeJson(){
- let jsonData = {
- '@DU': {
- 'NE ID': [],
- 'NE Type': [],
- 'NE Version': [],
- 'Release Version': [],
- 'Network': [],
- 'NE Name': [],
- 'Administrative State': [],
- 'gNB DU Name': [],
- 'gNB DU Name': [],
- 'Endpoint CU IP address': [],
- 'Local Time Offset': [],
- 'NE Serial Number': [],
- 'FW Auto Fusing': [],
- },
- '@GNB_INFORMATION': {
- 'NE ID': [],
- 'gNB Num': [],
- 'gNB ID': [],
- 'gNB ID Length': [],
- 'Operator Name': [],
- 'Access Mode': [],
- },
- '@GNB_IP_INFORMATION': {
- 'NE ID': [],
- 'gNB Num': [],
- 'IP Index': [],
- 'Local IPv4 Address': [],
- 'Local IPv6 Address': [],
- 'Secondary Local IPv4 Address': [],
- 'Secondary Local IPv6 Address': [],
- },
- '@SERVER_INFORMATION': {
- 'NE ID': [],
- 'CFM': [],
- 'PSM': [],
- 'Local IPv4 Address': [],
- 'Local IPv6 Address': [],
- 'Secondary Local IPv4 Address': [],
- 'Secondary Local IPv6 Address': [],
- },
- '@PLMN_INFORMATION': {
- 'NE ID': [],
- 'gNB Num': [],
- 'PLMN Index': [],
- 'MCC': [],
- 'MNC': [],
- },
- '@MAIN_BOARD_INFORMATION': {
- 'NE ID': [],
- 'Unit Type': [],
- 'Unit ID': [],
- 'Board Type': [],
- },
- '@CLOCK_INFORMATION': {
- 'NE ID': [],
- 'Clock Source ID': [],
- 'Clock Source': [],
- 'Priority Level': [],
- 'Quality Level': [],
- },
- '@PTP_INFORMATION': {
- 'NE ID': [],
- 'IP Version': [],
- 'First Master IP': [],
- 'Second Master IP': [],
- 'Clock Profile': [],
- 'PTP Domain': [],
- 'PTP Hybrid Mode': [],
- },
- '@DEBUG_PORT_INFORMATION': {
- 'NE ID': [],
- 'Port Switch': [],
- },
- '@PORT_INFORMATION': {
- 'NE ID': [],
- 'Port ID': [],
- 'VR ID': [],
- 'Port Administrative State': [],
- 'Connect Type': [],
- 'UDE Type': [],
- 'MTU': [],
- 'Speed Duplex': [],
- 'Fec Mode': [],
- },
- '@VIRTUAL_ROUTING_INFORMATION': {
- 'NE ID': [],
- 'VR ID': [],
- },
- '@IP_INFORMATION': {
- 'NE ID': [],
- 'CPU ID': [],
- 'External Interface Name': [],
- 'IP Address': [],
- 'IP Get Type': [],
- 'Management': [],
- 'Control': [],
- 'Bearer': [],
- 'IEEE1588': [],
- },
- '@VLAN_INFORMATION': {
- 'NE ID': [],
- 'CPU ID': [],
- 'VLAN Interface Name': [],
- 'VLAN ID': [],
- 'VR ID': [],
- },
- '@LAG_INFORMATION': {
- 'NE ID': [],
- 'CPU ID': [],
- 'LAG ID': [],
- 'VR ID': [],
- 'LAG Interface Name': [],
- },
- '@ROUTE_INFORMATION': {
- 'NE ID': [],
- 'CPU ID': [],
- 'VR ID': [],
- 'IP Prefix': [],
- 'IP Prefix Length': [],
- 'IP Gateway': [],
- 'Route Interface Name': [],
- },
- '@SYSTEM_LOCATION_INFORMATION': {
- 'NE ID': [],
- 'User Defined Mode': [],
- 'Latitude': [],
- 'Longitude': [],
- 'Height': [],
- },
- '@RU_INFORMATION': {
- 'NE ID': [],
- 'Start Frequency': [],
- 'Second Start Frequency': [],
- 'Uncertainty Semi Major': [],
- 'Uncertainty Semi Minor': [],
- 'Orientation Of Majjor Axis': [],
- 'Uncertainty Altitude': [],
- 'Confidence': []
- },
- '@IPSEC_INFORMATION': {
- 'NE ID': [],
- 'CPU ID': [],
- 'VR ID': [],
- 'Interface Name1': [],
- 'Peer IP Version': [],
- 'First Peer IP': [],
- 'Second Peer IP': [],
- 'Inner IP Version': [],
- 'Tunnel Mode': [],
- 'Interface Name2': [],
- 'Interface Name3': [],
- 'Interface Name4': [],
- 'Interface Name5': [],
- 'Interface Name6': [],
- 'Crypto Algorithm': [],
- 'Hash Algorithm': [],
- 'Local ID Type': [],
- 'Local ID': [],
- },
- '@PKI_INFORMATION': {
- 'NE ID': [],
- 'CPU ID': [],
- 'IP Address': [],
- 'FQDN': [],
- 'Port': [],
- 'Path': [],
- 'DN': [],
- 'DN Domain': [],
- 'CA DN': [],
- 'Hash Algorithm': [],
- },
- }
- return JSON.stringify(jsonData)
- }
- </script>
|