useUtil.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. import dayjs from 'dayjs';
  2. import { utils, writeFile } from "xlsx";
  3. import * as XLSX from 'xlsx-js-style/dist/xlsx.bundle.js';
  4. /*
  5. * Harmory 3.0 Util Plugin
  6. * Version : 1.0
  7. * Make By Jason 2022
  8. */
  9. let util = {
  10. /**
  11. * @TODO 함수설명 필요
  12. **/
  13. toStr(str){
  14. return str + ''
  15. },
  16. /**
  17. * @TODO 함수설명 필요
  18. **/
  19. nvl(str, restr){
  20. if (str === '' || str === null || typeof(str) === 'undefined' || str === 'undefined' || str === 'null'){
  21. if (restr === ''){
  22. return ''
  23. } else {
  24. return restr
  25. }
  26. }else{
  27. return str
  28. }
  29. },
  30. /**
  31. * @TODO 함수설명 필요
  32. */
  33. isNull(str){
  34. if ( str === '' || str === null || str === undefined || typeof(str) === 'undefined' || str ==='undefined' || str ==='null'){
  35. return true
  36. }else{
  37. return false
  38. }
  39. },
  40. /**
  41. * @TODO 함수설명 필요
  42. * 로깅처리 하는 글로벌 Util
  43. * LOGGING =='YES' 일때만 처리함
  44. **/
  45. log(msg, level){
  46. console.log(level+'|', msg)
  47. },
  48. colorLog(msg){
  49. // console.log("%c"+dayjs().format('YYYY-MM-DD HH:mm:ss')+" "+msg, 'color:#02f7eb')
  50. },
  51. /**
  52. * @TODO 좌우 Trim
  53. **/
  54. trim(data){
  55. return data.replace(/^\s+|\s+$/g, '')
  56. },
  57. /**
  58. * @TODO 왼쪽으로 Trim
  59. **/
  60. ltrim(data){
  61. return data.replace(/^\s+/, '')
  62. },
  63. /**
  64. * @TODO 오른쪽으로 trim
  65. **/
  66. rtrim(data){
  67. return data.replace(/\s+$/, '')
  68. },
  69. /**
  70. * @TODO 소수점 자리숫를 파싱한다.
  71. **/
  72. toRoundFix(data, digit){
  73. if(Number.isInteger(parseFloat(data))){
  74. return parseFloat(data)
  75. } else {
  76. return parseFloat(data).toFixed(digit)
  77. }
  78. },
  79. fillZero(number, width){
  80. width -= number.toString().length
  81. if ( width > 0 ){
  82. return new Array( width + (/\./.test( number ) ? 2 : 1) ).join( '0' ) + number
  83. }
  84. return number + '' // always return a strin
  85. },
  86. hex2Float(number, underDigit){
  87. let sNum = ''
  88. let num = parseInt(number, 16)
  89. sNum += parseFloat(num/100).toFixed(underDigit)
  90. return sNum
  91. },
  92. decimalToHex(d, padding){
  93. let hex = Number(d).toString(16)
  94. padding = typeof (padding) === 'undefined' || padding === null ? padding = 2 : padding
  95. while (hex.length < padding){
  96. hex = '0' + hex
  97. }
  98. return hex.toUpperCase()
  99. },
  100. left(str, n){
  101. if (n <= 0){
  102. return ''
  103. }else if (n > String(str).length){
  104. return str
  105. }else{
  106. return String(str).substring(0, n)
  107. }
  108. },
  109. right(str, n){
  110. if (n <= 0){
  111. return ''
  112. }else if (n > String(str).length){
  113. return str
  114. }else{
  115. let iLen = String(str).length
  116. return String(str).substring(iLen, iLen - n)
  117. }
  118. },
  119. convert12Hour(hour){
  120. return ''+util.fillZero((parseInt(hour, 10) + 24) % 12 || 12, 2)
  121. },
  122. getStrLength(str){
  123. let strLength = 0
  124. let i
  125. for (i = 0; i < str.length; i++){
  126. let code = str.charCodeAt(i)
  127. let ch = str.substr(i, 1).toUpperCase()
  128. code = parseInt(code)
  129. if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') && ((code > 255) || (code < 0)))
  130. strLength = strLength + 2
  131. else
  132. strLength = strLength + 1
  133. }
  134. return strLength
  135. },
  136. str2Hex(instr){
  137. let str = ''+instr
  138. let hex = ''
  139. for(let i = 0; i<str.length; i++){
  140. hex += '' + str.charCodeAt(i).toString(16)
  141. }
  142. return hex
  143. },
  144. getTextCutByte(obj, len){
  145. let str = $(obj).val()
  146. let str_len = str.length
  147. let bytes = 0
  148. let result = true
  149. for(let i=0; i<str.length; i++){
  150. let ch = str.charAt(i)
  151. if(escape(ch).length > 4){
  152. bytes += 2
  153. }else if(ch === '\n'){
  154. if(str.charAt(i-1) != '\r'){
  155. bytes += 1
  156. }
  157. }else if(ch === '<' || ch === '>'){
  158. bytes += 4
  159. }else{
  160. bytes += 1
  161. }
  162. if(bytes > len){
  163. str_len--
  164. $(obj).val(str.substring(0, str_len))
  165. }
  166. }
  167. if(bytes > len){
  168. result = false
  169. }
  170. return result
  171. },
  172. getOS(){
  173. let ua = String( navigator.userAgent ).toLowerCase()
  174. if(/iphone|ipad/.test(ua)){
  175. return 'ios'
  176. }else if(/android/.test(ua)){
  177. return 'android'
  178. }else{
  179. return 'android'
  180. }
  181. },
  182. setComma(num){
  183. let sign = ''
  184. let rnum = String(num)
  185. if(rnum.substring(0, 1) == '-'){
  186. sign = '-'
  187. rnum = rnum.substring(1)
  188. }
  189. let spNum = rnum.split('.')
  190. return sign + spNum[0].replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (spNum[1] ? '.' + spNum[1] : '')
  191. },
  192. setUnComma(num){
  193. num = String(num)
  194. return num.replace(/[^\d]+/g, '')
  195. },
  196. setInputNumberComma(obj){
  197. return util.setComma(util.setUnComma(obj))
  198. },
  199. get24To12(hour){
  200. var _result = 0
  201. var _hour = parseInt(hour, 10)
  202. if(_hour === 0){
  203. _result = 12
  204. }else if(_hour > 12){
  205. _result = _hour - 12
  206. }else{
  207. _result = _hour
  208. }
  209. return _result
  210. },
  211. /**
  212. * @param2 : 0: 오전 / 1: 오후
  213. */
  214. get12To24(hour, ampm){
  215. let _result = 0
  216. let _hour = parseInt(hour, 10)
  217. if(ampm === 0 ){
  218. if(_hour === 12){
  219. _result = 0
  220. }else{
  221. _result = _hour
  222. }
  223. }else if(ampm === 1){
  224. if(_hour != 12){
  225. _result = _hour + 12
  226. }else{
  227. _result = 12
  228. }
  229. }else{
  230. return _hour
  231. }
  232. return _result
  233. },
  234. /**
  235. * 연락처 자동 파이프(-)생성 계산식
  236. * @param {*} data
  237. */
  238. getPhoneMask(data){
  239. if(!util.isNull(data)){
  240. data = data.replace(/[^0-9]/g, '')
  241. let res = ''
  242. if(data.length < 3){
  243. res = data
  244. } else {
  245. if(data.substr(0, 2) =='02'){
  246. if(data.length <= 5){//02-123-5678
  247. res = data.substr(0, 2) + '-' + data.substr(2, 3)
  248. } else if(data.length > 5 && data.length <= 9){//02-123-5678
  249. res = data.substr(0, 2) + '-' + data.substr(2, 3) + '-' + data.substr(5)
  250. } else {//02-1234-5678
  251. data = data.substr(0, 10)
  252. res = data.substr(0, 2) + '-' + data.substr(2, 4) + '-' + data.substr(6)
  253. }
  254. } else {
  255. if(data.length < 8){
  256. res = data
  257. } else if(data.length == 8){
  258. res = data.substr(0, 4) + '-' + data.substr(4)
  259. } else if(data.length == 9){
  260. res = data.substr(0, 3) + '-' + data.substr(3, 3) + '-' + data.substr(6)
  261. } else if(data.length == 10){
  262. res = data.substr(0, 3) + '-' + data.substr(3, 3) + '-' + data.substr(6)
  263. } else if(data.length == 11){ //010-1234-5678
  264. res = data.substr(0, 3) + '-' + data.substr(3, 4) + '-' + data.substr(7)
  265. }else {
  266. data = data.substr(0, 11)
  267. res = data.substr(0, 3) + '-' + data.substr(3, 4) + '-' + data.substr(7)
  268. }
  269. }
  270. }
  271. return res
  272. }else{
  273. return data
  274. }
  275. },
  276. /**
  277. * 사업자 등록번호 파이프(-) 자동입력 :
  278. * ex) 123-45-67890
  279. */
  280. getBisinessMask(data){
  281. if(!data) return data
  282. data = data.replace(/[^0-9]/g, '')
  283. let res = ''
  284. if(data.length < 3){
  285. res = data
  286. } else {
  287. if(data.length <= 5){
  288. res = data.substr(0, 3) + '-' + data.substr(3, 2)
  289. }else if(data.length >= 6){
  290. res = data.substr(0, 3) + '-' + data.substr(3, 2) + '-' + data.substr(5)
  291. }
  292. }
  293. return res
  294. },
  295. replaceAll(str, searchStr, replaceStr){
  296. if(util.nvl(str, '') === ''){
  297. return ''
  298. }
  299. return str.split(searchStr).join(replaceStr)
  300. },
  301. setDragged(obj){
  302. let el = $(obj.el).parent().parent()[0]
  303. if (!$(el).hasClass('laypop_renew')){
  304. el = $(obj.el).parent().parent().parent()[0]
  305. }
  306. el.style.left =obj.offsetX+'px'
  307. el.style.top =obj.offsetY+'px'
  308. },
  309. //Blob형태로 다운로드 할때 사용
  310. downLoadBlob(fileName, blob){
  311. let downloadLink = document.createElement('a')
  312. downloadLink.download = fileName
  313. downloadLink.innerHTML = ''
  314. downloadLink.href = window.URL.createObjectURL(blob)
  315. downloadLink.onclick = function (event){
  316. document.body.removeChild(event.target)
  317. }
  318. downloadLink.style.visibility = 'hidden'
  319. document.body.appendChild(downloadLink)
  320. downloadLink.click()
  321. },
  322. async setPageMove(url){
  323. const { $log } = useNuxtApp()
  324. if(useRoute().path === url) {
  325. $log.debug('현재 경로와 이동하려는 경로가 같다면 새로고침')
  326. window.location.reload()
  327. }else{
  328. useRouter().push(url)
  329. }
  330. },
  331. isMatch(data, clone){
  332. return JSON.stringify(data) === JSON.stringify(clone)
  333. },
  334. /**
  335. * 휴대폰 하이픈 처리
  336. */
  337. getPhoneHyphen(num){
  338. const hyphenNum = num.replace(/[^0-9]/g, "")
  339. let strNum = ''
  340. if(hyphenNum.length >= 4 && hyphenNum.length<=7){
  341. strNum = hyphenNum.replace(/(\d{3})(\d{1,3})/, '$1-$2')
  342. }
  343. else if(hyphenNum.length>=8 && hyphenNum.length <= 11){
  344. strNum = hyphenNum.replace(/(\d{3})(\d{4})(\d{1,4})/, '$1-$2-$3')
  345. }
  346. else{
  347. strNum = hyphenNum.substring(0,11).replace(/(\d{3})(\d{4})(\d{1,4})/, '$1-$2-$3')
  348. strNum = strNum.substring(0,13)
  349. }
  350. return strNum
  351. },
  352. /**
  353. * 객체배열 오름차순 정렬
  354. */
  355. sortAsc(arr, key){
  356. return arr.sort((a,b)=>{
  357. var x = a[key];
  358. var y = b[key];
  359. return((x<y)?-1:((x>y)?1:0));
  360. })
  361. },
  362. /**
  363. * 객체배열 내림차순 정렬
  364. */
  365. sortDesc(arr, key){
  366. return arr.sort((a,b)=>{
  367. var x = a[key];
  368. var y = b[key];
  369. return((x>y)?-1:((x>y)?1:0));
  370. })
  371. },
  372. /**
  373. * 숫자 포맷 세팅
  374. * @param {*} num 변경할 숫자
  375. * @param {*} decimalPlaces 소수점 개수
  376. * @param {*} nonNumberStr 숫자가 아닐경우 표현할 문자
  377. * @param {*} unit 단위
  378. */
  379. fnFormatNumber(num, decimalPlaces = 2, nonNumberStr = 0, unit = '') {
  380. let number = Number(num)
  381. if(isNaN(number) || typeof number !== 'number' || num == null){
  382. return nonNumberStr
  383. }
  384. const hasDecimal = number % 1 !== 0
  385. const fixedNumber = hasDecimal ? parseFloat(number.toFixed(decimalPlaces)) : number
  386. const [integerPart, decimalPart] = fixedNumber.toString().split('.')
  387. const formattedIntegerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
  388. if(decimalPart){
  389. return `${formattedIntegerPart}.${decimalPart}${unit}`
  390. } else {
  391. return `${formattedIntegerPart}${unit}`
  392. }
  393. },
  394. /**
  395. * Excel 다운로드 (클라이언트 데이터 기반)
  396. *
  397. * @param {*} params Excel 생성 설정값
  398. * @param {*} headers 테이블 Header 데이터. format: [{title: '타이틀', key: '데이터Key'}, ....]
  399. * @param {*} tableList 테이블 row 데이터. format: [{ '데이터Key': value, ...}, ....]
  400. * @param {*} firstRow 테이블 최상위에 표시할 테이터 (없으면 표시하지 않음)
  401. * @param {*} specialStyle firstRow, 특정 셀 스타일을 주고 싶을 때
  402. */
  403. fnExcelMergeDownLoad(params, headers, tableList, firstRow, specialStyle){
  404. const { $dayjs } = useNuxtApp()
  405. //excel 파일명
  406. let date = $dayjs(new Date()).format('YYYYMMDD')
  407. let excelTitle = params.title || 'download'
  408. let excelBody = JSON.parse(JSON.stringify(tableList))
  409. let merge = [] // 행, 열 결합
  410. let isFirstRow = !util.isNull(firstRow)
  411. // 헤더 스타일
  412. let headerStyle = {
  413. fill: { fgColor: { rgb: '878fa2' } },
  414. font: { bold: true, color: { rgb: 'fafafa' } },
  415. alignment: { vertical: 'center', horizontal: 'center' }
  416. }
  417. // firstRow가 있으면 table 정보에 첫 Row에 삽입
  418. if(isFirstRow) {
  419. excelBody.unshift(firstRow)
  420. }
  421. //excel 생성 데이터
  422. let excelData = []
  423. excelBody.forEach((item) => {
  424. let obj = {}
  425. headers.forEach((names, namesIdx) => {
  426. let objValue = item[headers[namesIdx].key]
  427. obj[names.title] = (util.isNull(objValue)) ? '': objValue.toString().replace('_NONE', '')
  428. })
  429. excelData.push(obj)
  430. })
  431. // 셀병합 데이터 생성(셀병합의 경우 우선 최상단 헤더에만 존재함)
  432. headers.forEach((names, namesIdx) => {
  433. // rowspan
  434. if(names.hasOwnProperty('rowspan')){
  435. merge.push({ s: { r: 0, c: namesIdx }, e: { r: names.rowspan - 1, c: namesIdx } })
  436. }
  437. // colspan
  438. if(names.hasOwnProperty('colspan')){
  439. merge.push({ s: { r: 0, c: namesIdx }, e: { r: 0, c: namesIdx + names.colspan - 1 } })
  440. }
  441. })
  442. let excelFileName = [date, excelTitle].join('_') + '.xlsx'
  443. let workbook = XLSX.utils.book_new()
  444. let worksheet = XLSX.utils.json_to_sheet(excelData)
  445. // 셀 병합
  446. // merge = [ { s: { r: 1, c: 1 }, e: { r: 2, c: 3 } }; // A1부터 C1까지 병합 ]
  447. const styles = {
  448. '!merges': merge // 병합된 셀에 스타일 적용
  449. }
  450. // 스타일 지정
  451. // 헤더, firstRow 영역 스타일 설정(유니코드 65 => A, 66 => B .... 헤더 cell 스타일 적용)
  452. headers.forEach((header, index) => {
  453. let val = index / 26
  454. let remain = index % 26
  455. let doubleIndex = val >= 1 ? String.fromCharCode(65 + Math.floor(val) - 1) : ''
  456. worksheet[doubleIndex + String.fromCharCode(65 + remain) + '1'].s = headerStyle
  457. if(isFirstRow) worksheet[doubleIndex + String.fromCharCode(65 + remain) + '2'].s = specialStyle.hasOwnProperty('totalRowStyle') ? specialStyle.totalRowStyle : headerStyle
  458. })
  459. // 특정 영역에 셀 스타일 적용
  460. if(specialStyle.hasOwnProperty('cellStyleObj')){
  461. specialStyle.cellStyleObj.target.forEach((cell) => {
  462. worksheet[cell].s = specialStyle.cellStyleObj.cellStyle
  463. })
  464. }
  465. worksheet['!merges'] = styles['!merges']; // 병합 정보 업데이트
  466. XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
  467. XLSX.writeFile(workbook, excelFileName)
  468. return
  469. },
  470. /**
  471. * KREMS > 분석통계 => 그래프&테이블 영역의 파라미터 가공(start_dt, end_dt) 공통 함수
  472. * @param {*} periodKey : UI상 일,주,월,년,기간에 대한 파라미터
  473. * @param {*} start_dt : 시작일
  474. * @param {*} end_dt : 종료일
  475. * @returns
  476. */
  477. statisticsDateFormat(periodKey, start_dt, end_dt) {
  478. let month = 0
  479. let start = ''
  480. let end = ''
  481. if(periodKey === 'day') {
  482. // 일
  483. start = dayjs(start_dt).format('YYYY-MM-DD')
  484. end = dayjs(start_dt).format('YYYY-MM-DD')
  485. } else if(periodKey === 'week') {
  486. // 주
  487. if(dayjs(start_dt).format('dddd') === 'Sunday') {
  488. start = dayjs(start_dt).subtract(6, 'day').format('YYYY-MM-DD')
  489. end = dayjs(start_dt).format('YYYY-MM-DD')
  490. } else {
  491. start = dayjs(start_dt).startOf('week').subtract(-1, 'day').format('YYYY-MM-DD')
  492. end = dayjs(start_dt).endOf('week').subtract(-1, 'day').format('YYYY-MM-DD')
  493. }
  494. } else if(periodKey === 'month') {
  495. //월
  496. if(util.isNull(start_dt.month)) {
  497. // true 일때
  498. start = dayjs(start_dt).startOf('month').format('YYYY-MM-DD')
  499. end = dayjs(start_dt).endOf('month').format('YYYY-MM-DD')
  500. } else {
  501. month = start_dt.month + 1
  502. start = dayjs(start_dt.year+'-'+month).startOf('month').format('YYYY-MM-DD')
  503. end = dayjs(start_dt.year+'-'+month).endOf('month').format('YYYY-MM-DD')
  504. }
  505. } else if(periodKey === 'year') {
  506. start = start_dt+'-01-01'
  507. end = start_dt+'-12-31'
  508. } else if(periodKey === 'period') {
  509. start = dayjs(start_dt).format('YYYY-MM-DD')
  510. end = dayjs(end_dt).format('YYYY-MM-DD')
  511. }
  512. return [start, end]
  513. },
  514. /**
  515. * 엑셀다운로드 공통
  516. * @returns 엑셀파일
  517. * @param {*} params Excel 생성 설정값
  518. * @param {*} headers 테이블 Header 데이터. format: [{heder: '타이틀', dataKey: '데이터Key'}, ....]
  519. * @param {*} tableList 테이블 row 데이터. format: [{ '데이터Key': value, ...}, ....]
  520. * @param {*} firstRow 테이블 최상위에 표시할 테이터 (없으면 표시하지 않음)
  521. */
  522. fnExcelDownLoad(params, headers, tableList, firstRow){
  523. let date = dayjs(new Date()).format('YYYYMMDD')
  524. let excelTitle = params.title || 'download';
  525. let excelBody = JSON.parse(JSON.stringify(tableList));
  526. //firstRow가 있으면 table 정보에 첫 Row에 삽입
  527. if(util.isNull(firstRow) === false) {
  528. excelBody.unshift(firstRow);
  529. }
  530. //excel 생성 데이터
  531. let excelData = []
  532. excelBody.forEach((item) => {
  533. let obj = {}
  534. headers.forEach((names, namesIdx) => {
  535. let objValue = item[headers[namesIdx].dataKey]
  536. obj[names.header] = (util.isNull(objValue)) ? '': objValue.toString().replace('_NONE', '')
  537. })
  538. excelData.push(obj)
  539. });
  540. // var excelData = XLSX.utils.table_to_sheet(tableList); // table id를 넣어주면된다
  541. let excelFileName = [date, excelTitle].join('_') + '.xlsx'
  542. let workbook = XLSX.utils.book_new()
  543. let worksheet = XLSX.utils.json_to_sheet(excelData)
  544. // 헤더 스타일 설정
  545. const headerStyle = {
  546. alignment: {
  547. horizontal: "center",
  548. vertical: "center"
  549. },
  550. fill: { fgColor: { rgb: '878fa2' } },
  551. font: {
  552. bold: true
  553. }
  554. };
  555. // 자동 너비 계산
  556. const maxLengths = headers.map(header =>
  557. Math.max(header.header.length, ...excelData.map(row => (row[header.header] ? row[header.header].toString().length : 0)))
  558. )
  559. worksheet['!cols'] = maxLengths.map(length => ({ wch: length + 20 }));
  560. // 헤더 스타일을 시트에 적용
  561. headers.forEach((header, colIdx) => {
  562. const cellAddress = XLSX.utils.encode_cell({ c: colIdx, r: 0 });
  563. if (!worksheet[cellAddress]) {
  564. worksheet[cellAddress] = { v: header.header };
  565. }
  566. worksheet[cellAddress].s = headerStyle;
  567. });
  568. XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
  569. XLSX.writeFile(workbook, excelFileName)
  570. return;
  571. },
  572. /***************
  573. * p5g util
  574. ***************/
  575. fnExcelFormDown(arrForm, arrGuide, sheetName, fileName){
  576. // 엑셀 파일 생성
  577. const book = utils.book_new()
  578. // data get > 실 개발시 api 호출
  579. const userDataByAoa = arrForm
  580. const guideByAoa = arrGuide
  581. // sheet 생성 - aoa_to_sheet 방식
  582. const worksheetUserData = utils.aoa_to_sheet(userDataByAoa)
  583. const worksheetGuide = utils.aoa_to_sheet(guideByAoa)
  584. // sheet 생성 - json_to_sheet 방식
  585. //const worksheetByJson = xlsx.utils.json_to_sheet(fruitDataByJson)
  586. // 엑셀 파일에 sheet set(엑셀파일, 시트데이터, 시트명)
  587. utils.book_append_sheet(book, worksheetUserData, sheetName)
  588. utils.book_append_sheet(book, worksheetGuide, "GUIDE")
  589. // 엑셀 다운로드
  590. writeFile(book, `${fileName}.xlsx`);
  591. },
  592. /**
  593. * 필수 입력 필드 체크
  594. * @param {Array} fields 필수 입력 필드값
  595. * @param {Object} obj 체크할 대상
  596. * @returns
  597. */
  598. isAllFieldsFilled(fields, obj) {
  599. return fields.every(field => !util.isNull(obj[field]))
  600. },
  601. /**
  602. * 위도, 경도 입력 제한
  603. */
  604. fnIsValidLatlngKey(event){
  605. const key = event.key
  606. const value = event.target.value
  607. // 입력가능한 특수 키
  608. const allowedKeys = ['Backspace', 'Tab', 'Delete', 'ArrowLeft', 'ArrowRight', '-', '.']
  609. if (allowedKeys.includes(key) || (!isNaN(Number(key)) && key !== ' ')) {
  610. // '.' 한번만 입력되도록 제한
  611. if (key === '.' && value.includes('.')) {
  612. event.preventDefault()
  613. return false
  614. }
  615. // '-' 첫번째 위치가 아닌 경우 제한
  616. if (key === '-' && value.length > 0) {
  617. event.preventDefault();
  618. return false
  619. }
  620. return true
  621. }
  622. event.preventDefault()
  623. return false
  624. },
  625. /**
  626. * keydown이벤트 > 위도 입력 체크
  627. * @param {*} event keydown 이벤트 값
  628. */
  629. fnKeydownLatitude(event){
  630. const isValid = util.fnIsValidLatlngKey(event)
  631. if (!isValid) return
  632. const value = event.target.value
  633. const newValue = parseFloat(value + event.key)
  634. if (newValue > 90 || newValue < -90) {
  635. event.preventDefault()
  636. }
  637. },
  638. /**
  639. * keydown이벤트 > 경도 입력 체크
  640. * @param {*} event keydown 이벤트 값
  641. */
  642. fnKeydownLongitude(event){
  643. const isValid = util.fnIsValidLatlngKey(event, true)
  644. if (!isValid) return
  645. const value = event.target.value
  646. const newValue = parseFloat(value + event.key)
  647. if (newValue > 180 || newValue < -180) {
  648. event.preventDefault()
  649. }
  650. },
  651. // 정수
  652. fnReplaceValidateInteger(value){
  653. return value.replace(/[^0-9]/g, '')
  654. },
  655. // 위도, 경도
  656. fnReplaceValidateLatlng(value){
  657. return value.replace(/[^0-9.-]/g, '')
  658. },
  659. /**
  660. * 기간 주기 변경 포맷
  661. * @param {*} periodKey
  662. * @returns
  663. */
  664. fnChangePeriodKey(periodKey){
  665. const today = dayjs().format('YYYY-MM-DD HH:mm:ss')
  666. let startDate = ''
  667. let endDate = ''
  668. if(periodKey === 'Now'){
  669. startDate = today
  670. endDate = today
  671. }else if(periodKey === '1H'){
  672. startDate = dayjs().subtract(1, 'hour').format('YYYY-MM-DD HH:mm:ss')
  673. endDate = today
  674. }else if(periodKey === '6H'){
  675. startDate = dayjs().subtract(6, 'hour').format('YYYY-MM-DD HH:mm:ss')
  676. endDate = today
  677. }else if(periodKey === '1D'){
  678. startDate = dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss')
  679. endDate = today
  680. }else if(periodKey === '1W'){
  681. startDate = dayjs().subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss')
  682. endDate = today
  683. }else{
  684. }
  685. return [startDate, endDate]
  686. },
  687. /**
  688. * 캘린더 종료날짜에 따른 시작날짜와 시작날짜의 최소선택가능날짜 설정
  689. * @param {*} periodKey 기간
  690. * @param {*} startDate 시작날짜
  691. * @param {*} endDate 종료날짜
  692. * @returns
  693. */
  694. setUpdateStartDate(periodKey, startDate, endDate){
  695. let dateFormat = 'YYYY-MM-DD HH:mm:ss'
  696. let diffDay = endDate.diff(startDate, "day", true)
  697. let dDay = Math.floor(diffDay)
  698. let newStartDate = startDate
  699. let startMinDate = dayjs(endDate).subtract(1, 'months').format(dateFormat)
  700. if(dDay < 0) {
  701. // 종료날짜가 시작날짜 이전인 경우 시작날짜 재설정
  702. if(periodKey == '1H') {
  703. newStartDate = dayjs(endDate).subtract(1, 'hours').format(dateFormat)
  704. }else if(periodKey == '6H'){
  705. newStartDate = dayjs(endDate).subtract(6, 'hours').format(dateFormat)
  706. }else if(periodKey == '1D'){
  707. newStartDate = dayjs(endDate).subtract(1, 'days').format(dateFormat)
  708. }else if(periodKey == '1W'){
  709. newStartDate = dayjs(endDate).subtract(1, 'weeks').format(dateFormat)
  710. }
  711. }
  712. return [newStartDate, startMinDate]
  713. },
  714. /**
  715. * 페이지 사이즈 목록 리턴
  716. */
  717. fnGetPageSizeList(){
  718. return [10, 20, 50]
  719. },
  720. fnNullCheckFormatDate(val){
  721. if(!util.isNull(val)){
  722. return dayjs(val).format('YYYY-MM-DD HH:mm:ss')
  723. }else{
  724. return '-'
  725. }
  726. },
  727. /**
  728. * 현재 로그인한 계정의 권한에 맞는 권한목록 설정
  729. * @param {*} myRole 나의 권한
  730. * @param {*} roleList 권한 목록 enum
  731. * @returns
  732. */
  733. setAccountRoleList(myRole, roleList){
  734. let result = []
  735. if(myRole == 'SUPER') result = roleList
  736. else if(myRole == 'ADMIN') result = roleList.slice(1)
  737. else if(myRole == 'MANAGER') result = roleList.slice(2)
  738. else result = []
  739. return result
  740. },
  741. /**
  742. * 지역코드 반환
  743. */
  744. getRegionCode(sidoList, regionName){
  745. let regionCode = ''
  746. sidoList.forEach((item) => {
  747. if(item.title.includes(regionName)) {
  748. regionCode = item.value
  749. }
  750. })
  751. return regionCode
  752. }
  753. }
  754. export default util