layout01User.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <template>
  2. <div>
  3. <div :class="widgetSize === 'M' ? 'user--list--wrap user--list--bar--graph' : 'user--list--bar--graph'">
  4. <!-- 헤더 영역 : S -->
  5. <div class="inner--header--wrap">
  6. <h2 class="inner--component--title none--after">
  7. 가입자
  8. </h2>
  9. <pagination
  10. :page-obj="pageObj"
  11. @chg_page="fnChgPage"
  12. >
  13. <template
  14. v-if="userItems && userItems.length > 0"
  15. #rightArea
  16. >
  17. <div class="btn--list--content">
  18. <v-btn
  19. class="custom-btn mini all--view--btn"
  20. @click="fnUserTotalClick"
  21. >
  22. <i class="icon" />전체보기
  23. </v-btn>
  24. </div>
  25. <div class="shape--selector">
  26. <v-btn
  27. class="custom-btn mini card--type--btn"
  28. :class="{ on: showType === 'CARD' }"
  29. @click="fnChangeShowType('CARD')"
  30. />
  31. <v-btn
  32. class="custom-btn mini list--type--btn"
  33. :class="{ on: showType === 'TABLE' }"
  34. @click="fnChangeShowType('TABLE')"
  35. />
  36. </div>
  37. </template>
  38. </pagination>
  39. </div>
  40. <!-- 헤더 영역 : E -->
  41. <!-- Contents 영역 : S -->
  42. <div class="user--list--contents">
  43. <WidgetM
  44. v-if="showType === 'CARD' && widgetSize === 'M'"
  45. :items="userItems"
  46. />
  47. <WidgetS
  48. v-if="showType === 'CARD' && widgetSize === 'S'"
  49. :items="userItems"
  50. />
  51. <WidgetT
  52. v-if="showType === 'TABLE'"
  53. :items="userItems"
  54. :page-obj="pageObj"
  55. />
  56. </div>
  57. <!-- Contents 영역 : E -->
  58. </div>
  59. </div>
  60. </template>
  61. <script setup>
  62. /***********************
  63. * import
  64. ************************/
  65. import { useI18n } from "vue-i18n"
  66. import apiUrl from '@/composables/useApi';
  67. import useAxios from '@/composables/useAxios';
  68. import useUtil from '@/composables/useUtil';
  69. import pagination from "@/components/home/dashboard/common/pagination.vue"
  70. import WidgetM from "@/components/home/dashboard/layout01/user/layout01UserWidgetM.vue"
  71. import WidgetS from "@/components/home/dashboard/layout01/user/layout01UserWidgetS.vue"
  72. import WidgetT from "@/components/home/dashboard/layout01/user/layout01UserWidgetT.vue"
  73. import testJson from "../../test.json"
  74. /***********************
  75. * plugins inject
  76. ************************/
  77. const { $toast, $log, $dayjs, $eventBus } = useNuxtApp()
  78. // props
  79. const props = defineProps({
  80. config: {
  81. type: Object,
  82. default: () => {}
  83. },
  84. intervalTime: {
  85. type: Number,
  86. default: 5000
  87. }
  88. })
  89. // 참조가능 데이터 설정
  90. defineExpose({})
  91. // 발신 이벤트 선언
  92. const emit = defineEmits([""]);
  93. const i18n = useI18n();
  94. /***********************
  95. * data & created
  96. ************************/
  97. // 카드 / 리스트 구분
  98. const showType = ref('CARD'); // CARD or TABLE
  99. // TenantName
  100. const tenantName = computed(() => useAuthStore().getTenantName);
  101. // 설정된 위젯 사이즈 : M or S
  102. const widgetSize = computed(() => props.config?.widgetSize || 'M');
  103. // 위젯 사이즈별 표시 갯수
  104. const widgetListLimit = ref({
  105. S: 16, M: 8, T: 10,
  106. });
  107. // 페이징 정보
  108. const pageObj = ref( {
  109. page: 1, // 현재 페이지
  110. pageSize: widgetListLimit.value[widgetSize.value], // 테이블 조회 데이터 개수
  111. totalCnt: 0, // 전체 페이지
  112. })
  113. // 가입자 리스트
  114. const userItems = ref([]);
  115. /***********************
  116. * Methods
  117. ************************/
  118. const fnReset = () => {
  119. userItems.value = [];
  120. showType.value = 'CARD';
  121. pageObj.value.page = 1;
  122. pageObj.value.pageSize = widgetListLimit.value[widgetSize.value];
  123. pageObj.value.totalCnt = 0;
  124. }
  125. function fnGetUserList() {
  126. const params = {
  127. tenantName: tenantName.value,
  128. }
  129. useAxios().post(apiUrl.getUserList, params).then((res) => {
  130. const {resCode, resMsg, data} = res.data;
  131. if(resCode == 200) {
  132. // 테스트를 위한 테스트 코드 (삭제 필수)
  133. // fnParseData([...(data?.items || []), ...testJson.user.data.items])
  134. fnParseData(data.items || [])
  135. $log.debug("[dashboard][fnGetUserList][success]")
  136. } else {
  137. $log.debug("[dashboard][fnGetUserList][error]", `[${resCode}] ${resMsg}`);
  138. }
  139. }).catch((error)=>{
  140. // 테스트를 위한 테스트 코드 (삭제 필수)
  141. // fnParseData([...testJson.user.data.items])
  142. $log.debug("[dashboard][fnGetUserList][error]", error)
  143. useErrorHandler().fnSetCommErrorHandle(error, fnGetUserList)
  144. // 테스트 데이터 파싱
  145. }).finally(()=>{
  146. $log.debug("[dashboard][fnGetUserList][finished]")
  147. })
  148. }
  149. /**
  150. * 데이터 가공
  151. */
  152. function fnParseData(items = []) {
  153. userItems.value = [];
  154. if(!items || items.length < 1) {
  155. pageObj.value.totalCnt = 0;
  156. return;
  157. }
  158. let temp = [];
  159. // 정렬 적용
  160. temp = items.sort((a, b) => {
  161. const perA = fnGetPercentValue(a.maxSubscriber, a.curSubscriber);
  162. const perB = fnGetPercentValue(b.maxSubscriber, b.curSubscriber);
  163. return +perA < +perB ? 1 : (+perA > +perB ? -1 : 0);
  164. })
  165. // 페이징 적용
  166. pageObj.value.totalCnt = temp.length;
  167. temp = temp.filter((data, index) =>(index >= ((pageObj.value.page - 1) * pageObj.value.pageSize) && index < (pageObj.value.page * pageObj.value.pageSize)));
  168. // 데이터 가공
  169. userItems.value = temp.map((item, index) => {
  170. //percent
  171. const { maxSubscriber, curSubscriber } = item;
  172. const perSubscriber = fnGetPercentValue(maxSubscriber, curSubscriber);
  173. //심각도
  174. const level = fnGetLevel(perSubscriber);
  175. //차트 데이터
  176. const chartData = {
  177. datasets: [
  178. {
  179. data: [curSubscriber , maxSubscriber - curSubscriber],
  180. backgroundColor: fnGetChartColorSet(level),
  181. borderWidth: 0,
  182. }
  183. ]
  184. }
  185. //테이블 사용량 class
  186. const tablePercentClass = fnGetTablePercentClass(perSubscriber);
  187. return {
  188. ...item,
  189. no: index+1,
  190. level,
  191. perSubscriber,
  192. chartData,
  193. tablePercentClass
  194. }
  195. })
  196. }
  197. /** make percent data */
  198. const fnGetPercentValue = (max, curr) => {
  199. return useUtil.toRoundFix((curr / max) * 100, 0);
  200. }
  201. const fnGetLevel = (per) => {
  202. if(per >= 95) return 'critical'; //critical
  203. else if(per >= 90) return 'major'; //major
  204. else if(per >= 85) return 'minor'; //minor
  205. else return 'normal'; //normal
  206. }
  207. /** 차트 데이터 > 컬러셋 */
  208. const fnGetChartColorSet = (level) => {
  209. if(level == 'critical') return ['#f00','#EAEAEA']; //critical
  210. else if(level == 'major') return ['#C96103','#EAEAEA']; //major
  211. else if(level == 'minor') return ['#DDA405','#EAEAEA']; //minor
  212. else return ['#2D8CFA','#EAEAEA']; //normal
  213. }
  214. /** 테이블 > 사용량 class */
  215. const fnGetTablePercentClass = (level) => {
  216. if(level == 'critical') return 'user--list--critical'; //critical
  217. else if(level == 'major') return 'user--list--major'; //major
  218. else if(level == 'minor') return 'user--list--minor'; //minor
  219. else return 'user--list--normal';
  220. }
  221. /** 카드형/목록형 Change Event */
  222. function fnChangeShowType(type) {
  223. pageObj.value.page = 1;
  224. pageObj.value.totalCnt = 0;
  225. if(type === 'TABLE') pageObj.value.pageSize = widgetListLimit.value.T;
  226. else pageObj.value.pageSize = widgetListLimit.value[widgetSize.value];
  227. fnGetUserList();
  228. showType.value = type;
  229. }
  230. /** 전체보기 open */
  231. function fnUserTotalClick() {
  232. const url = window.location.origin+'/view/home/user'
  233. const popupWindow = window.open(url, '_blank', 'width=' + screen.width + ',height=' + screen.height + ',fullscreen=yes')
  234. if (popupWindow) {
  235. popupWindow.focus()
  236. }
  237. }
  238. /**
  239. * 페이지 변경
  240. */
  241. function fnChgPage(page){
  242. pageObj.value.page = page
  243. fnGetUserList();
  244. }
  245. onMounted(() => fnGetUserList())
  246. // 위젯사이즈 변경 watch
  247. watch(() => widgetSize.value, () => {
  248. fnReset();
  249. fnGetUserList();
  250. }, {deep: true})
  251. </script>