layout01Core.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <template>
  2. <div
  3. class="core--component--wrap"
  4. :class="widgetSize === 'S' ? 'small' : ''"
  5. >
  6. <div class="inner--header--wrap">
  7. <h2 class="inner--component--title none--after">
  8. CORE
  9. </h2>
  10. <pagination
  11. :page-obj="pageObj"
  12. @chg_page="fnChgPage"
  13. >
  14. <template #rightArea>
  15. <div class="search--box">
  16. <v-select
  17. v-model="objSltSearch.neType"
  18. :items="objSlt.neTypeList"
  19. variant="outlined"
  20. style="width:9.0625rem;"
  21. class="custom-select"
  22. />
  23. <v-select
  24. v-model="objSltSearch.customerType"
  25. :items="objSlt.customerTypeList"
  26. variant="outlined"
  27. style="width:9.0625rem;"
  28. class="custom-select"
  29. />
  30. <v-btn
  31. class="custom-btn mini sort-btn"
  32. flat
  33. @click="isSortShow ? isSortShow = false : isSortShow = true"
  34. />
  35. <div
  36. v-if="isSortShow == true"
  37. class="sort--atv"
  38. >
  39. <ul>
  40. <li
  41. v-for="(sort, index) in objSlt.sortTypeList"
  42. :key="`sort-option-${index}`"
  43. :class="{atv: objSltSearch.sortType == sort.value}"
  44. @click="fnOnclickSortType(sort.value)"
  45. >
  46. {{ sort.title }}
  47. </li>
  48. </ul>
  49. </div>
  50. </div>
  51. </template>
  52. </pagination>
  53. </div>
  54. <!-- 위젯 영역 -->
  55. <WidgetM
  56. v-if="widgetSize === 'M'"
  57. :items="coreItems"
  58. @more="fnCoreDetailClick"
  59. />
  60. <WidgetS
  61. v-if="widgetSize === 'S'"
  62. :items="coreItems"
  63. @more="fnCoreDetailClick"
  64. />
  65. <!-- 코어 상세보기 Modal -->
  66. <CoreDetailModal
  67. ref="refCoreDetailModal"
  68. :is-core-detail-modal="isCoreDetailModal"
  69. @close-modal="fnCloseCoreDetailModal"
  70. />
  71. </div>
  72. </template>
  73. <script setup>
  74. /***********************
  75. * import
  76. ************************/
  77. import { useI18n } from "vue-i18n"
  78. import apiUrl from '@/composables/useApi';
  79. import useAxios from '@/composables/useAxios';
  80. import useUtil from '@/composables/useUtil';
  81. import CoreDetailModal from "@/components/home/dashboard/common/coreDetailModal.vue"
  82. import WidgetM from "@/components/home/dashboard/layout01/core/layout01CoreWidgetM.vue"
  83. import WidgetS from "@/components/home/dashboard/layout01/core/layout01CoreWidgetS.vue"
  84. import pagination from "@/components/home/dashboard/common/pagination.vue"
  85. import testJson from "../../test.json"
  86. /***********************
  87. * plugins inject
  88. ************************/
  89. const { $toast, $log, $dayjs, $eventBus } = useNuxtApp()
  90. // props
  91. const props = defineProps({
  92. config: {
  93. type: Object,
  94. default: () => {}
  95. },
  96. intervalTime: {
  97. type: Number,
  98. default: 5000
  99. }
  100. })
  101. // 참조가능 데이터 설정
  102. defineExpose({})
  103. // 발신 이벤트 선언
  104. const emit = defineEmits([""]);
  105. const i18n = useI18n();
  106. /***********************
  107. * data & created
  108. ************************/
  109. // 코어 상세보기 모달
  110. const refCoreDetailModal = ref(null);
  111. const isCoreDetailModal = ref(false);
  112. // TenantName
  113. const tenantName = computed(() => useAuthStore().getTenantName);
  114. // 설정된 위젯 사이즈 : M or S
  115. const widgetSize = computed(() => props.config?.widgetSize || 'M');
  116. // 위젯 사이즈별 표시 갯수
  117. const widgetListLimit = ref({
  118. S: 9, M: 6
  119. });
  120. // 페이징 정보
  121. const pageObj = ref( {
  122. page: 1, // 현재 페이지
  123. pageSize: widgetListLimit.value[widgetSize.value], // 테이블 조회 데이터 개수
  124. totalCnt: 0, // 전체 페이지
  125. })
  126. const objSltSearch = ref({
  127. neType: '',
  128. customerType: '',
  129. sortType: 0,
  130. })
  131. // 검색조건
  132. const objSlt = ref({
  133. neTypeList: [],
  134. customerTypeList: [],
  135. sortTypeList: [
  136. {title: '위험도순', value: 0},
  137. {title: '이름순(오름차순)', value: 1},
  138. {title: '이름순(내림차순)', value: 2}
  139. ],
  140. })
  141. // 코어 리스트
  142. const coreItems = ref([]);
  143. // 정렬 옵션 open 여부
  144. const isSortShow = ref(false);
  145. /***********************
  146. * Methods
  147. ************************/
  148. /**
  149. * 리셋
  150. */
  151. const fnReset = () => {
  152. objSltSearch.value.neType = '';
  153. objSltSearch.value.customerType = '';
  154. objSltSearch.value.sortType = '';
  155. pageObj.value.page = 1;
  156. pageObj.value.pageSize = widgetListLimit.value[widgetSize.value];
  157. pageObj.value.totalCnt = 0;
  158. }
  159. /**
  160. * 코어 리스트 조회
  161. */
  162. function fnGetCoreList() {
  163. const params = {
  164. tenantName: tenantName.value,
  165. }
  166. useAxios().post(apiUrl.getCoreInfoList, params).then((res) => {
  167. const {resCode, resMsg, data} = res.data;
  168. if(resCode == 200) {
  169. // 테스트를 위한 테스트 코드 (삭제 필수)
  170. // fnParseData([...(data?.items || []), ...testJson.core.data.items])
  171. fnParseData(data.items || [])
  172. $log.debug("[dashboard][fnGetCoreList][success]")
  173. } else {
  174. $log.debug("[dashboard][fnGetCoreList][error]", `[${resCode}] ${resMsg}`);
  175. }
  176. }).catch((error)=>{
  177. // 테스트를 위한 테스트 코드 (삭제 필수)
  178. // fnParseData([...testJson.core.data.items])
  179. $log.debug("[dashboard][fnGetCoreList][error]", error)
  180. useErrorHandler().fnSetCommErrorHandle(error, fnGetCoreList)
  181. }).finally(()=>{
  182. $log.debug("[dashboard][fnGetCoreList][finished]")
  183. })
  184. }
  185. /**
  186. * 데이터 가공
  187. */
  188. function fnParseData(items = []) {
  189. // {neType: 'AMF', neName: 'neName1', emsStatus: 0, mcmStatus: 0, psmStatus: 0, criCnt: 3,majCnt: 1, minCnt: 1,customerType: 1,CPU: {AVG_CPU_L: 14,PEAK_CPU_L: 15, }, MEM: {AVG_MEM_L: 6,PEAK_MEM_L: 95,}},
  190. // {id: 14, customerType: '1', level: 'MINOR', isDisconnect: false, neType: 'AMF', status: 'ACTIVE', cpu: Math.random() * 100, memory: Math.random() * 100, disk: Math.random() * 100},
  191. coreItems.value = [];
  192. if(!items || items.length < 1) {
  193. pageObj.value.totalCnt = 0;
  194. return;
  195. }
  196. let temp = [];
  197. // 검색 조건 적용
  198. const { neType, customerType} = objSltSearch.value;
  199. temp = items.filter((data) => (useUtil.isNull(neType) || neType == data.neType) && (useUtil.isNull(customerType) || customerType == data.customerType));
  200. // 정렬 조건 적용
  201. const { sortType } = objSltSearch.value;
  202. temp = temp.sort((a, b) => {
  203. // 위험도순
  204. if(sortType == 0) {
  205. return a.criCnt < b.criCnt ? 1 : a.criCnt > b.criCnt ? -1 : (a.majCnt < b.majCnt ? 1 : a.majCnt > b.majCnt ? -1 : (a.minCnt < b.minCnt ? 1 : a.minCnt > b.minCnt ? -1 : 0));
  206. }
  207. //이름순 오름차순
  208. else if(sortType == 1) {
  209. return a.neName < b.neName ? -1 : a.neName > b.neName ? 1 : 0;
  210. }
  211. //이름순 내림차순
  212. else if(sortType == 2) {
  213. return a.neName > b.neName ? -1 : a.neName < b.neName ? 1 : 0;
  214. }
  215. })
  216. // 페이징 적용
  217. pageObj.value.totalCnt = temp.length;
  218. temp = temp.filter((data, index) =>(index >= ((pageObj.value.page - 1) * pageObj.value.pageSize) && index < (pageObj.value.page * pageObj.value.pageSize)));
  219. // 데이터 가공
  220. coreItems.value = temp.map((item) => {
  221. // KPI 정보 셋팅 - TODO: CPU, MEM 외의 값이 추가되면 여기에 추가
  222. const { cpu, mem } = item;
  223. const kpiItems = [];
  224. if(cpu) {
  225. const objCpu = typeof cpu === 'string' ? JSON.parse(cpu) : cpu;
  226. if(objCpu && objCpu[`AVG_CPU_L(%)`]){
  227. kpiItems.push({label: 'CPU', val: objCpu[`AVG_CPU_L(%)`] || 0})
  228. item.cpu = objCpu;
  229. }
  230. }
  231. if(mem) {
  232. const objMem = typeof mem === 'string' ? JSON.parse(mem) : mem ;
  233. if(objMem && objMem['AVG_MEM_L(%)']){
  234. kpiItems.push({label: 'MEMORY', val: objMem['AVG_MEM_L(%)'] || 0})
  235. item.mem = objMem;
  236. }
  237. }
  238. //고객 유형명 셋팅
  239. const { customerType } = item;
  240. let customerTypeName = '';
  241. if(customerType) {
  242. const type = objSlt.value.customerTypeList.find((t) => t.value == customerType)
  243. if(type) customerTypeName = type.title;
  244. }
  245. // disconected 셋팅
  246. const { emsStatus, mcmStatus, psmStatus } = item;
  247. const connect = {
  248. isConnected: false,
  249. reason: [],
  250. }
  251. if([emsStatus, mcmStatus, psmStatus].every((status) => status == 0)) {
  252. connect.isConnected = true;
  253. } else {
  254. connect.isConnected = false;
  255. if(emsStatus != 0 ) connect.reason.push(`emsSatats: ${emsStatus}`);
  256. if(mcmStatus != 0 ) connect.reason.push(`mcmStatus: ${mcmStatus}`);
  257. if(psmStatus != 0 ) connect.reason.push(`psmStatus: ${psmStatus}`);
  258. }
  259. // 심각도 level 셋팅
  260. const { criCnt ,majCnt, minCnt } = item;
  261. let level = '';
  262. if(criCnt > 0) level = 'CRITICAL';
  263. else if(majCnt > 0) level = 'MAJOR';
  264. else if(minCnt > 0) level = 'MINOR';
  265. return {
  266. ...item,
  267. kpiItems, // kpi 정보
  268. customerTypeName, // 고객유형명
  269. connect, // 연결 상태
  270. level, // 심각도 레벨
  271. }
  272. });
  273. console.log('::::::: coreItems : ' ,coreItems.value)
  274. }
  275. /**
  276. * 페이지 변경
  277. */
  278. function fnChgPage(page){
  279. pageObj.value.page = page;
  280. fnGetCoreList();
  281. // gridApi.value.paginationGoToPage(page-1)
  282. }
  283. /** 코어 상세보기 open */
  284. function fnCoreDetailClick(item) {
  285. isCoreDetailModal.value = true
  286. refCoreDetailModal.value.fnInit(item)
  287. }
  288. /** 코어 상세보기 Close */
  289. function fnCloseCoreDetailModal() {
  290. isCoreDetailModal.value = false
  291. }
  292. /** 검색조건 > 정렬 변경 */
  293. function fnOnclickSortType(type) {
  294. objSltSearch.value.sortType = type;
  295. isSortShow.value = false;
  296. }
  297. /**
  298. * ENUM 업데이트
  299. * @param lang
  300. */
  301. function fnGetEnumCode(lang){
  302. lang = useUtil.nvl(lang, 'kr')
  303. const objEnum = useEnumCode.getEnumCode(lang)
  304. objSlt.value.neTypeList = [{title: i18n.t('common.all'), value: ''},...objEnum.neType]
  305. objSlt.value.customerTypeList = [{title: i18n.t('common.all'), value: ''},...objEnum.customerType]
  306. }
  307. onMounted(() => fnGetCoreList())
  308. watchEffect(() => fnGetEnumCode(useLangStore().getLang))
  309. // 검색 조건 변경 watch
  310. watch(() => objSltSearch.value, () => {
  311. pageObj.value.page = 1;
  312. fnGetCoreList();
  313. }, {deep: true})
  314. // 위젯사이즈 변경 watch
  315. watch(() => widgetSize.value, () => {
  316. fnReset();
  317. fnGetCoreList();
  318. }, {deep: true})
  319. </script>