@bwg-ui/core 1.1.16 → 1.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/dist/chunks/{BwgLargeUploader-Nx2-wiD8.js → BwgLargeUploader-D6plJv5D.js} +130 -131
  2. package/dist/chunks/BwgLargeUploader-D6plJv5D.js.map +1 -0
  3. package/dist/chunks/BwgLargeUploader-LMj6KXhK.cjs +3 -0
  4. package/dist/chunks/BwgLargeUploader-LMj6KXhK.cjs.map +1 -0
  5. package/dist/chunks/{SSOHandler-DZeC8Xgh.cjs → SSOHandler-DXnV_f_M.cjs} +43 -43
  6. package/dist/chunks/SSOHandler-DXnV_f_M.cjs.map +1 -0
  7. package/dist/chunks/{SSOHandler-DrKRTb6h.js → SSOHandler-yNjxYbHn.js} +263 -263
  8. package/dist/chunks/SSOHandler-yNjxYbHn.js.map +1 -0
  9. package/dist/chunks/{SearchBoxContext-BxtHF9BO.js → SearchBoxContext-CO1AyqH4.js} +7 -7
  10. package/dist/chunks/{SearchBoxContext-BxtHF9BO.js.map → SearchBoxContext-CO1AyqH4.js.map} +1 -1
  11. package/dist/chunks/{SearchBoxContext-Cpr9xa1S.cjs → SearchBoxContext-Cinu3U4b.cjs} +2 -2
  12. package/dist/chunks/{SearchBoxContext-Cpr9xa1S.cjs.map → SearchBoxContext-Cinu3U4b.cjs.map} +1 -1
  13. package/dist/chunks/{ViewContainer-BJQtASUE.cjs → ViewContainer-BH7t9T4d.cjs} +3 -3
  14. package/dist/chunks/{ViewContainer-BJQtASUE.cjs.map → ViewContainer-BH7t9T4d.cjs.map} +1 -1
  15. package/dist/chunks/{ViewContainer-D6ne-F5v.js → ViewContainer-CMbN_tYW.js} +121 -81
  16. package/dist/chunks/{ViewContainer-D6ne-F5v.js.map → ViewContainer-CMbN_tYW.js.map} +1 -1
  17. package/dist/chunks/apiUtils-BJRcT3Tm.js +1315 -0
  18. package/dist/chunks/apiUtils-BJRcT3Tm.js.map +1 -0
  19. package/dist/chunks/apiUtils-DEnQeWNI.cjs +3 -0
  20. package/dist/chunks/apiUtils-DEnQeWNI.cjs.map +1 -0
  21. package/dist/chunks/{codeStore-BzT5wSd9.js → codeStore-C0f5xZ_m.js} +2 -2
  22. package/dist/chunks/{codeStore-BzT5wSd9.js.map → codeStore-C0f5xZ_m.js.map} +1 -1
  23. package/dist/chunks/{codeStore-BGLhSpAM.cjs → codeStore-DTtOQhfW.cjs} +2 -2
  24. package/dist/chunks/{codeStore-BGLhSpAM.cjs.map → codeStore-DTtOQhfW.cjs.map} +1 -1
  25. package/dist/chunks/{favoriteStore-C9utQ6sm.js → favoriteStore-Drhx0843.js} +5 -6
  26. package/dist/chunks/favoriteStore-Drhx0843.js.map +1 -0
  27. package/dist/chunks/favoriteStore-Dyp89Kew.cjs +2 -0
  28. package/dist/chunks/favoriteStore-Dyp89Kew.cjs.map +1 -0
  29. package/dist/chunks/popupStore-D1rxKTyJ.js +92 -0
  30. package/dist/chunks/popupStore-D1rxKTyJ.js.map +1 -0
  31. package/dist/chunks/popupStore-DGMxbQ--.cjs +2 -0
  32. package/dist/chunks/popupStore-DGMxbQ--.cjs.map +1 -0
  33. package/dist/chunks/usePopup-C1h8V04_.js +109 -0
  34. package/dist/chunks/usePopup-C1h8V04_.js.map +1 -0
  35. package/dist/chunks/usePopup-CdpFYf3m.cjs +2 -0
  36. package/dist/chunks/usePopup-CdpFYf3m.cjs.map +1 -0
  37. package/dist/components/common/BwgButtonGroup.d.ts.map +1 -1
  38. package/dist/components/common/BwgGrid.d.ts +5 -1
  39. package/dist/components/common/BwgGrid.d.ts.map +1 -1
  40. package/dist/components/common/index.cjs +1 -1
  41. package/dist/components/common/index.js +1 -1
  42. package/dist/components/core/BwgDatePicker.d.ts +2 -2
  43. package/dist/components/core/BwgDatePicker.d.ts.map +1 -1
  44. package/dist/components/core/BwgLargeUploader.d.ts.map +1 -1
  45. package/dist/components/core/BwgMaskedInput.d.ts +1 -1
  46. package/dist/components/core/BwgMaskedInput.d.ts.map +1 -1
  47. package/dist/components/core/BwgMaskedPicker.d.ts +1 -1
  48. package/dist/components/core/BwgMaskedPicker.d.ts.map +1 -1
  49. package/dist/components/core/BwgNumber.d.ts +0 -1
  50. package/dist/components/core/BwgNumber.d.ts.map +1 -1
  51. package/dist/components/core/BwgRangePicker.d.ts +2 -2
  52. package/dist/components/core/BwgRangePicker.d.ts.map +1 -1
  53. package/dist/components/core/BwgUploader.d.ts.map +1 -1
  54. package/dist/components/core/index.cjs +1 -1
  55. package/dist/components/core/index.js +1 -1
  56. package/dist/components/layout/ViewContainer.d.ts.map +1 -1
  57. package/dist/components/layout/index.cjs +1 -1
  58. package/dist/components/layout/index.js +1 -1
  59. package/dist/index.cjs +1 -1
  60. package/dist/index.js +217 -314
  61. package/dist/index.js.map +1 -1
  62. package/dist/provider/contexts/index.d.ts +0 -1
  63. package/dist/provider/contexts/index.d.ts.map +1 -1
  64. package/dist/provider/index.cjs +1 -1
  65. package/dist/provider/index.js +24 -31
  66. package/dist/stores/favoriteStore.d.ts.map +1 -1
  67. package/dist/stores/index.cjs +1 -1
  68. package/dist/stores/index.js +7 -7
  69. package/dist/utils/commonUtils.d.ts +236 -37
  70. package/dist/utils/commonUtils.d.ts.map +1 -1
  71. package/dist/utils/{FileUtils.d.ts → fileUtils.d.ts} +9 -1
  72. package/dist/utils/fileUtils.d.ts.map +1 -0
  73. package/dist/utils/index.cjs +1 -1
  74. package/dist/utils/index.cjs.map +1 -1
  75. package/dist/utils/index.d.ts +381 -15
  76. package/dist/utils/index.d.ts.map +1 -1
  77. package/dist/utils/index.js +215 -210
  78. package/dist/utils/index.js.map +1 -1
  79. package/dist/utils/notificationUtils.d.ts +5 -5
  80. package/dist/utils/notificationUtils.d.ts.map +1 -1
  81. package/package.json +2 -1
  82. package/dist/chunks/BwgLargeUploader-CgrJUwFW.cjs +0 -3
  83. package/dist/chunks/BwgLargeUploader-CgrJUwFW.cjs.map +0 -1
  84. package/dist/chunks/BwgLargeUploader-Nx2-wiD8.js.map +0 -1
  85. package/dist/chunks/FileUtils-Bbz3AvQn.js +0 -141
  86. package/dist/chunks/FileUtils-Bbz3AvQn.js.map +0 -1
  87. package/dist/chunks/FileUtils-D73GVmB8.cjs +0 -2
  88. package/dist/chunks/FileUtils-D73GVmB8.cjs.map +0 -1
  89. package/dist/chunks/SSOHandler-DZeC8Xgh.cjs.map +0 -1
  90. package/dist/chunks/SSOHandler-DrKRTb6h.js.map +0 -1
  91. package/dist/chunks/_commonjsHelpers-DKOUU3wS.cjs +0 -2
  92. package/dist/chunks/_commonjsHelpers-DKOUU3wS.cjs.map +0 -1
  93. package/dist/chunks/_commonjsHelpers-DaMA6jEr.js +0 -9
  94. package/dist/chunks/_commonjsHelpers-DaMA6jEr.js.map +0 -1
  95. package/dist/chunks/apiUtils-C45AWfu-.js +0 -957
  96. package/dist/chunks/apiUtils-C45AWfu-.js.map +0 -1
  97. package/dist/chunks/apiUtils-Cbg6NQLv.cjs +0 -4
  98. package/dist/chunks/apiUtils-Cbg6NQLv.cjs.map +0 -1
  99. package/dist/chunks/commonUtils-BH6QwGUb.cjs +0 -2
  100. package/dist/chunks/commonUtils-BH6QwGUb.cjs.map +0 -1
  101. package/dist/chunks/commonUtils-Bb16Yqjk.js +0 -629
  102. package/dist/chunks/commonUtils-Bb16Yqjk.js.map +0 -1
  103. package/dist/chunks/envUtils-C9Gf5aek.js +0 -30
  104. package/dist/chunks/envUtils-C9Gf5aek.js.map +0 -1
  105. package/dist/chunks/envUtils-CduTHoHu.cjs +0 -2
  106. package/dist/chunks/envUtils-CduTHoHu.cjs.map +0 -1
  107. package/dist/chunks/favoriteStore-3YceyayF.cjs +0 -2
  108. package/dist/chunks/favoriteStore-3YceyayF.cjs.map +0 -1
  109. package/dist/chunks/favoriteStore-C9utQ6sm.js.map +0 -1
  110. package/dist/chunks/popupStore-DmFbkkjd.js +0 -98
  111. package/dist/chunks/popupStore-DmFbkkjd.js.map +0 -1
  112. package/dist/chunks/popupStore-DnWLaQ70.cjs +0 -2
  113. package/dist/chunks/popupStore-DnWLaQ70.cjs.map +0 -1
  114. package/dist/chunks/usePopup-C8FrbrDD.cjs +0 -2
  115. package/dist/chunks/usePopup-C8FrbrDD.cjs.map +0 -1
  116. package/dist/chunks/usePopup-pfh-ajfP.js +0 -241
  117. package/dist/chunks/usePopup-pfh-ajfP.js.map +0 -1
  118. package/dist/provider/contexts/UtilsContext.d.ts +0 -195
  119. package/dist/provider/contexts/UtilsContext.d.ts.map +0 -1
  120. package/dist/utils/FileUtils.d.ts.map +0 -1
  121. package/dist/utils/arrayUtils.d.ts +0 -35
  122. package/dist/utils/arrayUtils.d.ts.map +0 -1
  123. package/dist/utils/cookieUtils.d.ts +0 -5
  124. package/dist/utils/cookieUtils.d.ts.map +0 -1
  125. package/dist/utils/dateUtils.d.ts +0 -27
  126. package/dist/utils/dateUtils.d.ts.map +0 -1
  127. package/dist/utils/imageUtils.d.ts +0 -32
  128. package/dist/utils/imageUtils.d.ts.map +0 -1
  129. package/dist/utils/objectUtils.d.ts +0 -28
  130. package/dist/utils/objectUtils.d.ts.map +0 -1
  131. package/dist/utils/stringUtils.d.ts +0 -143
  132. package/dist/utils/stringUtils.d.ts.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"apiUtils-C45AWfu-.js","sources":["../../src/utils/stringUtils.ts","../../src/utils/notificationUtils.ts","../../node_modules/zustand/esm/middleware.mjs","../../src/stores/userStore.ts","../../src/utils/userUtils.ts","../../src/utils/serviceConfig.ts","../../src/stores/menuModelStore.ts","../../src/stores/menuViewStore.ts","../../src/stores/loadingStore.ts","../../src/utils/apiUtils.ts"],"sourcesContent":["/**\r\n * 문자열 유틸리티 함수들\r\n */\r\n\r\nimport CryptoJS from \"crypto-js\";\r\n\r\n// 문자열이 비어있는지 확인\r\nexport const isEmpty = (str: any): boolean => {\r\n if (typeof str !== \"string\") return !str;\r\n return str.trim().length === 0;\r\n};\r\n\r\n/**\r\n * 문자열이 비어있는지 확인하고, 비어있으면 defaultValue를 반환\r\n * @param str - 문자열\r\n * @param defaultValue - 비어있을 때 반환할 기본값\r\n * @returns 문자열이 비어있으면 defaultValue, 아니면 str\r\n */\r\nexport const isSafeEmpty = (\r\n str: string | null | undefined,\r\n defaultValue: string\r\n): string => {\r\n return isEmpty(str) ? defaultValue : str || \"\";\r\n};\r\n\r\n// 문자열이 비어있지 않은지 확인\r\nexport const isNotEmpty = (str: string | null | undefined): boolean => {\r\n return !isEmpty(str);\r\n};\r\n\r\n// 문자열 길이 제한\r\nexport const truncate = (\r\n str: string,\r\n length: number,\r\n suffix: string = \"...\"\r\n): string => {\r\n if (str.length <= length) return str;\r\n return str.substring(0, length) + suffix;\r\n};\r\n\r\n// 첫 글자 대문자로 변환\r\nexport const capitalize = (str: string): string => {\r\n if (isEmpty(str)) return str;\r\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();\r\n};\r\n\r\n// 모든 단어의 첫 글자를 대문자로 변환\r\nexport const capitalizeWords = (str: string): string => {\r\n if (isEmpty(str)) return str;\r\n return str\r\n .split(\" \")\r\n .map((word) => capitalize(word))\r\n .join(\" \");\r\n};\r\n\r\n// 카멜케이스로 변환\r\nexport const toCamelCase = (str: string): string => {\r\n return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());\r\n};\r\n\r\n// 스네이크케이스로 변환\r\nexport const toSnakeCase = (str: string): string => {\r\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\r\n};\r\n\r\n// 케밥케이스로 변환\r\nexport const toKebabCase = (str: string): string => {\r\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\r\n};\r\n\r\n// 전화번호 포맷팅\r\nexport const formatPhoneNumber = (phone: string): string => {\r\n const cleaned = phone.replace(/\\D/g, \"\");\r\n const match = cleaned.match(/^(\\d{3})(\\d{4})(\\d{4})$/);\r\n if (match) {\r\n return `${match[1]}-${match[2]}-${match[3]}`;\r\n }\r\n return phone;\r\n};\r\n\r\n// 이메일 유효성 검사\r\nexport const isValidEmail = (email: string): boolean => {\r\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n return emailRegex.test(email);\r\n};\r\n\r\n// URL 유효성 검사\r\nexport const isValidUrl = (url: string): boolean => {\r\n try {\r\n new URL(url);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\n// 숫자만 추출\r\nexport const extractNumbers = (str: string): string => {\r\n return str.replace(/\\D/g, \"\");\r\n};\r\n\r\n// 특수문자 제거\r\nexport const removeSpecialChars = (str: string): string => {\r\n return str.replace(/[^a-zA-Z0-9가-힣\\s]/g, \"\");\r\n};\r\n\r\n// HTML 태그 제거\r\nexport const removeHtmlTags = (str: string): string => {\r\n return str.replace(/<[^>]*>/g, \"\");\r\n};\r\n\r\n// 줄바꿈을 <br> 태그로 변환\r\nexport const nl2br = (str: string): string => {\r\n return str.replace(/\\n/g, \"<br>\");\r\n};\r\n\r\n// <br> 태그를 줄바꿈으로 변환\r\nexport const br2nl = (str: string): string => {\r\n return str.replace(/<br\\s*\\/?>/gi, \"\\n\");\r\n};\r\n\r\n// 문자열에서 특정 패턴 찾기\r\nexport const findPattern = (str: string, pattern: RegExp): string[] => {\r\n const matches = str.match(pattern);\r\n return matches ? matches : [];\r\n};\r\n\r\n// 문자열 반복\r\nexport const repeat = (str: string, count: number): string => {\r\n return str.repeat(count);\r\n};\r\n\r\n// 문자열 패딩 (왼쪽)\r\nexport const padLeft = (\r\n str: string,\r\n length: number,\r\n char: string = \" \"\r\n): string => {\r\n return str.padStart(length, char);\r\n};\r\n\r\n// 문자열 패딩 (오른쪽)\r\nexport const padRight = (\r\n str: string,\r\n length: number,\r\n char: string = \" \"\r\n): string => {\r\n return str.padEnd(length, char);\r\n};\r\n\r\n// 문자열 중앙 정렬\r\nexport const center = (\r\n str: string,\r\n length: number,\r\n char: string = \" \"\r\n): string => {\r\n const padding = length - str.length;\r\n if (padding <= 0) return str;\r\n\r\n const leftPadding = Math.floor(padding / 2);\r\n const rightPadding = padding - leftPadding;\r\n\r\n return char.repeat(leftPadding) + str + char.repeat(rightPadding);\r\n};\r\n\r\n// 랜덤 문자열 생성\r\nexport const generateRandomString = (\r\n length: number,\r\n chars: string = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"\r\n): string => {\r\n let result = \"\";\r\n for (let i = 0; i < length; i++) {\r\n result += chars.charAt(Math.floor(Math.random() * chars.length));\r\n }\r\n return result;\r\n};\r\n\r\n// 문자열 역순\r\nexport const reverse = (str: string): string => {\r\n return str.split(\"\").reverse().join(\"\");\r\n};\r\n\r\n// 문자열에서 특정 문자 개수 세기\r\nexport const countChar = (str: string, char: string): number => {\r\n return (str.match(new RegExp(char, \"g\")) || []).length;\r\n};\r\n\r\n// 문자열에서 단어 개수 세기\r\nexport const countWords = (str: string): number => {\r\n return str.trim().split(/\\s+/).length;\r\n};\r\n\r\n/**\r\n * UUID v4 생성 (하이픈 포함)\r\n */\r\nconst generateUUIDv4 = (): string => {\r\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n};\r\n\r\n/**\r\n * Random UID 생성 (하이픈 제거)\r\n * @param length - UID 길이 (기본값: 32)\r\n * @returns 하이픈이 제거된 UID 문자열\r\n */\r\nexport const generateUID = (length: number = 32): string => {\r\n const uuid = generateUUIDv4();\r\n const uidWithoutHyphens = uuid.replace(/-/g, \"\");\r\n\r\n if (length >= 32) {\r\n return (\r\n uidWithoutHyphens + generateRandomString(length - 32, \"0123456789abcdef\")\r\n );\r\n } else {\r\n return uidWithoutHyphens.substring(0, length);\r\n }\r\n};\r\n\r\n/**\r\n * 짧은 Random UID 생성 (16자리)\r\n * @returns 16자리 UID\r\n */\r\nexport const generateShortUID = (): string => {\r\n return generateUID(16);\r\n};\r\n\r\n/**\r\n * 긴 Random UID 생성 (64자리)\r\n * @returns 64자리 UID\r\n */\r\nexport const generateLongUID = (): string => {\r\n return generateUID(64);\r\n};\r\n\r\n/**\r\n * 숫자만으로 구성된 UID 생성\r\n * @param length - UID 길이 (기본값: 16)\r\n * @returns 숫자로만 구성된 UID\r\n */\r\nexport const generateNumericUID = (length: number = 16): string => {\r\n return generateRandomString(length, \"0123456789\");\r\n};\r\n\r\n/**\r\n * 대문자와 숫자로 구성된 UID 생성\r\n * @param length - UID 길이 (기본값: 16)\r\n * @returns 대문자와 숫자로 구성된 UID\r\n */\r\nexport const generateAlphanumericUID = (length: number = 16): string => {\r\n return generateRandomString(length, \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\");\r\n};\r\n\r\n/**\r\n * GUID 생성 (하이픈 포함)\r\n * @returns 표준 GUID 형식\r\n */\r\nexport const generateGUID = (): string => {\r\n return generateUUIDv4();\r\n};\r\n\r\n/**\r\n * GUID 생성 (하이픈 제거)\r\n * @returns 하이픈이 제거된 GUID\r\n */\r\nexport const generateGUIDWithoutHyphens = (): string => {\r\n return generateGUID().replace(/-/g, \"\");\r\n};\r\n\r\n/**\r\n * 타임스탬프 기반 UID 생성\r\n * @returns 타임스탬프 + 랜덤 문자열 조합\r\n */\r\nexport const generateTimestampUID = (): string => {\r\n const timestamp = Date.now().toString(36);\r\n const random = generateRandomString(8, \"0123456789abcdef\");\r\n return timestamp + random;\r\n};\r\n\r\n/**\r\n * 사용자 정의 UID 생성\r\n * @param pattern - UID 패턴 (예: 'XXXX-YYYY-ZZZZ')\r\n * @param charset - 사용할 문자셋 (기본값: 영문자+숫자)\r\n * @returns 패턴에 맞는 UID\r\n */\r\nexport const generateCustomUID = (\r\n pattern: string,\r\n charset: string = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"\r\n): string => {\r\n return pattern.replace(/[X-Z]/g, () =>\r\n charset.charAt(Math.floor(Math.random() * charset.length))\r\n );\r\n};\r\n\r\n// 암호화 관련 함수들\r\n\r\n/**\r\n * SHA256 단방향 암호화\r\n * @param data\r\n * @returns\r\n\r\n */\r\nexport const encryptSha256 = (data: string) => {\r\n const shaBuffer = CryptoJS.SHA256(data);\r\n const encStr = CryptoJS.enc.Base64.stringify(shaBuffer);\r\n return encStr;\r\n};\r\n\r\n/**\r\n * 환경 변수에서 암호화 키 가져오기\r\n */\r\nconst getEncryptionKey = (): string => {\r\n return \"abcdefghij1234567890!@#$%^&*();;\";\r\n};\r\n\r\n/**\r\n * 환경 변수에서 IV 가져오기\r\n */\r\nconst getEncryptionIV = (): string => {\r\n return \"123456098765!@#$\";\r\n};\r\n\r\n/**\r\n * AES 암호화 함수\r\n * @param plainText - 암호화할 평문\r\n * @returns 암호화된 문자열\r\n */\r\nexport const bxmEncrypt = (plainText: string): string => {\r\n if (!plainText) return \"\";\r\n\r\n try {\r\n // 키와 IV를 WordArray로 직접 변환\r\n const key = CryptoJS.enc.Utf8.parse(getEncryptionKey());\r\n const iv = CryptoJS.enc.Utf8.parse(getEncryptionIV());\r\n\r\n const bytes = CryptoJS.AES.encrypt(plainText, key, {\r\n iv: iv,\r\n padding: CryptoJS.pad.Pkcs7,\r\n mode: CryptoJS.mode.CBC,\r\n });\r\n return bytes.toString();\r\n } catch (error) {\r\n console.error(\"암호화 오류:\", error);\r\n return \"\";\r\n }\r\n};\r\n\r\n/**\r\n * AES 복호화 함수\r\n * @param encryptedText - 복호화할 암호문\r\n * @returns 복호화된 평문\r\n */\r\nexport const bxmDecrypt = (encryptedText: string): string => {\r\n if (!encryptedText) return \"\";\r\n\r\n try {\r\n // 키와 IV를 WordArray로 직접 변환\r\n const key = CryptoJS.enc.Utf8.parse(getEncryptionKey());\r\n const iv = CryptoJS.enc.Utf8.parse(getEncryptionIV());\r\n\r\n const bytes = CryptoJS.AES.decrypt(encryptedText, key, {\r\n iv: iv,\r\n padding: CryptoJS.pad.Pkcs7,\r\n mode: CryptoJS.mode.CBC,\r\n });\r\n return bytes.toString(CryptoJS.enc.Utf8);\r\n } catch (error) {\r\n console.error(\"복호화 오류:\", error);\r\n return \"\";\r\n }\r\n};\r\n\r\n/**\r\n * 간단한 AES 암호화 (기본 설정)\r\n * @param plainText - 암호화할 평문\r\n * @param secretKey - 암호화 키 (선택사항)\r\n * @returns 암호화된 문자열\r\n */\r\nexport const simpleEncrypt = (\r\n plainText: string,\r\n secretKey?: string\r\n): string => {\r\n if (!plainText) return \"\";\r\n\r\n try {\r\n const key = secretKey || getEncryptionKey();\r\n const bytes = CryptoJS.AES.encrypt(plainText, key);\r\n return bytes.toString();\r\n } catch (error) {\r\n console.error(\"간단한 암호화 오류:\", error);\r\n return \"\";\r\n }\r\n};\r\n\r\n/**\r\n * 간단한 AES 복호화 (기본 설정)\r\n * @param encryptedText - 복호화할 암호문\r\n * @param secretKey - 복호화 키 (선택사항)\r\n * @returns 복호화된 평문\r\n */\r\nexport const simpleDecrypt = (\r\n encryptedText: string,\r\n secretKey?: string\r\n): string => {\r\n if (!encryptedText) return \"\";\r\n\r\n try {\r\n const key = secretKey || getEncryptionKey();\r\n const bytes = CryptoJS.AES.decrypt(encryptedText, key);\r\n return bytes.toString(CryptoJS.enc.Utf8);\r\n } catch (error) {\r\n console.error(\"간단한 복호화 오류:\", error);\r\n return \"\";\r\n }\r\n};\r\n\r\n/**\r\n * MD5 해시 함수\r\n * @param text - 해시할 텍스트\r\n * @returns MD5 해시값\r\n */\r\nexport const md5Hash = (text: string): string => {\r\n if (!text) return \"\";\r\n return CryptoJS.MD5(text).toString();\r\n};\r\n\r\n/**\r\n * SHA256 해시 함수\r\n * @param text - 해시할 텍스트\r\n * @returns SHA256 해시값\r\n */\r\nexport const sha256Hash = (text: string): string => {\r\n if (!text) return \"\";\r\n return CryptoJS.SHA256(text).toString();\r\n};\r\n\r\n/**\r\n * Base64 인코딩\r\n * @param text - 인코딩할 텍스트\r\n * @returns Base64 인코딩된 문자열\r\n */\r\nexport const base64Encode = (text: string): string => {\r\n if (!text) return \"\";\r\n return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(text));\r\n};\r\n\r\n/**\r\n * Base64 디코딩\r\n * @param encodedText - 디코딩할 Base64 문자열\r\n * @returns 디코딩된 문자열\r\n */\r\nexport const base64Decode = (encodedText: string): string => {\r\n if (!encodedText) return \"\";\r\n try {\r\n return CryptoJS.enc.Base64.parse(encodedText).toString(CryptoJS.enc.Utf8);\r\n } catch (error) {\r\n console.error(\"Base64 디코딩 오류:\", error);\r\n return \"\";\r\n }\r\n};\r\n","import { notification } from \"antd\";\r\nimport type { NotificationArgsProps } from \"antd\";\r\n\r\n// Notification 타입 정의\r\nexport type NotificationType = \"success\" | \"error\" | \"info\" | \"warning\";\r\n\r\n// BwgError 전용 인터페이스\r\nexport interface BwgErrorProps {\r\n message: string;\r\n description?: string;\r\n duration?: number;\r\n placement?: NotificationArgsProps[\"placement\"];\r\n}\r\n\r\n// 기본 설정\r\nconst DEFAULT_CONFIG = {\r\n duration: 4.5, // 4.5초\r\n placement: \"topRight\" as const,\r\n maxCount: 3, // 최대 3개까지 표시\r\n};\r\n\r\n// 전역 Notification 유틸리티 클래스\r\nclass NotificationService {\r\n private static instance: NotificationService;\r\n\r\n private constructor() {\r\n // 싱글톤 패턴\r\n }\r\n\r\n public static getInstance(): NotificationService {\r\n if (!NotificationService.instance) {\r\n NotificationService.instance = new NotificationService();\r\n }\r\n return NotificationService.instance;\r\n }\r\n\r\n /**\r\n * BwgError 전용 에러 알림\r\n * @param props - 에러 메시지 설정\r\n */\r\n public showBwgError(props: BwgErrorProps): void {\r\n const {\r\n message,\r\n description,\r\n duration = DEFAULT_CONFIG.duration,\r\n placement = DEFAULT_CONFIG.placement,\r\n } = props;\r\n\r\n notification.error({\r\n message: `${message}`,\r\n description: description || \"오류가 발생했습니다. 다시 시도해주세요.\",\r\n duration,\r\n placement,\r\n style: {\r\n borderLeft: \"4px solid #ff4d4f\",\r\n backgroundColor: \"#fff2f0\",\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * 성공 알림\r\n */\r\n public showSuccess(\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n ): void {\r\n notification.success({\r\n message: `${message}`,\r\n description,\r\n duration: duration || DEFAULT_CONFIG.duration,\r\n placement: DEFAULT_CONFIG.placement,\r\n });\r\n }\r\n\r\n /**\r\n * 정보 알림\r\n */\r\n public showInfo(\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n ): void {\r\n notification.info({\r\n message: `${message}`,\r\n description,\r\n duration: duration || DEFAULT_CONFIG.duration,\r\n placement: DEFAULT_CONFIG.placement,\r\n });\r\n }\r\n\r\n /**\r\n * 경고 알림\r\n */\r\n public showWarning(\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n ): void {\r\n notification.warning({\r\n message: `${message}`,\r\n description,\r\n duration: duration || DEFAULT_CONFIG.duration,\r\n placement: DEFAULT_CONFIG.placement,\r\n });\r\n }\r\n\r\n /**\r\n * 일반 에러 알림\r\n */\r\n public showError(\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n ): void {\r\n notification.error({\r\n message: `${message}`,\r\n description,\r\n duration: duration || DEFAULT_CONFIG.duration,\r\n placement: DEFAULT_CONFIG.placement,\r\n });\r\n }\r\n\r\n /**\r\n * 모든 알림 닫기\r\n */\r\n public destroy(): void {\r\n notification.destroy();\r\n }\r\n\r\n /**\r\n * 특정 키의 알림 닫기\r\n */\r\n public close(key: string): void {\r\n // antd notification API에서는 개별 close 메서드가 없으므로 destroy 사용\r\n notification.destroy();\r\n }\r\n}\r\n\r\n// 싱글톤 인스턴스 생성\r\nexport const notificationService = NotificationService.getInstance();\r\n\r\n// 편의 함수들\r\nexport const showBwgError = (props: BwgErrorProps): void => {\r\n notificationService.showBwgError(props);\r\n};\r\n\r\nexport const showSuccess = (\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n): void => {\r\n notificationService.showSuccess(message, description, duration);\r\n};\r\n\r\nexport const showInfo = (\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n): void => {\r\n notificationService.showInfo(message, description, duration);\r\n};\r\n\r\nexport const showWarning = (\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n): void => {\r\n notificationService.showWarning(message, description, duration);\r\n};\r\n\r\nexport const showError = (\r\n message: string,\r\n description?: string,\r\n duration?: number\r\n): void => {\r\n notificationService.showError(message, description, duration);\r\n};\r\n\r\nexport const destroyNotifications = (): void => {\r\n notificationService.destroy();\r\n};\r\n\r\nexport const closeNotification = (key: string): void => {\r\n notificationService.close(key);\r\n};\r\n","const reduxImpl = (reducer, initial) => (set, _get, api) => {\n api.dispatch = (action) => {\n set((state) => reducer(state, action), false, action);\n return action;\n };\n api.dispatchFromDevtools = true;\n return { dispatch: (...args) => api.dispatch(...args), ...initial };\n};\nconst redux = reduxImpl;\n\nconst trackedConnections = /* @__PURE__ */ new Map();\nconst getTrackedConnectionState = (name) => {\n const api = trackedConnections.get(name);\n if (!api) return {};\n return Object.fromEntries(\n Object.entries(api.stores).map(([key, api2]) => [key, api2.getState()])\n );\n};\nconst extractConnectionInformation = (store, extensionConnector, options) => {\n if (store === void 0) {\n return {\n type: \"untracked\",\n connection: extensionConnector.connect(options)\n };\n }\n const existingConnection = trackedConnections.get(options.name);\n if (existingConnection) {\n return { type: \"tracked\", store, ...existingConnection };\n }\n const newConnection = {\n connection: extensionConnector.connect(options),\n stores: {}\n };\n trackedConnections.set(options.name, newConnection);\n return { type: \"tracked\", store, ...newConnection };\n};\nconst removeStoreFromTrackedConnections = (name, store) => {\n if (store === void 0) return;\n const connectionInfo = trackedConnections.get(name);\n if (!connectionInfo) return;\n delete connectionInfo.stores[store];\n if (Object.keys(connectionInfo.stores).length === 0) {\n trackedConnections.delete(name);\n }\n};\nconst findCallerName = (stack) => {\n var _a, _b;\n if (!stack) return void 0;\n const traceLines = stack.split(\"\\n\");\n const apiSetStateLineIndex = traceLines.findIndex(\n (traceLine) => traceLine.includes(\"api.setState\")\n );\n if (apiSetStateLineIndex < 0) return void 0;\n const callerLine = ((_a = traceLines[apiSetStateLineIndex + 1]) == null ? void 0 : _a.trim()) || \"\";\n return (_b = /.+ (.+) .+/.exec(callerLine)) == null ? void 0 : _b[1];\n};\nconst devtoolsImpl = (fn, devtoolsOptions = {}) => (set, get, api) => {\n const { enabled, anonymousActionType, store, ...options } = devtoolsOptions;\n let extensionConnector;\n try {\n extensionConnector = (enabled != null ? enabled : (import.meta.env ? import.meta.env.MODE : void 0) !== \"production\") && window.__REDUX_DEVTOOLS_EXTENSION__;\n } catch (e) {\n }\n if (!extensionConnector) {\n return fn(set, get, api);\n }\n const { connection, ...connectionInformation } = extractConnectionInformation(store, extensionConnector, options);\n let isRecording = true;\n api.setState = ((state, replace, nameOrAction) => {\n const r = set(state, replace);\n if (!isRecording) return r;\n const action = nameOrAction === void 0 ? {\n type: anonymousActionType || findCallerName(new Error().stack) || \"anonymous\"\n } : typeof nameOrAction === \"string\" ? { type: nameOrAction } : nameOrAction;\n if (store === void 0) {\n connection == null ? void 0 : connection.send(action, get());\n return r;\n }\n connection == null ? void 0 : connection.send(\n {\n ...action,\n type: `${store}/${action.type}`\n },\n {\n ...getTrackedConnectionState(options.name),\n [store]: api.getState()\n }\n );\n return r;\n });\n api.devtools = {\n cleanup: () => {\n if (connection && typeof connection.unsubscribe === \"function\") {\n connection.unsubscribe();\n }\n removeStoreFromTrackedConnections(options.name, store);\n }\n };\n const setStateFromDevtools = (...a) => {\n const originalIsRecording = isRecording;\n isRecording = false;\n set(...a);\n isRecording = originalIsRecording;\n };\n const initialState = fn(api.setState, get, api);\n if (connectionInformation.type === \"untracked\") {\n connection == null ? void 0 : connection.init(initialState);\n } else {\n connectionInformation.stores[connectionInformation.store] = api;\n connection == null ? void 0 : connection.init(\n Object.fromEntries(\n Object.entries(connectionInformation.stores).map(([key, store2]) => [\n key,\n key === connectionInformation.store ? initialState : store2.getState()\n ])\n )\n );\n }\n if (api.dispatchFromDevtools && typeof api.dispatch === \"function\") {\n let didWarnAboutReservedActionType = false;\n const originalDispatch = api.dispatch;\n api.dispatch = (...args) => {\n if ((import.meta.env ? import.meta.env.MODE : void 0) !== \"production\" && args[0].type === \"__setState\" && !didWarnAboutReservedActionType) {\n console.warn(\n '[zustand devtools middleware] \"__setState\" action type is reserved to set state from the devtools. Avoid using it.'\n );\n didWarnAboutReservedActionType = true;\n }\n originalDispatch(...args);\n };\n }\n connection.subscribe((message) => {\n var _a;\n switch (message.type) {\n case \"ACTION\":\n if (typeof message.payload !== \"string\") {\n console.error(\n \"[zustand devtools middleware] Unsupported action format\"\n );\n return;\n }\n return parseJsonThen(\n message.payload,\n (action) => {\n if (action.type === \"__setState\") {\n if (store === void 0) {\n setStateFromDevtools(action.state);\n return;\n }\n if (Object.keys(action.state).length !== 1) {\n console.error(\n `\n [zustand devtools middleware] Unsupported __setState action format.\n When using 'store' option in devtools(), the 'state' should have only one key, which is a value of 'store' that was passed in devtools(),\n and value of this only key should be a state object. Example: { \"type\": \"__setState\", \"state\": { \"abc123Store\": { \"foo\": \"bar\" } } }\n `\n );\n }\n const stateFromDevtools = action.state[store];\n if (stateFromDevtools === void 0 || stateFromDevtools === null) {\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(stateFromDevtools)) {\n setStateFromDevtools(stateFromDevtools);\n }\n return;\n }\n if (!api.dispatchFromDevtools) return;\n if (typeof api.dispatch !== \"function\") return;\n api.dispatch(action);\n }\n );\n case \"DISPATCH\":\n switch (message.payload.type) {\n case \"RESET\":\n setStateFromDevtools(initialState);\n if (store === void 0) {\n return connection == null ? void 0 : connection.init(api.getState());\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"COMMIT\":\n if (store === void 0) {\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n return connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n case \"ROLLBACK\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n connection == null ? void 0 : connection.init(api.getState());\n return;\n }\n setStateFromDevtools(state[store]);\n connection == null ? void 0 : connection.init(getTrackedConnectionState(options.name));\n });\n case \"JUMP_TO_STATE\":\n case \"JUMP_TO_ACTION\":\n return parseJsonThen(message.state, (state) => {\n if (store === void 0) {\n setStateFromDevtools(state);\n return;\n }\n if (JSON.stringify(api.getState()) !== JSON.stringify(state[store])) {\n setStateFromDevtools(state[store]);\n }\n });\n case \"IMPORT_STATE\": {\n const { nextLiftedState } = message.payload;\n const lastComputedState = (_a = nextLiftedState.computedStates.slice(-1)[0]) == null ? void 0 : _a.state;\n if (!lastComputedState) return;\n if (store === void 0) {\n setStateFromDevtools(lastComputedState);\n } else {\n setStateFromDevtools(lastComputedState[store]);\n }\n connection == null ? void 0 : connection.send(\n null,\n // FIXME no-any\n nextLiftedState\n );\n return;\n }\n case \"PAUSE_RECORDING\":\n return isRecording = !isRecording;\n }\n return;\n }\n });\n return initialState;\n};\nconst devtools = devtoolsImpl;\nconst parseJsonThen = (stringified, fn) => {\n let parsed;\n try {\n parsed = JSON.parse(stringified);\n } catch (e) {\n console.error(\n \"[zustand devtools middleware] Could not parse the received json\",\n e\n );\n }\n if (parsed !== void 0) fn(parsed);\n};\n\nconst subscribeWithSelectorImpl = (fn) => (set, get, api) => {\n const origSubscribe = api.subscribe;\n api.subscribe = ((selector, optListener, options) => {\n let listener = selector;\n if (optListener) {\n const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;\n let currentSlice = selector(api.getState());\n listener = (state) => {\n const nextSlice = selector(state);\n if (!equalityFn(currentSlice, nextSlice)) {\n const previousSlice = currentSlice;\n optListener(currentSlice = nextSlice, previousSlice);\n }\n };\n if (options == null ? void 0 : options.fireImmediately) {\n optListener(currentSlice, currentSlice);\n }\n }\n return origSubscribe(listener);\n });\n const initialState = fn(set, get, api);\n return initialState;\n};\nconst subscribeWithSelector = subscribeWithSelectorImpl;\n\nfunction combine(initialState, create) {\n return (...args) => Object.assign({}, initialState, create(...args));\n}\n\nfunction createJSONStorage(getStorage, options) {\n let storage;\n try {\n storage = getStorage();\n } catch (e) {\n return;\n }\n const persistStorage = {\n getItem: (name) => {\n var _a;\n const parse = (str2) => {\n if (str2 === null) {\n return null;\n }\n return JSON.parse(str2, options == null ? void 0 : options.reviver);\n };\n const str = (_a = storage.getItem(name)) != null ? _a : null;\n if (str instanceof Promise) {\n return str.then(parse);\n }\n return parse(str);\n },\n setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, options == null ? void 0 : options.replacer)),\n removeItem: (name) => storage.removeItem(name)\n };\n return persistStorage;\n}\nconst toThenable = (fn) => (input) => {\n try {\n const result = fn(input);\n if (result instanceof Promise) {\n return result;\n }\n return {\n then(onFulfilled) {\n return toThenable(onFulfilled)(result);\n },\n catch(_onRejected) {\n return this;\n }\n };\n } catch (e) {\n return {\n then(_onFulfilled) {\n return this;\n },\n catch(onRejected) {\n return toThenable(onRejected)(e);\n }\n };\n }\n};\nconst persistImpl = (config, baseOptions) => (set, get, api) => {\n let options = {\n storage: createJSONStorage(() => localStorage),\n partialize: (state) => state,\n version: 0,\n merge: (persistedState, currentState) => ({\n ...currentState,\n ...persistedState\n }),\n ...baseOptions\n };\n let hasHydrated = false;\n const hydrationListeners = /* @__PURE__ */ new Set();\n const finishHydrationListeners = /* @__PURE__ */ new Set();\n let storage = options.storage;\n if (!storage) {\n return config(\n (...args) => {\n console.warn(\n `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.`\n );\n set(...args);\n },\n get,\n api\n );\n }\n const setItem = () => {\n const state = options.partialize({ ...get() });\n return storage.setItem(options.name, {\n state,\n version: options.version\n });\n };\n const savedSetState = api.setState;\n api.setState = (state, replace) => {\n savedSetState(state, replace);\n return setItem();\n };\n const configResult = config(\n (...args) => {\n set(...args);\n return setItem();\n },\n get,\n api\n );\n api.getInitialState = () => configResult;\n let stateFromStorage;\n const hydrate = () => {\n var _a, _b;\n if (!storage) return;\n hasHydrated = false;\n hydrationListeners.forEach((cb) => {\n var _a2;\n return cb((_a2 = get()) != null ? _a2 : configResult);\n });\n const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0;\n return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => {\n if (deserializedStorageValue) {\n if (typeof deserializedStorageValue.version === \"number\" && deserializedStorageValue.version !== options.version) {\n if (options.migrate) {\n const migration = options.migrate(\n deserializedStorageValue.state,\n deserializedStorageValue.version\n );\n if (migration instanceof Promise) {\n return migration.then((result) => [true, result]);\n }\n return [true, migration];\n }\n console.error(\n `State loaded from storage couldn't be migrated since no migrate function was provided`\n );\n } else {\n return [false, deserializedStorageValue.state];\n }\n }\n return [false, void 0];\n }).then((migrationResult) => {\n var _a2;\n const [migrated, migratedState] = migrationResult;\n stateFromStorage = options.merge(\n migratedState,\n (_a2 = get()) != null ? _a2 : configResult\n );\n set(stateFromStorage, true);\n if (migrated) {\n return setItem();\n }\n }).then(() => {\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(stateFromStorage, void 0);\n stateFromStorage = get();\n hasHydrated = true;\n finishHydrationListeners.forEach((cb) => cb(stateFromStorage));\n }).catch((e) => {\n postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e);\n });\n };\n api.persist = {\n setOptions: (newOptions) => {\n options = {\n ...options,\n ...newOptions\n };\n if (newOptions.storage) {\n storage = newOptions.storage;\n }\n },\n clearStorage: () => {\n storage == null ? void 0 : storage.removeItem(options.name);\n },\n getOptions: () => options,\n rehydrate: () => hydrate(),\n hasHydrated: () => hasHydrated,\n onHydrate: (cb) => {\n hydrationListeners.add(cb);\n return () => {\n hydrationListeners.delete(cb);\n };\n },\n onFinishHydration: (cb) => {\n finishHydrationListeners.add(cb);\n return () => {\n finishHydrationListeners.delete(cb);\n };\n }\n };\n if (!options.skipHydration) {\n hydrate();\n }\n return stateFromStorage || configResult;\n};\nconst persist = persistImpl;\n\nexport { combine, createJSONStorage, devtools, persist, redux, subscribeWithSelector };\n","import { create } from 'zustand'\r\nimport { persist } from 'zustand/middleware'\r\n\r\n// 사용자 타입 정의\r\nexport interface UserInfo {\r\n crprCd: string | number // 회사정보\r\n userId: string // 사용자ID\r\n userNm: string // 사용자명\r\n userDvsn: string // 사용자구분\r\n emplNo: string // 사번\r\n dprtCd: string | number // 부서코드\r\n dprtNm: string // 부서명\r\n roleList: string[] // 사용자 역할목록\r\n}\r\n\r\n// 사용자 스토어 타입 정의\r\nexport interface UserStore {\r\n user: UserInfo | null\r\n isLoggedIn: boolean\r\n login: (user: UserInfo) => void\r\n logout: () => void\r\n updateUser: (userData: Partial<UserInfo>) => void\r\n}\r\n\r\n// 사용자 스토어 생성 (지속성 포함)\r\nexport const useUserStore = create<UserStore>()(\r\n persist(\r\n (set, get) => ({\r\n user: null,\r\n isLoggedIn: false,\r\n\r\n // 로그인\r\n login: (user: UserInfo) => {\r\n set({ user, isLoggedIn: true })\r\n console.log('사용자 로그인:', user)\r\n },\r\n\r\n // 로그아웃\r\n logout: () => {\r\n set({ user: null, isLoggedIn: false })\r\n console.log('사용자 로그아웃')\r\n },\r\n\r\n // 사용자 정보 업데이트\r\n updateUser: (userData: Partial<UserInfo>) => {\r\n const currentUser = get().user\r\n if (currentUser) {\r\n set({ user: { ...currentUser, ...userData } })\r\n }\r\n }\r\n }),\r\n {\r\n name: 'user-storage', // 로컬 스토리지 키\r\n partialize: (state) => ({ \r\n user: state.user, \r\n isLoggedIn: state.isLoggedIn \r\n }) // 저장할 상태만 선택\r\n }\r\n )\r\n) ","import { useUserStore } from '../stores/userStore'\r\n\r\n/**\r\n * 사용자 정보 관련 유틸리티 함수들\r\n */\r\n\r\n// 회사정보 가져오기\r\nexport const getCrprCd = (): string | number | null => {\r\n const user = useUserStore.getState().user\r\n return user?.crprCd || null\r\n}\r\n\r\n// 사용자ID 가져오기\r\nexport const getUserId = (): string | null => {\r\n const user = useUserStore.getState().user\r\n return user?.userId || null\r\n}\r\n\r\n// 사용자명 가져오기\r\nexport const getUserNm = (): string | null => {\r\n const user = useUserStore.getState().user\r\n return user?.userNm || null\r\n}\r\n\r\n// 사용자구분 가져오기\r\nexport const getUserDvsn = (): string | null => {\r\n const user = useUserStore.getState().user\r\n return user?.userDvsn || null\r\n}\r\n\r\n// 사번 가져오기\r\nexport const getEmplNo = (): string | null => {\r\n const user = useUserStore.getState().user\r\n return user?.emplNo || null\r\n}\r\n\r\n// 부서코드 가져오기\r\nexport const getDprtCd = (): string | number | null => {\r\n const user = useUserStore.getState().user\r\n return user?.dprtCd || null\r\n}\r\n\r\n// 부서명 가져오기\r\nexport const getDprtNm = (): string | null => {\r\n const user = useUserStore.getState().user\r\n return user?.dprtNm || null\r\n}\r\n\r\n// 사용자 역할목록 가져오기\r\nexport const getRoleList = (): string[] | null => {\r\n const user = useUserStore.getState().user\r\n return user?.roleList || null\r\n}\r\n\r\n// 특정 역할이 있는지 확인\r\nexport const hasRole = (role: string): boolean => {\r\n const roleList = getRoleList()\r\n return roleList ? roleList.includes(role) : false\r\n}\r\n\r\n// 여러 역할 중 하나라도 있는지 확인\r\nexport const hasAnyRole = (roles: string[]): boolean => {\r\n const roleList = getRoleList()\r\n if (!roleList) return false\r\n return roles.some(role => roleList.includes(role))\r\n}\r\n\r\n// 모든 역할이 있는지 확인\r\nexport const hasAllRoles = (roles: string[]): boolean => {\r\n const roleList = getRoleList()\r\n if (!roleList) return false\r\n return roles.every(role => roleList.includes(role))\r\n}\r\n\r\n// 로그인 상태 확인\r\nexport const isLoggedIn = (): boolean => {\r\n return useUserStore.getState().isLoggedIn\r\n}\r\n\r\n// 전체 사용자 정보 가져오기\r\nexport const getUserInfo = () => {\r\n return useUserStore.getState().user\r\n}\r\n\r\n// 사용자 정보가 있는지 확인\r\nexport const hasUserInfo = (): boolean => {\r\n const user = getUserInfo()\r\n return user !== null\r\n}\r\n\r\n// 사용자 표시명 가져오기 (사용자명이 없으면 사용자ID 반환)\r\nexport const getDisplayName = (): string | null => {\r\n const userNm = getUserNm()\r\n const userId = getUserId()\r\n return userNm || userId || null\r\n}\r\n\r\n// 부서 정보 가져오기 (부서명이 있으면 부서명, 없으면 부서코드)\r\nexport const getDepartmentInfo = (): string | null => {\r\n const dprtNm = getDprtNm()\r\n const dprtCd = getDprtCd()\r\n return dprtNm || (dprtCd ? String(dprtCd) : null)\r\n} ","/**\r\n * 서비스코드 관리 유틸리티\r\n * Provider 패턴을 우선적으로 사용하고, 기본값을 fallback으로 사용\r\n */\r\n\r\n// 서비스코드 기본값 정의\r\nconst DEFAULT_SERVICE_CODES = {\r\n // 권한 관련\r\n AUTH_BTNS: 'SCMSIGN00202', // 버튼 권한 조회\r\n AUTH_MENU: 'SCMSIGN00201', // 메뉴 권한 조회\r\n SRCH_CODE: 'SCMSIGN00301', // 코드 조회\r\n \r\n // 팝업 관련\r\n SRCH_POPU: 'SCMPOPU00101', // 팝업 조회\r\n \r\n // 즐겨찾기 관련\r\n AUTH_BMRK: 'SCMBMRK00101', // 즐겨찾기 관리\r\n} as const;\r\n\r\ntype ServiceCodeKey = keyof typeof DEFAULT_SERVICE_CODES;\r\n\r\n// Provider에서 설정된 서비스코드 오버라이드를 저장할 모듈 스코프 변수\r\nlet serviceCodeOverrides: Partial<Record<ServiceCodeKey, string>> = {};\r\n\r\n/**\r\n * Provider에서 설정된 서비스코드 오버라이드를 설정하는 함수\r\n * ServiceCodeProvider에서 내부적으로 사용\r\n */\r\nexport function setServiceCodeOverrides(overrides: Partial<Record<ServiceCodeKey, string>>): void {\r\n serviceCodeOverrides = overrides;\r\n console.log('🔧 Provider 서비스코드 오버라이드 설정:', overrides);\r\n}\r\n\r\n/**\r\n * 서비스코드 값을 가져오는 함수\r\n * Provider 설정 > 기본값 순서로 우선순위 적용\r\n * @param serviceCodeKey 서비스코드 키\r\n * @returns 실제 서비스코드 값\r\n */\r\nexport function getServiceCode(serviceCodeKey: ServiceCodeKey): string {\r\n // 1. Provider에서 설정된 값 우선 확인\r\n if (serviceCodeOverrides[serviceCodeKey] && serviceCodeOverrides[serviceCodeKey]!.trim() !== '') {\r\n console.log(`🔧 Provider 설정 사용: ${serviceCodeKey} = ${serviceCodeOverrides[serviceCodeKey]}`);\r\n return serviceCodeOverrides[serviceCodeKey]!;\r\n }\r\n \r\n // 2. 기본값 사용\r\n const defaultValue = DEFAULT_SERVICE_CODES[serviceCodeKey];\r\n console.log(`🔧 기본값 사용: ${serviceCodeKey} = ${defaultValue}`);\r\n return defaultValue;\r\n}\r\n\r\n/**\r\n * 모든 서비스코드를 한 번에 가져오는 함수\r\n * @returns 모든 서비스코드 객체\r\n */\r\nexport function getAllServiceCodes(): Record<ServiceCodeKey, string> {\r\n const result = {} as Record<ServiceCodeKey, string>;\r\n \r\n for (const key of Object.keys(DEFAULT_SERVICE_CODES) as ServiceCodeKey[]) {\r\n result[key] = getServiceCode(key);\r\n }\r\n \r\n return result;\r\n}\r\n\r\n/**\r\n * 서비스코드 설정을 초기화하는 함수\r\n * 개발 시 설정 확인용\r\n */\r\nexport function logServiceCodeConfig(): void {\r\n console.log('🔧 bwg-core 서비스코드 설정:');\r\n console.log('📋 Provider 설정 > 기본값 순서로 확인');\r\n \r\n const allCodes = getAllServiceCodes();\r\n for (const [key, value] of Object.entries(allCodes)) {\r\n const source = serviceCodeOverrides[key as ServiceCodeKey] ? 'Provider 설정' : '기본값';\r\n console.log(` ${key}: ${value} (${source})`);\r\n }\r\n}\r\n\r\n// 타입 내보내기\r\nexport type { ServiceCodeKey };\r\n","import { create } from \"zustand\";\r\n// 필요에 맞게 경로 조정\r\nimport { callService } from \"@/utils/apiUtils\";\r\nimport { getServiceCode } from \"@/utils/serviceConfig\";\r\n\r\n/* ──── Constants ──── */\r\nconst MENU_CONSTANTS = {\r\n DEFAULT_ACTIVE_MENU: \"1\",\r\n DEFAULT_PRNT_GBCD: 1,\r\n COMPANY_CODE: \"100\",\r\n MENU_PARENT_ROOT: \"-\",\r\n MENU_TYPE: { MAIN: \"CMPRGRM\", SUB: \"CMPRGRS\", PROGRAM: \"CMPRGRP\" } as const,\r\n} as const;\r\n\r\n/* ──── Types (이 파일 전용) ──── */\r\nexport interface MenuItem {\r\n crprCd: string;\r\n menuGbCd: string;\r\n menuPrntId: string;\r\n menuId: string;\r\n menuNm: string;\r\n menuNo?: number;\r\n scrnId?: string;\r\n scrnPath?: string;\r\n prsnInfoYn?: \"Y\" | \"N\";\r\n rootMenu: string;\r\n iconCd?: string;\r\n children?: MenuItem[];\r\n}\r\n\r\nexport type FetchMenuParams = {\r\n crprCd: string;\r\n userId: string;\r\n prntGbcd: number;\r\n};\r\n\r\nexport interface MenuApiResponse {\r\n menus?: MenuItem[];\r\n [k: string]: any;\r\n}\r\n\r\n/* 런타임 타입가드 */\r\nconst isMenuItem = (v: any): v is MenuItem =>\r\n v &&\r\n typeof v === \"object\" &&\r\n typeof v.menuId === \"string\" &&\r\n typeof v.menuNm === \"string\" &&\r\n typeof v.crprCd === \"string\";\r\n\r\nconst isMenuItemArray = (v: any): v is MenuItem[] =>\r\n Array.isArray(v) && v.every(isMenuItem);\r\n\r\n/* ──── State Shape ──── */\r\ntype MenuModelState = {\r\n // 📊 State (상태)\r\n // 계층형 메뉴 트리 구조 (부모-자식 관계)\r\n menuList: MenuItem[];\r\n // 평면화된 메뉴 리스트 (검색/조회용)\r\n flatMenuList: MenuItem[];\r\n // 메뉴 데이터 로딩 상태\r\n isLoading: boolean;\r\n // 에러 메시지\r\n error: string | null;\r\n // 마지막 조회 파라미터 (중복 요청 방지)\r\n _lastFetchParams: FetchMenuParams | null;\r\n\r\n // 🔧 Actions (액션 함수들)\r\n // 서버에서 메뉴 데이터 조회\r\n fetchMenu: (p: FetchMenuParams) => Promise<void>;\r\n // 메뉴 데이터 초기화\r\n clearMenu: () => void;\r\n // 메뉴 ID로 특정 메뉴 찾기\r\n findMenuById: (menuId: string) => MenuItem | null;\r\n};\r\n\r\n/* ──── Local Memoization Cache ──── */\r\nlet _lastFlat: MenuItem[] = [];\r\nlet _cachedTree: MenuItem[] = [];\r\n\r\n/* ──── Helpers ──── */\r\nconst parseMenuResponse = (data: unknown): MenuItem[] => {\r\n if (data && typeof data === \"object\") {\r\n const r = data as MenuApiResponse;\r\n if (r.menus && isMenuItemArray(r.menus)) return r.menus;\r\n if (isMenuItemArray(data)) return data;\r\n }\r\n console.warn(\"⚠️ 메뉴 응답이 비어있거나 예상과 다릅니다.\");\r\n return [];\r\n};\r\n\r\nconst sameParams = (a: FetchMenuParams, b: FetchMenuParams | null) =>\r\n !!b &&\r\n a.crprCd === b.crprCd &&\r\n a.userId === b.userId &&\r\n (a.prntGbcd ?? MENU_CONSTANTS.DEFAULT_PRNT_GBCD) ===\r\n (b.prntGbcd ?? MENU_CONSTANTS.DEFAULT_PRNT_GBCD);\r\n\r\nconst buildHierarchy = (flat: MenuItem[]): MenuItem[] => {\r\n if (\r\n _lastFlat.length === flat.length &&\r\n _lastFlat.every(\r\n (x, i) =>\r\n x.menuId === flat[i]?.menuId && x.menuPrntId === flat[i]?.menuPrntId\r\n )\r\n )\r\n return _cachedTree;\r\n\r\n if (!flat.length) return [];\r\n\r\n const map = new Map<string, MenuItem>();\r\n const roots: MenuItem[] = [];\r\n\r\n flat.forEach((m) => m?.menuId && map.set(m.menuId, { ...m, children: [] }));\r\n flat.forEach((m) => {\r\n const cur = map.get(m.menuId);\r\n if (!cur) return;\r\n if (m.menuPrntId && m.menuPrntId !== \"\" && m.menuPrntId !== \"-\") {\r\n const p = map.get(m.menuPrntId);\r\n p?.children?.push(cur);\r\n } else {\r\n roots.push(cur);\r\n }\r\n });\r\n\r\n const sortRec = (arr: MenuItem[]): MenuItem[] =>\r\n arr\r\n .sort((a, b) => (a?.menuNo ?? 0) - (b?.menuNo ?? 0))\r\n .map((x) => ({\r\n ...x,\r\n children:\r\n x.children && x.children.length ? sortRec(x.children) : undefined,\r\n }));\r\n\r\n const out = sortRec(roots);\r\n _lastFlat = [...flat];\r\n _cachedTree = out;\r\n return out;\r\n};\r\n\r\n/* ──── Store ──── */\r\nexport const useMenuModelStore = create<MenuModelState>((set, get) => ({\r\n // 📊 초기 상태값\r\n menuList: [],\r\n flatMenuList: [],\r\n isLoading: false,\r\n error: null,\r\n _lastFetchParams: null,\r\n\r\n // 🔧 메뉴 모델 조회\r\n // 서버에서 사용자별 메뉴 권한 데이터를 가져와서 트리/플랫 구조로 저장\r\n fetchMenu: async ({ crprCd, userId, prntGbcd }: FetchMenuParams) => {\r\n const p = {\r\n crprCd,\r\n userId,\r\n prntGbcd: prntGbcd ?? MENU_CONSTANTS.DEFAULT_PRNT_GBCD,\r\n };\r\n // 중복 요청 방지\r\n if (sameParams(p, get()._lastFetchParams)) {\r\n console.log(\"✅ 중복 fetch 차단\", p);\r\n return;\r\n }\r\n set({ isLoading: true, error: null, _lastFetchParams: p });\r\n try {\r\n // API 호출하여 메뉴 데이터 가져오기\r\n const data = await callService(getServiceCode(\"AUTH_MENU\"), p);\r\n const flat = parseMenuResponse(data); // 응답 데이터 파싱\r\n const tree = buildHierarchy(flat); // 계층 구조 생성\r\n set({\r\n flatMenuList: flat, // 평면 리스트 저장\r\n menuList: tree, // 트리 구조 저장\r\n isLoading: false,\r\n error: null,\r\n });\r\n } catch (e: any) {\r\n set({ isLoading: false, error: e?.message ?? \"메뉴 로드 실패\" });\r\n }\r\n },\r\n\r\n // 🔧 메뉴 모델 초기화\r\n // 로그아웃 시나 사용자 변경 시 메뉴 모델 클리어\r\n clearMenu: () => {\r\n set({\r\n menuList: [],\r\n flatMenuList: [],\r\n error: null,\r\n _lastFetchParams: null,\r\n });\r\n },\r\n\r\n // 🔧 메뉴 ID로 메뉴 아이템 찾기\r\n // URL 파라미터나 프로그래밍 방식으로 특정 메뉴를 찾을 때 사용\r\n findMenuById: (menuId: string) => {\r\n const { flatMenuList } = get();\r\n return flatMenuList.find((m) => m.menuId === menuId) ?? null;\r\n },\r\n}));\r\n","import { message } from \"antd\";\r\nimport { create } from \"zustand\";\r\nimport { MenuItem, useMenuModelStore } from \"./menuModelStore\";\r\n\r\n/* ──── Constants (UI 측에도 독립적으로 존재) ──── */\r\nconst MENU_CONSTANTS = {\r\n DEFAULT_ACTIVE_MENU: \"1\",\r\n MAX_TABS: 15,\r\n} as const;\r\n\r\nexport interface ViewItem {\r\n viewId: string;\r\n viewLabel: string | React.ReactNode;\r\n viewParams?: Record<string, any>;\r\n prntInfo?:{\r\n menuId: string;\r\n menuNm: string;\r\n }\r\n}\r\n\r\n/* ──── Types (이 파일 전용) ──── */\r\nexport interface TabItem {\r\n key: string; // menuId\r\n label: string | React.ReactNode; // menuNm\r\n gubun: \"M\" | \"C\"; // menuId or componentPath\r\n menuItem?: MenuItem;\r\n componentItem?: {\r\n scrnPath: string;\r\n prsnInfoYn?: \"Y\" | \"N\";\r\n prntInfo?: {\r\n menuId: string;\r\n menuNm: string;\r\n };\r\n };\r\n closable: boolean;\r\n}\r\n\r\n\r\n/* ──── State Shape ──── */\r\ntype MenuViewState = {\r\n // 📊 UI State (화면 상태)\r\n // 현재 활성화된 메뉴 ID\r\n activeMenuId: string | undefined | null;\r\n // 현재 활성화된 메뉴 정보\r\n activeMenuItem: MenuItem | null;\r\n // 현재 활성화된 상세 정보\r\n activeDetailItem: ViewItem | null;\r\n // 열린 탭 목록\r\n tabs: TabItem[];\r\n // 사이드바 접힘/펼침 상태\r\n sidebarCollapsed: boolean;\r\n // 최대 탭 개수\r\n maxTabs: number;\r\n tabProtectFlag: Record<string, boolean>;\r\n // 탭 파라미터\r\n tabParams: Record<string, Record<string, any>>;\r\n // 컴포넌트 라벨 맵\r\n componentLabelMap: Record<string, string>;\r\n\r\n /* 🛠 UI Actions (UI 액션 함수들) */\r\n // 메뉴 아이템으로 탭 추가\r\n openTabFromMenu: (menuItem: MenuItem, params?: Record<string, any>) => void;\r\n // 메뉴 ID로 탭 추가 (URL 파라미터 처리용)\r\n openTabByMenuId: (menuId: string, params?: Record<string, any>) => void;\r\n /**\r\n * 상세 탭 추가\r\n * @param viewInfo 상세 컴포넌트 정보\r\n * @param scrnPath 상세 컴포넌트 경로\r\n * @returns \r\n * @description 상세 탭 추가\r\n */\r\n openDetailView: (viewInfo: ViewItem, scrnPath: string, prsnInfoYn?: \"Y\" | \"N\") => void;\r\n // 활성 탭 변경\r\n focusTab: (tabKey: string) => void;\r\n // 탭 제거\r\n closeTab: (tabKey: string) => void;\r\n // 모든 탭 제거\r\n closeAllTabs: () => void;\r\n // 사이드바 토글\r\n toggleSidebar: () => void;\r\n // 탭 순서 변경\r\n reorderTabs: (keys: string[]) => void;\r\n // 개인정보 포함여부에 따른 탭 잠금 Flag 설정\r\n setProtectFlagForKey: (key: string) => void;\r\n // 개인정보 포함여부에 따른 탭 잠금 해제\r\n clearProtectFlagForKey: (key: string) => void;\r\n // 탭 파라미터 설정\r\n setTabParams: (key: string, params: Record<string, any>) => void;\r\n //컴포넌트 라벨 맵 설정\r\n setComponentLabelMap: (map: Record<string, string>, merge?: boolean) => void;\r\n};\r\n\r\n/* ──── Store ──── */\r\nexport const useMenuViewStore = create<MenuViewState>((set, get) => ({\r\n // 📊 초기 상태값\r\n activeMenuId: null,\r\n activeMenuItem: null,\r\n activeDetailItem: null,\r\n tabs: [],\r\n sidebarCollapsed: false,\r\n maxTabs: MENU_CONSTANTS.MAX_TABS,\r\n tabProtectFlag: {},\r\n tabParams: {},\r\n componentLabelMap: {},\r\n // 🔧 탭 추가 (메뉴 아이템 객체로)\r\n // 사이드바에서 메뉴 클릭 시 호출되는 메인 함수\r\n openTabFromMenu: (menuItem, params) => {\r\n const { tabs, activeMenuId } = get();\r\n const exists = tabs.find((t) => t.key === menuItem.menuId);\r\n const findTab = tabs.find((t) => t.key === menuItem.menuId);\r\n\r\n // 새 탭 생성\r\n if (!exists) {\r\n // 2. 최대 탭 개수 확인\r\n if (tabs.length > MENU_CONSTANTS.MAX_TABS) {\r\n console.warn(\"❌ 최대 탭 개수를 초과했습니다.\");\r\n message.warning(\r\n `최대 ${MENU_CONSTANTS.MAX_TABS}개의 탭만 열 수 있습니다.\\n기존 탭을 닫고 다시 시도해주세요.`\r\n );\r\n return;\r\n }\r\n const newTab: TabItem = {\r\n key: menuItem.menuId,\r\n label: menuItem.menuNm,\r\n gubun: \"M\",\r\n menuItem: menuItem as MenuItem,\r\n closable: true,\r\n };\r\n set({\r\n tabs: [...tabs, newTab], // 탭 목록에 추가\r\n activeMenuId: menuItem.menuId, // 새 탭을 활성화\r\n activeMenuItem: menuItem, // 현재 프로그램으로 설정\r\n });\r\n get().setTabParams(menuItem.menuId, params || {});\r\n console.log(\"✅ 새 탭 추가 - activeMenuItem:\", menuItem);\r\n\r\n // 개인정보 메뉴만 Protect\r\n if (menuItem?.prsnInfoYn === \"Y\") {\r\n get().setProtectFlagForKey(menuItem.menuId);\r\n }\r\n } else if (findTab !== null && findTab !== undefined) {\r\n // 이미 존재하는 탭이면 활성화만\r\n set({ activeMenuId: menuItem.menuId, activeMenuItem: menuItem });\r\n console.log(\"✅ 기존 탭 활성화 - activeMenuItem:\", menuItem);\r\n get().setTabParams(menuItem.menuId, params || {});\r\n // 개인정보 메뉴만 Protect\r\n if (menuItem?.prsnInfoYn === \"Y\") {\r\n get().setProtectFlagForKey(menuItem.menuId);\r\n }\r\n } else {\r\n console.warn(\"❌ 유효하지 않은 메뉴정보\", menuItem.menuId);\r\n message.warning(\"유효하지 않은 메뉴정보입니다.\");\r\n }\r\n },\r\n // 🔧 탭 추가 (메뉴 ID로)\r\n // URL 파라미터로 메뉴 열기 시 사용 (예: ?menuId=CM000301)\r\n openTabByMenuId: (menuId, params) => {\r\n const target = useMenuModelStore.getState().findMenuById(menuId);\r\n if (!target) {\r\n console.warn(\"❌ 메뉴 ID를 찾을 수 없음:\", menuId);\r\n message.warning(\"메뉴 ID를 찾을 수 없습니다.\");\r\n } else {\r\n get().openTabFromMenu(target, params); // 찾은 메뉴로 탭 추가\r\n }\r\n },\r\n openDetailView: (viewInfo, scrnPath, prsnInfoYn) => {\r\n const { tabs, activeMenuId } = get();\r\n const exists = tabs.find((t) => t.key === viewInfo.viewId);\r\n \r\n if (!exists) {\r\n const newTab: TabItem = {\r\n key: viewInfo.viewId,\r\n label: viewInfo.viewLabel,\r\n gubun: \"C\",\r\n componentItem: {\r\n scrnPath: scrnPath,\r\n prsnInfoYn: prsnInfoYn,\r\n prntInfo: viewInfo.prntInfo,\r\n },\r\n closable: true,\r\n };\r\n set({\r\n tabs: [...tabs, newTab], // 탭 목록에 추가\r\n activeMenuId: viewInfo.viewId, // 새 탭을 활성화\r\n activeDetailItem: viewInfo,\r\n });\r\n get().setTabParams(viewInfo.viewId, viewInfo.viewParams || {});\r\n } else {\r\n get().focusTab(viewInfo.viewId);\r\n }\r\n },\r\n // 🔧 탭 제거\r\n // X 버튼 클릭 시 탭을 닫고 관련 상태도 정리\r\n closeTab: (tabKey) => {\r\n const { tabs, activeMenuId } = get();\r\n const removed = tabs.find((t) => t.key === tabKey);\r\n const nextTabs = tabs.filter((t) => t.key !== tabKey);\r\n\r\n // 닫힌 탭이 현재 활성 탭이면 다음 탭으로 이동\r\n let nextActive = activeMenuId;\r\n if (activeMenuId === tabKey) {\r\n const idx = tabs.findIndex((t) => t.key === tabKey);\r\n nextActive = nextTabs.length\r\n ? nextTabs[Math.min(idx, nextTabs.length - 1)]?.key ?? null\r\n : null;\r\n }\r\n\r\n set({\r\n tabs: nextTabs,\r\n });\r\n\r\n if (nextActive) get().focusTab(nextActive);\r\n },\r\n // 🔧 활성 탭 변경\r\n // 탭 헤더 클릭 시 해당 탭으로 전환\r\n focusTab: (tabKey) => {\r\n const { tabs } = get();\r\n const target = tabs.find((t) => t.key === tabKey);\r\n\r\n if (target) {\r\n // activeDetailItem 업데이트 (컴포넌트 탭인 경우)\r\n const activeDetailItem = target.gubun === \"C\" ? {\r\n viewId: target.key,\r\n viewLabel: target.label,\r\n prntInfo: target.componentItem?.prntInfo\r\n } : null;\r\n\r\n if (target.menuItem?.prsnInfoYn === \"Y\") {\r\n set({\r\n activeMenuId: tabKey,\r\n activeMenuItem: target.menuItem,\r\n activeDetailItem,\r\n });\r\n console.log(\r\n \"✅ 탭 포커스 (개인정보) - activeMenuItem:\",\r\n target.menuItem\r\n );\r\n get().setProtectFlagForKey(tabKey);\r\n } else {\r\n set({\r\n activeMenuId: tabKey,\r\n activeMenuItem: target.menuItem,\r\n activeDetailItem,\r\n });\r\n console.log(\"✅ 탭 포커스 (일반) - activeMenuItem:\", target.menuItem);\r\n get().clearProtectFlagForKey(tabKey);\r\n }\r\n } else {\r\n set({ activeMenuId: tabKey, activeMenuItem: null, activeDetailItem: null });\r\n console.warn(\"❌ 탭을 찾을 수 없음:\", tabKey);\r\n }\r\n },\r\n\r\n // 🔧 모든 탭 제거\r\n // 로그아웃이나 전체 초기화 시 사용\r\n closeAllTabs: () =>\r\n set({ tabs: [], activeMenuId: null, activeMenuItem: null, activeDetailItem: null }),\r\n\r\n // 🔧 사이드바 토글\r\n // 햄버거 메뉴 클릭 시 사이드바 접기/펼치기\r\n toggleSidebar: () => set((s) => ({ sidebarCollapsed: !s.sidebarCollapsed })),\r\n\r\n // useMenuViewStore.ts\r\n reorderTabs: (keys: string[]) =>\r\n set((state) => {\r\n const map = new Map(state.tabs.map((t) => [t.key, t]));\r\n return { tabs: keys.map((k) => map.get(k)!).filter(Boolean) };\r\n }),\r\n // 개인정보 포함여부에 따른 탭 잠금 Flag 설정\r\n setProtectFlagForKey: (key: string) =>\r\n set((s) => ({\r\n tabProtectFlag: { ...s.tabProtectFlag, [key]: true },\r\n })),\r\n // 개인정보 포함여부에 따른 탭 잠금 해제\r\n clearProtectFlagForKey: (key: string) =>\r\n set((s) => {\r\n const newFlags = { ...s.tabProtectFlag };\r\n delete newFlags[key];\r\n return { tabProtectFlag: newFlags };\r\n }),\r\n // 탭 파라미터 설정\r\n setTabParams: (key, params) =>\r\n set((state) => {\r\n const prev = state.tabParams[key] || {};\r\n const next = { ...(params || {}) }; // 새 객체 (불변 보장)\r\n\r\n // shallow equal이면 스킵(불필요 렌더 방지)\r\n const isShallowEqual =\r\n Object.keys(prev).length === Object.keys(next).length &&\r\n Object.keys(next).every((k) => prev[k] === next[k]);\r\n if (isShallowEqual) return state;\r\n\r\n return {\r\n tabParams: { ...state.tabParams, [key]: next },\r\n };\r\n }),\r\n // 컴포넌트 라벨 맵 설정\r\n setComponentLabelMap: (map: Record<string, string>, merge?: boolean) =>\r\n set({ componentLabelMap: map }),\r\n}));\r\n","import { create } from 'zustand';\r\n\r\ninterface LoadingState {\r\n requestCount: number;\r\n loading: boolean;\r\n showLoading: () => void;\r\n hideLoading: () => void;\r\n}\r\n\r\nexport const useLoadingStore = create<LoadingState>((set) => ({\r\n requestCount: 0,\r\n loading: false,\r\n showLoading: () =>\r\n set((state) => {\r\n const newCount = state.requestCount + 1;\r\n return { requestCount: newCount, loading: newCount > 0 };\r\n }),\r\n hideLoading: () =>\r\n set((state) => {\r\n const newCount = Math.max(0, state.requestCount - 1);\r\n return { requestCount: newCount, loading: newCount > 0 };\r\n }),\r\n}));\r\n","import axios, { AxiosError } from \"axios\";\r\nimport type { AxiosRequestConfig, AxiosResponse } from \"axios\";\r\nimport { generateGUIDWithoutHyphens, bxmEncrypt } from \"./stringUtils\";\r\nimport { showBwgError, showInfo, showWarning } from \"./notificationUtils\";\r\nimport { getUserInfo } from \"./userUtils\";\r\nimport { getEnvCode, isLocal } from \"./envUtils\";\r\nimport { useLoadingStore, useMenuViewStore } from \"@/stores\";\r\n\r\n// 클라이언트 IP 저장 변수 (읽기 전용)\r\nlet clientIp: string | null = null;\r\n\r\n/**\r\n * 클라이언트 IP 설정 (초기화 시에만 사용)\r\n * @param ip - 클라이언트 IP 주소\r\n */\r\nexport const setClientIp = async (ip?: string): Promise<void> => {\r\n // 이미 설정된 경우 재설정 방지\r\n if (clientIp !== null) {\r\n return;\r\n }\r\n\r\n if (ip === undefined) {\r\n try {\r\n //ip가 널로 드러왔을경우 기존 /api/ip를 통해 ip입력\r\n const res = await axios.get(\"/api/ip\");\r\n let ipAddr: string = res.data.trim();\r\n // 모든 공백 문자 제거 (공백, 탭, 줄바꿈 등)\r\n ipAddr = ipAddr.replace(/\\s+/g, \"\");\r\n clientIp = ipAddr;\r\n } catch (error) {\r\n console.warn(\"IP 가져오기 실패:\", error);\r\n // IP 가져오기 실패해도 기본값 설정\r\n clientIp = \"unknown\";\r\n }\r\n } else {\r\n clientIp = ip;\r\n }\r\n};\r\n\r\n/**\r\n * 클라이언트 IP 가져오기 (읽기 전용)\r\n * @returns 클라이언트 IP 주소 또는 null\r\n */\r\nexport const getClientIp = (): string | null => {\r\n return clientIp;\r\n};\r\n\r\n/**\r\n * 서버에서 실제 클라이언트 IP 확인 (보안 강화)\r\n * @returns Promise<string> - 서버가 확인한 실제 IP\r\n */\r\nexport const verifyClientIp = async (): Promise<string> => {\r\n // IP 검증 비활성화 (성능 최적화)\r\n console.log(\"IP 검증 비활성화됨 (성능 최적화)\");\r\n return clientIp || \"unknown\";\r\n\r\n // 아래 코드는 주석 처리 (필요시 활성화)\r\n /*\r\n try {\r\n const response = await axios.get('/api/ip', {\r\n headers: {\r\n 'Cache-Control': 'no-cache',\r\n Pragma: 'no-cache',\r\n },\r\n });\r\n\r\n let serverIp = response.data.trim().replace(/\\s+/g, '');\r\n\r\n // 클라이언트 IP와 서버 IP 비교\r\n if (clientIp && clientIp !== serverIp) {\r\n console.warn('⚠️ IP 불일치 감지:', {\r\n client: clientIp,\r\n server: serverIp,\r\n });\r\n }\r\n\r\n return serverIp;\r\n } catch (error) {\r\n console.error('IP 확인 실패:', error);\r\n return clientIp || 'unknown';\r\n }\r\n */\r\n};\r\n\r\n// API 응답 타입 정의\r\nexport interface ApiResponse<T = any> {\r\n success: boolean;\r\n data?: T;\r\n message?: string;\r\n error?: string;\r\n code?: number;\r\n}\r\n\r\n// API 요청 옵션 타입 정의\r\nexport interface ApiOptions {\r\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\r\n headers?: Record<string, string>;\r\n timeout?: number;\r\n withCredentials?: boolean;\r\n params?: Record<string, any>;\r\n data?: any;\r\n showLoading?: boolean;\r\n showError?: boolean;\r\n retryCount?: number;\r\n retryDelay?: number;\r\n}\r\n\r\n/**\r\n * 사용자 정의 API 에러 클래스\r\n * @param {string} message - 기본 에러 메시지 (basicMsg)\r\n * @param {string} detailMsg - 상세 에러 메시지 (detailMsgs)\r\n * @param {AxiosResponse} [response] - Axios 응답 객체 (선택 사항)\r\n * @param {string} [msgCd] - 서버 메시지 코드 (선택 사항)\r\n */\r\nexport class ApiError extends Error {\r\n detailMsg: string;\r\n response?: AxiosResponse;\r\n msgCd?: string;\r\n errorType?: string;\r\n\r\n constructor(\r\n message: string,\r\n detailMsg: string,\r\n response?: AxiosResponse,\r\n msgCd?: string,\r\n errorType?: string\r\n ) {\r\n super(message);\r\n this.name = \"ApiError\";\r\n this.detailMsg = detailMsg;\r\n this.response = response;\r\n this.msgCd = msgCd;\r\n this.errorType = errorType;\r\n\r\n // 스택 트레이스 복원 (V8 엔진 환경 등)\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, ApiError);\r\n }\r\n }\r\n}\r\n\r\n// 기본 설정\r\nconst DEFAULT_OPTIONS: ApiOptions = {\r\n method: \"POST\",\r\n timeout: 30000, // 30초\r\n withCredentials: true, // 쿠키 포함\r\n showLoading: true,\r\n showError: true,\r\n retryCount: 0,\r\n retryDelay: 1000,\r\n};\r\n\r\n// axios 인스턴스 생성\r\nconst apiClient = axios.create({\r\n timeout: DEFAULT_OPTIONS.timeout,\r\n withCredentials: DEFAULT_OPTIONS.withCredentials,\r\n headers: {\r\n \"Content-Type\": \"application/json; charset=utf-8\",\r\n Accept: \"application/json; charset=utf-8\",\r\n },\r\n});\r\n\r\n// 요청 인터셉터\r\napiClient.interceptors.request.use(\r\n (config) => {\r\n // showLoading 옵션이 true일 경우 로딩 표시\r\n if ((config as any).showLoading) {\r\n useLoadingStore.getState().showLoading();\r\n }\r\n\r\n // trxCd와 guid 추출 (requestData에서)\r\n let trxCd = \"UNKNOWN\";\r\n let guid = \"UNKNOWN\";\r\n const requestTime = new Date().getTime();\r\n\r\n try {\r\n if (config.data && config.data.header) {\r\n trxCd = config.data.header.trxCd || \"UNKNOWN\";\r\n guid = config.data.header.guid || \"UNKNOWN\";\r\n } else if (config.params && config.params.header) {\r\n trxCd = config.params.header.trxCd || \"UNKNOWN\";\r\n guid = config.params.header.guid || \"UNKNOWN\";\r\n }\r\n } catch (error) {\r\n console.warn(\"trxCd/guid 추출 실패:\", error);\r\n }\r\n\r\n // trxCd, guid와 요청 시작 시간을 config에 저장 (응답 인터셉터에서 사용)\r\n (config as any).trxCd = trxCd;\r\n (config as any).guid = guid;\r\n (config as any).requestStartTime = Date.now();\r\n\r\n // 로딩 표시\r\n console.log(`🚀 API 요청 시작 [거래코드: ${trxCd} / GUID: ${guid}]`);\r\n\r\n // 토큰이 있다면 헤더에 추가\r\n const token = localStorage.getItem(\"accessToken\");\r\n if (token) {\r\n config.headers.Authorization = `Bearer ${token}`;\r\n }\r\n\r\n // UTF-8 인코딩 명시적 설정\r\n config.headers[\"Content-Type\"] = \"application/json; charset=UTF-8\";\r\n config.headers[\"Accept\"] = \"application/json; charset=UTF-8\";\r\n\r\n return config;\r\n },\r\n (error) => {\r\n console.error(\"❌ 요청 인터셉터 에러:\", error);\r\n return Promise.reject(error);\r\n }\r\n);\r\n\r\n// 응답 인터셉터\r\napiClient.interceptors.response.use(\r\n (response: AxiosResponse) => {\r\n // showLoading 옵션이 true였던 요청에 대해 로딩 숨김\r\n if ((response.config as any).showLoading) {\r\n useLoadingStore.getState().hideLoading();\r\n }\r\n\r\n // trxCd와 guid 추출 (요청 시 저장된 값 사용)\r\n let trxCd = \"UNKNOWN\";\r\n let guid = \"UNKNOWN\";\r\n const responseTime = new Date().getTime();\r\n\r\n try {\r\n // 요청 시 저장된 trxCd와 guid 사용\r\n if ((response.config as any).trxCd) {\r\n trxCd = (response.config as any).trxCd;\r\n }\r\n if ((response.config as any).guid) {\r\n guid = (response.config as any).guid;\r\n }\r\n // 응답 데이터에서도 확인\r\n else if (\r\n response.data &&\r\n response.data.header &&\r\n response.data.header.trxCd\r\n ) {\r\n trxCd = response.data.header.trxCd;\r\n guid = response.data.header.guid || \"UNKNOWN\";\r\n }\r\n // 요청 설정에서도 확인\r\n else if (response.config.data && response.config.data.header) {\r\n trxCd = response.config.data.header.trxCd || \"UNKNOWN\";\r\n guid = response.config.data.header.guid || \"UNKNOWN\";\r\n } else if (response.config.params && response.config.params.header) {\r\n trxCd = response.config.params.header.trxCd || \"UNKNOWN\";\r\n guid = response.config.params.header.guid || \"UNKNOWN\";\r\n }\r\n } catch (error) {\r\n console.warn(\"trxCd/guid 추출 실패:\", error);\r\n }\r\n\r\n // 소요 시간 계산\r\n let duration = 0;\r\n if ((response.config as any).requestStartTime) {\r\n duration = responseTime - (response.config as any).requestStartTime;\r\n }\r\n\r\n // 로딩 숨김\r\n console.log(\r\n `✅ API 응답 성공 [거래코드: ${trxCd} / GUID : ${guid}] - (소요시간: ${duration}ms)`\r\n );\r\n\r\n return response;\r\n },\r\n async (error: AxiosError) => {\r\n // showLoading 옵션이 true였던 요청에 대해 로딩 숨김 (에러 발생 시)\r\n if (error.config && (error.config as any).showLoading) {\r\n useLoadingStore.getState().hideLoading();\r\n }\r\n\r\n console.error(\"❌ API 응답 에러:\", error);\r\n\r\n // 개발 환경에서 에러 정보 출력\r\n if (isLocal) {\r\n console.error(\"🚨 Error Details:\", {\r\n message: error.message,\r\n status: error.response?.status,\r\n statusText: error.response?.statusText,\r\n data: error.response?.data,\r\n config: {\r\n url: error.config?.url,\r\n method: error.config?.method,\r\n baseURL: error.config?.baseURL,\r\n },\r\n });\r\n }\r\n\r\n // 401 에러 시 토큰 갱신 시도\r\n if (error.response?.status === 401) {\r\n const refreshToken = localStorage.getItem(\"refreshToken\");\r\n if (refreshToken) {\r\n try {\r\n const refreshResponse = await axios.post(\"/auth/refresh\", {\r\n refreshToken,\r\n });\r\n\r\n if (refreshResponse.data.accessToken) {\r\n localStorage.setItem(\r\n \"accessToken\",\r\n refreshResponse.data.accessToken\r\n );\r\n\r\n // 원래 요청 재시도\r\n const originalRequest = error.config;\r\n if (originalRequest) {\r\n originalRequest.headers.Authorization = `Bearer ${refreshResponse.data.accessToken}`;\r\n return apiClient(originalRequest);\r\n }\r\n }\r\n } catch (refreshError) {\r\n // 토큰 갱신 실패 시 로그아웃\r\n localStorage.removeItem(\"accessToken\");\r\n localStorage.removeItem(\"refreshToken\");\r\n window.location.href = \"/login\";\r\n }\r\n }\r\n }\r\n\r\n return Promise.reject(error);\r\n }\r\n);\r\n\r\n/**\r\n * GUID 생성 함수 (API 요청용)\r\n * @returns 하이픈이 제거된 GUID\r\n */\r\nexport const getGuid = (): string => {\r\n return generateGUIDWithoutHyphens();\r\n};\r\n\r\n/**\r\n * Tomcat WAS와 통신하는 범용 API 호출 함수\r\n * @param trxCd - 거래코드드\r\n * @param data - 요청 데이터 (GET 요청 시 params로 사용)\r\n * @param options - 옵션 파라미터 (선택사항)\r\n * @returns Promise<ApiResponse<T>>\r\n */\r\nexport const callService = async <T = any>(\r\n trxCd: string,\r\n data?: any,\r\n options?: ApiOptions\r\n): Promise<T> => {\r\n try {\r\n // 옵션 병합\r\n const mergedOptions: ApiOptions = {\r\n ...DEFAULT_OPTIONS,\r\n ...options,\r\n };\r\n\r\n //로드된 메뉴ID조회\r\n const { activeMenuId } = useMenuViewStore.getState();\r\n\r\n //ip가 없을경우 ip값 할당\r\n if (clientIp === null) {\r\n const ipStartTime = Date.now();\r\n await setClientIp();\r\n const ipEndTime = Date.now();\r\n console.log(`[INFO] IP 조회 소요시간: ${ipEndTime - ipStartTime}ms`);\r\n }\r\n\r\n // 요청 설정\r\n const config: AxiosRequestConfig & { showLoading?: boolean } = {\r\n method: mergedOptions.method,\r\n url: \"/api/service\",\r\n timeout: mergedOptions.timeout,\r\n withCredentials: mergedOptions.withCredentials,\r\n showLoading: mergedOptions.showLoading,\r\n };\r\n\r\n // 헤더 설정\r\n if (mergedOptions.headers) {\r\n config.headers = mergedOptions.headers;\r\n }\r\n\r\n // IP가 설정되지 않은 경우 기본값 사용 (추가 IP 호출 방지)\r\n const currentClientIp = clientIp || \"unknown\";\r\n\r\n // vite.config.ts에서 define으로 주입된 전역 변수를 사용합니다.\r\n // @ts-ignore - __APP_CD__는 Vite에 의해 빌드 시점에 주입되는 전역 변수입니다.\r\n const appCd = __APP_CD__;\r\n const sysCd = __SYS_CD__;\r\n\r\n const requestData = {\r\n header: {\r\n trxCd: trxCd,\r\n guid: getGuid(),\r\n userInfo: getUserInfo(),\r\n clientIp: currentClientIp, // 클라이언트 IP 추가 (서버에서 재확인 권장)\r\n domainId: \"DEFAULT\",\r\n appCd,\r\n sysCd,\r\n screenId: activeMenuId,\r\n },\r\n // data: bxmEncrypt(JSON.stringify(data)),\r\n data: data,\r\n };\r\n\r\n // 개발 환경에서 요청 정보 출력\r\n if (isLocal) {\r\n console.log(\"__BWG_LOCAL__ 테스트 입니다. \", isLocal);\r\n }\r\n\r\n // HTTP 메서드에 따른 데이터 설정\r\n if (mergedOptions.method === \"GET\") {\r\n config.params = requestData || mergedOptions.params;\r\n } else {\r\n config.data = requestData || mergedOptions.data;\r\n if (mergedOptions.params) {\r\n config.params = mergedOptions.params;\r\n }\r\n }\r\n\r\n // 재시도 로직\r\n let lastError: Error | undefined;\r\n for (\r\n let attempt = 0;\r\n attempt <= (mergedOptions.retryCount || 0);\r\n attempt++\r\n ) {\r\n try {\r\n const response = await apiClient(config);\r\n\r\n // 성공 응답 처리\r\n if (response.data.header?.resCd == 0) {\r\n // resCd가 0인 경우, header를 제외한 데이터 반환\r\n for (const key in response.data) {\r\n if (key !== \"header\") {\r\n return response.data[key];\r\n }\r\n }\r\n // 데이터 필드가 없는 성공 응답의 경우, 빈 객체를 반환\r\n return {} as T;\r\n } else {\r\n // 실패 시 에러 생성 및 throw (비즈니스 에러)\r\n const header = response.data.header;\r\n const basicMsg =\r\n header?.msgs?.basicMsg || \"요청 처리 중 오류가 발생했습니다.\";\r\n const detailMsg = header?.msgs?.detailMsgs || basicMsg;\r\n const msgCd = header?.msgCd;\r\n const errorType = header?.msgs?.type;\r\n\r\n // ApiError를 생성하여 throw\r\n throw new ApiError(basicMsg, detailMsg, response, msgCd, errorType);\r\n }\r\n } catch (error) {\r\n // Axios 에러이고, 서버 응답이 있는 경우 (e.g., 500 에러)\r\n if (\r\n (error as AxiosError).isAxiosError &&\r\n (error as AxiosError).response\r\n ) {\r\n const axiosError = error as AxiosError;\r\n const response = axiosError.response!;\r\n const responseData = response.data as any;\r\n\r\n // 서버 응답 본문에서 메시지 추출 시도\r\n const basicMsg =\r\n responseData?.header?.msgs?.basicMsg ||\r\n axiosError.message || // 실패 시 Axios 에러 메시지 사용\r\n \"서버에서 오류가 발생했습니다.\";\r\n const detailMsg =\r\n responseData?.header?.msgs?.detailMsgs ||\r\n // 상세 메시지로 응답 본문 제공 (문자열이 아니면 JSON으로 변환)\r\n (typeof response.data === \"string\"\r\n ? response.data\r\n : JSON.stringify(response.data)) ||\r\n basicMsg;\r\n const msgCd = responseData?.header?.msgCd;\r\n const errorType = responseData?.header?.msgs?.type;\r\n\r\n // AxiosError를 ApiError로 변환하여 lastError에 저장\r\n lastError = new ApiError(\r\n basicMsg,\r\n detailMsg,\r\n response,\r\n msgCd,\r\n errorType\r\n );\r\n } else {\r\n // 네트워크 에러 또는 try 블록에서 throw된 커스텀 에러(ApiError)\r\n lastError = error as Error;\r\n }\r\n\r\n // 재시도 로직\r\n if (\r\n (error as AxiosError).isAxiosError &&\r\n shouldRetry(error as AxiosError) &&\r\n attempt < (mergedOptions.retryCount || 0)\r\n ) {\r\n await delay(mergedOptions.retryDelay || 1000);\r\n continue;\r\n }\r\n\r\n // 재시도 불가능하거나 재시도 횟수 초과 시 루프 중단\r\n break;\r\n }\r\n }\r\n\r\n // 루프 종료 후 에러 처리 (lastError가 설정된 경우)\r\n if (lastError) {\r\n // 에러 표시 옵션이 활성화된 경우, 통합된 에러 메시지를 표시합니다.\r\n if (mergedOptions.showError) {\r\n const errorMessage =\r\n lastError instanceof ApiError\r\n ? lastError.message\r\n : \"요청 처리 중 오류가 발생했습니다.\";\r\n const errorCode =\r\n lastError instanceof ApiError\r\n ? lastError.msgCd\r\n : \"요청 처리 중 오류가 발생했습니다.\";\r\n const errorDescription =\r\n lastError instanceof ApiError\r\n ? lastError.detailMsg\r\n : lastError.message;\r\n const errorType =\r\n lastError instanceof ApiError ? lastError.errorType : \"\";\r\n\r\n if (errorCode?.startsWith(\"BXM\"))\r\n showBwgError({\r\n message: errorMessage,\r\n description: errorDescription,\r\n duration: 5,\r\n });\r\n else if (\"I\" == errorType) {\r\n showInfo(errorMessage, errorDescription, 5);\r\n } else {\r\n showWarning(errorMessage, errorDescription, 5);\r\n }\r\n }\r\n // 최종 에러를 호출자에게 throw합니다.\r\n throw lastError;\r\n }\r\n\r\n // 이 코드는 이론적으로 도달할 수 없지만, lastError가 없는 경우를 대비한 방어 코드입니다.\r\n throw new Error(\"알 수 없는 API 오류가 발생했습니다.\");\r\n } catch (error: any) {\r\n // 최종 에러 처리 및 전파\r\n // callService에서 발생하는 모든 에러는 ApiError 형태로 변환하여 throw합니다.\r\n console.error(\"callService 최종 에러:\", error);\r\n\r\n throw error;\r\n }\r\n};\r\n\r\n/**\r\n * 재시도 가능한 에러인지 확인\r\n */\r\nconst shouldRetry = (error: AxiosError): boolean => {\r\n // 네트워크 에러 또는 5xx 서버 에러만 재시도\r\n return (\r\n !error.response ||\r\n (error.response.status >= 500 && error.response.status < 600)\r\n );\r\n};\r\n\r\n/**\r\n * 지연 함수\r\n */\r\nconst delay = (ms: number): Promise<void> => {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n};\r\n\r\n/**\r\n * 에러 처리 함수\r\n */\r\nconst handleError = (\r\n error: AxiosError,\r\n showError: boolean = true\r\n): ApiResponse => {\r\n let errorMessage = \"알 수 없는 오류가 발생했습니다.\";\r\n let errorCode = 500;\r\n\r\n if (error.response) {\r\n // 서버 응답이 있는 경우\r\n errorCode = error.response.status;\r\n const responseData = error.response.data as any;\r\n\r\n errorMessage =\r\n responseData?.message ||\r\n responseData?.error ||\r\n getErrorMessage(errorCode);\r\n } else if (error.request) {\r\n // 요청은 보냈지만 응답이 없는 경우\r\n errorMessage = \"서버에 연결할 수 없습니다.\";\r\n errorCode = 0;\r\n } else {\r\n // 요청 설정 중 에러\r\n errorMessage = error.message || \"요청 설정 중 오류가 발생했습니다.\";\r\n }\r\n\r\n // 에러 메시지 표시 (옵션)\r\n if (showError) {\r\n console.error(`API 에러 [${errorCode}]: ${errorMessage}`);\r\n // 여기서 전역 에러 처리 (예: toast, alert 등)를 할 수 있습니다\r\n }\r\n\r\n return {\r\n success: false,\r\n error: errorMessage,\r\n code: errorCode,\r\n };\r\n};\r\n\r\n/**\r\n * HTTP 상태 코드별 에러 메시지\r\n */\r\nconst getErrorMessage = (statusCode: number): string => {\r\n const errorMessages: Record<number, string> = {\r\n 400: \"잘못된 요청입니다.\",\r\n 401: \"인증이 필요합니다.\",\r\n 403: \"접근이 거부되었습니다.\",\r\n 404: \"요청한 리소스를 찾을 수 없습니다.\",\r\n 405: \"허용되지 않는 메서드입니다.\",\r\n 408: \"요청 시간이 초과되었습니다.\",\r\n 409: \"요청이 충돌했습니다.\",\r\n 422: \"처리할 수 없는 엔티티입니다.\",\r\n 429: \"너무 많은 요청이 발생했습니다.\",\r\n 500: \"서버 내부 오류가 발생했습니다.\",\r\n 502: \"잘못된 게이트웨이입니다.\",\r\n 503: \"서비스를 사용할 수 없습니다.\",\r\n 504: \"게이트웨이 시간 초과입니다.\",\r\n };\r\n\r\n return errorMessages[statusCode] || \"알 수 없는 오류가 발생했습니다.\";\r\n};\r\n\r\n// 편의 함수들\r\nexport const apiGet = <T = any>(\r\n trxCd: string,\r\n params?: any,\r\n options?: ApiOptions\r\n): Promise<T> => {\r\n return callService<T>(trxCd, params, { ...options, method: \"GET\" });\r\n};\r\n\r\nexport const apiPost = <T = any>(\r\n trxCd: string,\r\n data?: any,\r\n options?: ApiOptions\r\n): Promise<T> => {\r\n return callService<T>(trxCd, data, { ...options, method: \"POST\" });\r\n};\r\n\r\nexport const apiPut = <T = any>(\r\n trxCd: string,\r\n data?: any,\r\n options?: ApiOptions\r\n): Promise<T> => {\r\n return callService<T>(trxCd, data, { ...options, method: \"PUT\" });\r\n};\r\n\r\nexport const apiDelete = <T = any>(\r\n trxCd: string,\r\n data?: any,\r\n options?: ApiOptions\r\n): Promise<T> => {\r\n return callService<T>(trxCd, data, { ...options, method: \"DELETE\" });\r\n};\r\n\r\nexport const apiPatch = <T = any>(\r\n trxCd: string,\r\n data?: any,\r\n options?: ApiOptions\r\n): Promise<T> => {\r\n return callService<T>(trxCd, data, { ...options, method: \"PATCH\" });\r\n};\r\n\r\n/**\r\n * 권한 확인 서비스\r\n * @param userId 사용자 ID\r\n * @param menuId 메뉴 ID\r\n * @param popupId 팝업 ID (선택사항)\r\n * @returns 권한 정보\r\n */\r\nexport const getPermissionService = async (\r\n userId: string,\r\n menuId: string,\r\n popupId?: string\r\n) => {\r\n try {\r\n const response = await fetch(\"/api/permissions\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n },\r\n body: JSON.stringify({\r\n userId,\r\n menuId,\r\n popupId,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`권한 확인 실패: ${response.status}`);\r\n }\r\n\r\n const data = await response.json();\r\n return data;\r\n } catch (error) {\r\n console.error(\"권한 확인 서비스 오류:\", error);\r\n throw error;\r\n }\r\n};\r\n\r\n/**\r\n * 권한 정보 타입\r\n */\r\nexport interface PermissionInfo {\r\n // 공통 권한 버튼들\r\n commonButtons: Array<{\r\n id: string;\r\n label: string;\r\n type: \"primary\" | \"default\" | \"dashed\" | \"link\" | \"text\";\r\n disabled?: boolean;\r\n visible?: boolean;\r\n }>;\r\n // 커스텀 버튼 그룹들\r\n customButtonGroups: {\r\n [groupId: string]: {\r\n [buttonId: string]: {\r\n label: string;\r\n type: \"primary\" | \"default\" | \"dashed\" | \"link\" | \"text\";\r\n disabled?: boolean;\r\n visible?: boolean;\r\n isHeader?: boolean;\r\n };\r\n };\r\n };\r\n // 전체 권한 여부\r\n hasAccess: boolean;\r\n // 에러 메시지\r\n errorMessage?: string;\r\n}\r\n"],"names":["isEmpty","str","isSafeEmpty","defaultValue","isNotEmpty","truncate","length","suffix","capitalize","capitalizeWords","word","toCamelCase","g","toSnakeCase","letter","toKebabCase","formatPhoneNumber","phone","match","isValidEmail","email","isValidUrl","url","extractNumbers","removeSpecialChars","removeHtmlTags","nl2br","br2nl","findPattern","pattern","matches","repeat","count","padLeft","char","padRight","center","padding","leftPadding","rightPadding","generateRandomString","chars","result","i","reverse","countChar","countWords","generateUUIDv4","c","generateUID","uidWithoutHyphens","generateShortUID","generateLongUID","generateNumericUID","generateAlphanumericUID","generateGUID","generateGUIDWithoutHyphens","generateTimestampUID","timestamp","random","generateCustomUID","charset","encryptSha256","data","shaBuffer","CryptoJS","getEncryptionKey","getEncryptionIV","bxmEncrypt","plainText","key","iv","error","bxmDecrypt","encryptedText","simpleEncrypt","secretKey","simpleDecrypt","md5Hash","text","sha256Hash","base64Encode","base64Decode","encodedText","DEFAULT_CONFIG","NotificationService","props","message","description","duration","placement","notification","notificationService","showBwgError","showSuccess","showInfo","showWarning","showError","destroyNotifications","closeNotification","createJSONStorage","getStorage","options","storage","name","_a","parse","str2","newValue","toThenable","fn","input","onFulfilled","_onRejected","e","_onFulfilled","onRejected","persistImpl","config","baseOptions","set","get","api","state","persistedState","currentState","hasHydrated","hydrationListeners","finishHydrationListeners","args","setItem","savedSetState","replace","configResult","stateFromStorage","hydrate","_b","cb","_a2","postRehydrationCallback","deserializedStorageValue","migration","migrationResult","migrated","migratedState","newOptions","persist","useUserStore","create","user","userData","currentUser","getCrprCd","getUserId","getUserNm","getUserDvsn","getEmplNo","getDprtCd","getDprtNm","getRoleList","hasRole","role","roleList","hasAnyRole","roles","hasAllRoles","isLoggedIn","getUserInfo","hasUserInfo","getDisplayName","userNm","userId","getDepartmentInfo","dprtNm","dprtCd","DEFAULT_SERVICE_CODES","serviceCodeOverrides","setServiceCodeOverrides","overrides","getServiceCode","serviceCodeKey","getAllServiceCodes","MENU_CONSTANTS","isMenuItem","v","isMenuItemArray","_lastFlat","_cachedTree","parseMenuResponse","sameParams","a","b","buildHierarchy","flat","x","map","roots","m","cur","sortRec","arr","out","useMenuModelStore","crprCd","prntGbcd","p","callService","tree","menuId","flatMenuList","useMenuViewStore","menuItem","params","tabs","activeMenuId","exists","t","findTab","newTab","target","viewInfo","scrnPath","prsnInfoYn","tabKey","nextTabs","nextActive","idx","activeDetailItem","s","keys","k","newFlags","prev","next","merge","useLoadingStore","newCount","clientIp","setClientIp","ip","ipAddr","axios","getClientIp","verifyClientIp","ApiError","detailMsg","response","msgCd","errorType","DEFAULT_OPTIONS","apiClient","trxCd","guid","token","responseTime","isLocal","refreshToken","refreshResponse","originalRequest","getGuid","mergedOptions","ipStartTime","ipEndTime","currentClientIp","appCd","sysCd","requestData","lastError","attempt","header","basicMsg","axiosError","responseData","shouldRetry","delay","errorMessage","errorCode","errorDescription","ms","resolve","apiGet","apiPost","apiPut","apiDelete","apiPatch"],"mappings":";;;;;AAOO,MAAMA,IAAU,CAACC,MAClB,OAAOA,KAAQ,WAAiB,CAACA,IAC9BA,EAAI,OAAO,WAAW,GASlBC,KAAc,CACzBD,GACAE,MAEOH,EAAQC,CAAG,IAAIE,IAAeF,KAAO,IAIjCG,KAAa,CAACH,MAClB,CAACD,EAAQC,CAAG,GAIRI,KAAW,CACtBJ,GACAK,GACAC,IAAiB,UAEbN,EAAI,UAAUK,IAAeL,IAC1BA,EAAI,UAAU,GAAGK,CAAM,IAAIC,GAIvBC,IAAa,CAACP,MACrBD,EAAQC,CAAG,IAAUA,IAClBA,EAAI,OAAO,CAAC,EAAE,gBAAgBA,EAAI,MAAM,CAAC,EAAE,YAAA,GAIvCQ,KAAkB,CAACR,MAC1BD,EAAQC,CAAG,IAAUA,IAClBA,EACJ,MAAM,GAAG,EACT,IAAI,CAACS,MAASF,EAAWE,CAAI,CAAC,EAC9B,KAAK,GAAG,GAIAC,KAAc,CAACV,MACnBA,EAAI,QAAQ,aAAa,CAACW,MAAMA,EAAE,CAAC,EAAE,aAAa,GAI9CC,KAAc,CAACZ,MACnBA,EAAI,QAAQ,UAAU,CAACa,MAAW,IAAIA,EAAO,YAAA,CAAa,EAAE,GAIxDC,KAAc,CAACd,MACnBA,EAAI,QAAQ,UAAU,CAACa,MAAW,IAAIA,EAAO,YAAA,CAAa,EAAE,GAIxDE,KAAoB,CAACC,MAA0B;AAE1D,QAAMC,IADUD,EAAM,QAAQ,OAAO,EAAE,EACjB,MAAM,yBAAyB;AACrD,SAAIC,IACK,GAAGA,EAAM,CAAC,CAAC,IAAIA,EAAM,CAAC,CAAC,IAAIA,EAAM,CAAC,CAAC,KAErCD;AACT,GAGaE,KAAe,CAACC,MACR,6BACD,KAAKA,CAAK,GAIjBC,KAAa,CAACC,MAAyB;AAClD,MAAI;AACF,eAAI,IAAIA,CAAG,GACJ;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF,GAGaC,KAAiB,CAACtB,MACtBA,EAAI,QAAQ,OAAO,EAAE,GAIjBuB,KAAqB,CAACvB,MAC1BA,EAAI,QAAQ,sBAAsB,EAAE,GAIhCwB,KAAiB,CAACxB,MACtBA,EAAI,QAAQ,YAAY,EAAE,GAItByB,KAAQ,CAACzB,MACbA,EAAI,QAAQ,OAAO,MAAM,GAIrB0B,KAAQ,CAAC1B,MACbA,EAAI,QAAQ,gBAAgB;AAAA,CAAI,GAI5B2B,KAAc,CAAC3B,GAAa4B,MAA8B;AACrE,QAAMC,IAAU7B,EAAI,MAAM4B,CAAO;AACjC,SAAOC,KAAoB,CAAA;AAC7B,GAGaC,KAAS,CAAC9B,GAAa+B,MAC3B/B,EAAI,OAAO+B,CAAK,GAIZC,KAAU,CACrBhC,GACAK,GACA4B,IAAe,QAERjC,EAAI,SAASK,GAAQ4B,CAAI,GAIrBC,KAAW,CACtBlC,GACAK,GACA4B,IAAe,QAERjC,EAAI,OAAOK,GAAQ4B,CAAI,GAInBE,KAAS,CACpBnC,GACAK,GACA4B,IAAe,QACJ;AACX,QAAMG,IAAU/B,IAASL,EAAI;AAC7B,MAAIoC,KAAW,EAAG,QAAOpC;AAEzB,QAAMqC,IAAc,KAAK,MAAMD,IAAU,CAAC,GACpCE,IAAeF,IAAUC;AAE/B,SAAOJ,EAAK,OAAOI,CAAW,IAAIrC,IAAMiC,EAAK,OAAOK,CAAY;AAClE,GAGaC,IAAuB,CAClClC,GACAmC,IAAgB,qEACL;AACX,MAAIC,IAAS;AACb,WAASC,IAAI,GAAGA,IAAIrC,GAAQqC;AAC1B,IAAAD,KAAUD,EAAM,OAAO,KAAK,MAAM,KAAK,OAAA,IAAWA,EAAM,MAAM,CAAC;AAEjE,SAAOC;AACT,GAGaE,KAAU,CAAC3C,MACfA,EAAI,MAAM,EAAE,EAAE,QAAA,EAAU,KAAK,EAAE,GAI3B4C,KAAY,CAAC5C,GAAaiC,OAC7BjC,EAAI,MAAM,IAAI,OAAOiC,GAAM,GAAG,CAAC,KAAK,CAAA,GAAI,QAIrCY,KAAa,CAAC7C,MAClBA,EAAI,KAAA,EAAO,MAAM,KAAK,EAAE,QAM3B8C,IAAiB,MACd,uCAAuC,QAAQ,SAAS,SAAUC,GAAG;AAC1E,QAAM,IAAK,KAAK,OAAA,IAAW,KAAM;AAEjC,UADUA,MAAM,MAAM,IAAK,IAAI,IAAO,GAC7B,SAAS,EAAE;AACtB,CAAC,GAQUC,IAAc,CAAC3C,IAAiB,OAAe;AAE1D,QAAM4C,IADOH,EAAA,EACkB,QAAQ,MAAM,EAAE;AAE/C,SAAIzC,KAAU,KAEV4C,IAAoBV,EAAqBlC,IAAS,IAAI,kBAAkB,IAGnE4C,EAAkB,UAAU,GAAG5C,CAAM;AAEhD,GAMa6C,KAAmB,MACvBF,EAAY,EAAE,GAOVG,KAAkB,MACtBH,EAAY,EAAE,GAQVI,KAAqB,CAAC/C,IAAiB,OAC3CkC,EAAqBlC,GAAQ,YAAY,GAQrCgD,KAA0B,CAAChD,IAAiB,OAChDkC,EAAqBlC,GAAQ,sCAAsC,GAO/DiD,IAAe,MACnBR,EAAA,GAOIS,IAA6B,MACjCD,EAAA,EAAe,QAAQ,MAAM,EAAE,GAO3BE,KAAuB,MAAc;AAChD,QAAMC,IAAY,KAAK,IAAA,EAAM,SAAS,EAAE,GAClCC,IAASnB,EAAqB,GAAG,kBAAkB;AACzD,SAAOkB,IAAYC;AACrB,GAQaC,KAAoB,CAC/B/B,GACAgC,IAAkB,2CAEXhC,EAAQ;AAAA,EAAQ;AAAA,EAAU,MAC/BgC,EAAQ,OAAO,KAAK,MAAM,KAAK,OAAA,IAAWA,EAAQ,MAAM,CAAC;AAAA,GAYhDC,KAAgB,CAACC,MAAiB;AAC7C,QAAMC,IAAYC,EAAS,OAAOF,CAAI;AAEtC,SADeE,EAAS,IAAI,OAAO,UAAUD,CAAS;AAExD,GAKME,IAAmB,MAChB,oCAMHC,IAAkB,MACf,oBAQIC,KAAa,CAACC,MAA8B;AACvD,MAAI,CAACA,EAAW,QAAO;AAEvB,MAAI;AAEF,UAAMC,IAAML,EAAS,IAAI,KAAK,MAAMC,GAAkB,GAChDK,IAAKN,EAAS,IAAI,KAAK,MAAME,GAAiB;AAOpD,WALcF,EAAS,IAAI,QAAQI,GAAWC,GAAK;AAAA,MACjD,IAAAC;AAAA,MACA,SAASN,EAAS,IAAI;AAAA,MACtB,MAAMA,EAAS,KAAK;AAAA,IAAA,CACrB,EACY,SAAA;AAAA,EACf,SAASO,GAAO;AACd,mBAAQ,MAAM,WAAWA,CAAK,GACvB;AAAA,EACT;AACF,GAOaC,KAAa,CAACC,MAAkC;AAC3D,MAAI,CAACA,EAAe,QAAO;AAE3B,MAAI;AAEF,UAAMJ,IAAML,EAAS,IAAI,KAAK,MAAMC,GAAkB,GAChDK,IAAKN,EAAS,IAAI,KAAK,MAAME,GAAiB;AAOpD,WALcF,EAAS,IAAI,QAAQS,GAAeJ,GAAK;AAAA,MACrD,IAAAC;AAAA,MACA,SAASN,EAAS,IAAI;AAAA,MACtB,MAAMA,EAAS,KAAK;AAAA,IAAA,CACrB,EACY,SAASA,EAAS,IAAI,IAAI;AAAA,EACzC,SAASO,GAAO;AACd,mBAAQ,MAAM,WAAWA,CAAK,GACvB;AAAA,EACT;AACF,GAQaG,KAAgB,CAC3BN,GACAO,MACW;AACX,MAAI,CAACP,EAAW,QAAO;AAEvB,MAAI;AACF,UAAMC,IAAMM,KAAaV,EAAA;AAEzB,WADcD,EAAS,IAAI,QAAQI,GAAWC,CAAG,EACpC,SAAA;AAAA,EACf,SAASE,GAAO;AACd,mBAAQ,MAAM,eAAeA,CAAK,GAC3B;AAAA,EACT;AACF,GAQaK,KAAgB,CAC3BH,GACAE,MACW;AACX,MAAI,CAACF,EAAe,QAAO;AAE3B,MAAI;AACF,UAAMJ,IAAMM,KAAaV,EAAA;AAEzB,WADcD,EAAS,IAAI,QAAQS,GAAeJ,CAAG,EACxC,SAASL,EAAS,IAAI,IAAI;AAAA,EACzC,SAASO,GAAO;AACd,mBAAQ,MAAM,eAAeA,CAAK,GAC3B;AAAA,EACT;AACF,GAOaM,KAAU,CAACC,MACjBA,IACEd,EAAS,IAAIc,CAAI,EAAE,SAAA,IADR,IASPC,KAAa,CAACD,MACpBA,IACEd,EAAS,OAAOc,CAAI,EAAE,SAAA,IADX,IASPE,KAAe,CAACF,MACtBA,IACEd,EAAS,IAAI,OAAO,UAAUA,EAAS,IAAI,KAAK,MAAMc,CAAI,CAAC,IADhD,IASPG,KAAe,CAACC,MAAgC;AAC3D,MAAI,CAACA,EAAa,QAAO;AACzB,MAAI;AACF,WAAOlB,EAAS,IAAI,OAAO,MAAMkB,CAAW,EAAE,SAASlB,EAAS,IAAI,IAAI;AAAA,EAC1E,SAASO,GAAO;AACd,mBAAQ,MAAM,kBAAkBA,CAAK,GAC9B;AAAA,EACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8CC9bMY,IAAiB;AAAA,EACrB,UAAU;AAAA;AAAA,EACV,WAAW;AAEb;AAGA,MAAMC,EAAoB;AAAA,EAGhB,cAAc;AAAA,EAEtB;AAAA,EAEA,OAAc,cAAmC;AAC/C,WAAKA,EAAoB,aACvBA,EAAoB,WAAW,IAAIA,EAAA,IAE9BA,EAAoB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMO,aAAaC,GAA4B;AAC9C,UAAM;AAAA,MACJ,SAAAC;AAAA,MACA,aAAAC;AAAA,MACA,UAAAC,IAAWL,EAAe;AAAA,MAC1B,WAAAM,IAAYN,EAAe;AAAA,IAAA,IACzBE;AAEJ,IAAAK,EAAa,MAAM;AAAA,MACjB,SAAS,GAAGJ,CAAO;AAAA,MACnB,aAAaC,KAAe;AAAA,MAC5B,UAAAC;AAAA,MACA,WAAAC;AAAA,MACA,OAAO;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB;AAAA,MAAA;AAAA,IACnB,CACD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,YACLH,GACAC,GACAC,GACM;AACN,IAAAE,EAAa,QAAQ;AAAA,MACnB,SAAS,GAAGJ,CAAO;AAAA,MACnB,aAAAC;AAAA,MACA,UAAUC,KAAYL,EAAe;AAAA,MACrC,WAAWA,EAAe;AAAA,IAAA,CAC3B;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,SACLG,GACAC,GACAC,GACM;AACN,IAAAE,EAAa,KAAK;AAAA,MAChB,SAAS,GAAGJ,CAAO;AAAA,MACnB,aAAAC;AAAA,MACA,UAAUC,KAAYL,EAAe;AAAA,MACrC,WAAWA,EAAe;AAAA,IAAA,CAC3B;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,YACLG,GACAC,GACAC,GACM;AACN,IAAAE,EAAa,QAAQ;AAAA,MACnB,SAAS,GAAGJ,CAAO;AAAA,MACnB,aAAAC;AAAA,MACA,UAAUC,KAAYL,EAAe;AAAA,MACrC,WAAWA,EAAe;AAAA,IAAA,CAC3B;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,UACLG,GACAC,GACAC,GACM;AACN,IAAAE,EAAa,MAAM;AAAA,MACjB,SAAS,GAAGJ,CAAO;AAAA,MACnB,aAAAC;AAAA,MACA,UAAUC,KAAYL,EAAe;AAAA,MACrC,WAAWA,EAAe;AAAA,IAAA,CAC3B;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,UAAgB;AACrB,IAAAO,EAAa,QAAA;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKO,MAAMrB,GAAmB;AAE9B,IAAAqB,EAAa,QAAA;AAAA,EACf;AACF;AAGO,MAAMC,IAAsBP,EAAoB,YAAA,GAG1CQ,KAAe,CAACP,MAA+B;AAC1D,EAAAM,EAAoB,aAAaN,CAAK;AACxC,GAEaQ,KAAc,CACzBP,GACAC,GACAC,MACS;AACT,EAAAG,EAAoB,YAAYL,GAASC,GAAaC,CAAQ;AAChE,GAEaM,KAAW,CACtBR,GACAC,GACAC,MACS;AACT,EAAAG,EAAoB,SAASL,GAASC,GAAaC,CAAQ;AAC7D,GAEaO,KAAc,CACzBT,GACAC,GACAC,MACS;AACT,EAAAG,EAAoB,YAAYL,GAASC,GAAaC,CAAQ;AAChE,GAEaQ,KAAY,CACvBV,GACAC,GACAC,MACS;AACT,EAAAG,EAAoB,UAAUL,GAASC,GAAaC,CAAQ;AAC9D,GAEaS,KAAuB,MAAY;AAC9C,EAAAN,EAAoB,QAAA;AACtB,GAEaO,KAAoB,CAAC7B,MAAsB;AACtD,EAAAsB,EAAoB,MAAMtB,CAAG;AAC/B;;ACwFA,SAAS8B,GAAkBC,GAAYC,GAAS;AAC9C,MAAIC;AACJ,MAAI;AACF,IAAAA,IAAUF,EAAA;AAAA,EACZ,QAAY;AACV;AAAA,EACF;AAmBA,SAlBuB;AAAA,IACrB,SAAS,CAACG,MAAS;AACjB,UAAIC;AACJ,YAAMC,IAAQ,CAACC,MACTA,MAAS,OACJ,OAEF,KAAK,MAAMA,GAAwB,MAAwB,GAE9D1G,KAAOwG,IAAKF,EAAQ,QAAQC,CAAI,MAAM,OAAOC,IAAK;AACxD,aAAIxG,aAAe,UACVA,EAAI,KAAKyG,CAAK,IAEhBA,EAAMzG,CAAG;AAAA,IAClB;AAAA,IACA,SAAS,CAACuG,GAAMI,MAAaL,EAAQ,QAAQC,GAAM,KAAK,UAAUI,GAA4B,MAAyB,CAAC;AAAA,IACxH,YAAY,CAACJ,MAASD,EAAQ,WAAWC,CAAI;AAAA,EAAA;AAGjD;AACA,MAAMK,IAAa,CAACC,MAAO,CAACC,MAAU;AACpC,MAAI;AACF,UAAMrE,IAASoE,EAAGC,CAAK;AACvB,WAAIrE,aAAkB,UACbA,IAEF;AAAA,MACL,KAAKsE,GAAa;AAChB,eAAOH,EAAWG,CAAW,EAAEtE,CAAM;AAAA,MACvC;AAAA,MACA,MAAMuE,GAAa;AACjB,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,EAEJ,SAASC,GAAG;AACV,WAAO;AAAA,MACL,KAAKC,GAAc;AACjB,eAAO;AAAA,MACT;AAAA,MACA,MAAMC,GAAY;AAChB,eAAOP,EAAWO,CAAU,EAAEF,CAAC;AAAA,MACjC;AAAA,IAAA;AAAA,EAEJ;AACF,GACMG,KAAc,CAACC,GAAQC,MAAgB,CAACC,GAAKC,GAAKC,MAAQ;AAC9D,MAAIpB,IAAU;AAAA,IACZ,SAASF,GAAkB,MAAM,YAAY;AAAA,IAC7C,YAAY,CAACuB,MAAUA;AAAA,IACvB,SAAS;AAAA,IACT,OAAO,CAACC,GAAgBC,OAAkB;AAAA,MACxC,GAAGA;AAAA,MACH,GAAGD;AAAA,IAAA;AAAA,IAEL,GAAGL;AAAA,EAAA,GAEDO,IAAc;AAClB,QAAMC,wBAAyC,IAAA,GACzCC,wBAA+C,IAAA;AACrD,MAAIzB,IAAUD,EAAQ;AACtB,MAAI,CAACC;AACH,WAAOe;AAAA,MACL,IAAIW,MAAS;AACX,gBAAQ;AAAA,UACN,uDAAuD3B,EAAQ,IAAI;AAAA,QAAA,GAErEkB,EAAI,GAAGS,CAAI;AAAA,MACb;AAAA,MACAR;AAAA,MACAC;AAAA,IAAA;AAGJ,QAAMQ,IAAU,MAAM;AACpB,UAAMP,IAAQrB,EAAQ,WAAW,EAAE,GAAGmB,EAAA,GAAO;AAC7C,WAAOlB,EAAQ,QAAQD,EAAQ,MAAM;AAAA,MACnC,OAAAqB;AAAA,MACA,SAASrB,EAAQ;AAAA,IAAA,CAClB;AAAA,EACH,GACM6B,IAAgBT,EAAI;AAC1B,EAAAA,EAAI,WAAW,CAACC,GAAOS,OACrBD,EAAcR,GAAOS,CAAO,GACrBF,EAAA;AAET,QAAMG,IAAef;AAAA,IACnB,IAAIW,OACFT,EAAI,GAAGS,CAAI,GACJC,EAAA;AAAA,IAETT;AAAA,IACAC;AAAA,EAAA;AAEF,EAAAA,EAAI,kBAAkB,MAAMW;AAC5B,MAAIC;AACJ,QAAMC,IAAU,MAAM;AACpB,QAAI9B,GAAI+B;AACR,QAAI,CAACjC,EAAS;AACd,IAAAuB,IAAc,IACdC,EAAmB,QAAQ,CAACU,MAAO;AACjC,UAAIC;AACJ,aAAOD,GAAIC,IAAMjB,EAAA,MAAU,OAAOiB,IAAML,CAAY;AAAA,IACtD,CAAC;AACD,UAAMM,MAA4BH,IAAKlC,EAAQ,uBAAuB,OAAO,SAASkC,EAAG,KAAKlC,IAAUG,IAAKgB,EAAA,MAAU,OAAOhB,IAAK4B,CAAY,MAAM;AACrJ,WAAOxB,EAAWN,EAAQ,QAAQ,KAAKA,CAAO,CAAC,EAAED,EAAQ,IAAI,EAAE,KAAK,CAACsC,MAA6B;AAChG,UAAIA;AACF,YAAI,OAAOA,EAAyB,WAAY,YAAYA,EAAyB,YAAYtC,EAAQ,SAAS;AAChH,cAAIA,EAAQ,SAAS;AACnB,kBAAMuC,IAAYvC,EAAQ;AAAA,cACxBsC,EAAyB;AAAA,cACzBA,EAAyB;AAAA,YAAA;AAE3B,mBAAIC,aAAqB,UAChBA,EAAU,KAAK,CAACnG,MAAW,CAAC,IAAMA,CAAM,CAAC,IAE3C,CAAC,IAAMmG,CAAS;AAAA,UACzB;AACA,kBAAQ;AAAA,YACN;AAAA,UAAA;AAAA,QAEJ;AACE,iBAAO,CAAC,IAAOD,EAAyB,KAAK;AAGjD,aAAO,CAAC,IAAO,MAAM;AAAA,IACvB,CAAC,EAAE,KAAK,CAACE,MAAoB;AAC3B,UAAIJ;AACJ,YAAM,CAACK,GAAUC,EAAa,IAAIF;AAMlC,UALAR,IAAmBhC,EAAQ;AAAA,QACzB0C;AAAA,SACCN,IAAMjB,QAAU,OAAOiB,IAAML;AAAA,MAAA,GAEhCb,EAAIc,GAAkB,EAAI,GACtBS;AACF,eAAOb,EAAA;AAAA,IAEX,CAAC,EAAE,KAAK,MAAM;AACZ,MAA2CS,IAAwBL,GAAkB,MAAM,GAC3FA,IAAmBb,EAAA,GACnBK,IAAc,IACdE,EAAyB,QAAQ,CAACS,MAAOA,EAAGH,CAAgB,CAAC;AAAA,IAC/D,CAAC,EAAE,MAAM,CAACpB,MAAM;AACd,MAA2CyB,IAAwB,QAAQzB,CAAC;AAAA,IAC9E,CAAC;AAAA,EACH;AACA,SAAAQ,EAAI,UAAU;AAAA,IACZ,YAAY,CAACuB,MAAe;AAC1B,MAAA3C,IAAU;AAAA,QACR,GAAGA;AAAA,QACH,GAAG2C;AAAA,MAAA,GAEDA,EAAW,YACb1C,IAAU0C,EAAW;AAAA,IAEzB;AAAA,IACA,cAAc,MAAM;AAClB,MAA2B1C,GAAQ,WAAWD,EAAQ,IAAI;AAAA,IAC5D;AAAA,IACA,YAAY,MAAMA;AAAA,IAClB,WAAW,MAAMiC,EAAA;AAAA,IACjB,aAAa,MAAMT;AAAA,IACnB,WAAW,CAACW,OACVV,EAAmB,IAAIU,CAAE,GAClB,MAAM;AACX,MAAAV,EAAmB,OAAOU,CAAE;AAAA,IAC9B;AAAA,IAEF,mBAAmB,CAACA,OAClBT,EAAyB,IAAIS,CAAE,GACxB,MAAM;AACX,MAAAT,EAAyB,OAAOS,CAAE;AAAA,IACpC;AAAA,EACF,GAEGnC,EAAQ,iBACXiC,EAAA,GAEKD,KAAoBD;AAC7B,GACMa,KAAU7B,IClbH8B,IAAeC,EAAA;AAAA,EAC1BF;AAAA,IACE,CAAC1B,GAAKC,OAAS;AAAA,MACb,MAAM;AAAA,MACN,YAAY;AAAA;AAAA,MAGZ,OAAO,CAAC4B,MAAmB;AACzB,QAAA7B,EAAI,EAAE,MAAA6B,GAAM,YAAY,GAAA,CAAM,GAC9B,QAAQ,IAAI,YAAYA,CAAI;AAAA,MAC9B;AAAA;AAAA,MAGA,QAAQ,MAAM;AACZ,QAAA7B,EAAI,EAAE,MAAM,MAAM,YAAY,IAAO,GACrC,QAAQ,IAAI,UAAU;AAAA,MACxB;AAAA;AAAA,MAGA,YAAY,CAAC8B,MAAgC;AAC3C,cAAMC,IAAc9B,IAAM;AAC1B,QAAI8B,KACF/B,EAAI,EAAE,MAAM,EAAE,GAAG+B,GAAa,GAAGD,EAAA,GAAY;AAAA,MAEjD;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,MAAM;AAAA;AAAA,MACN,YAAY,CAAC3B,OAAW;AAAA,QACtB,MAAMA,EAAM;AAAA,QACZ,YAAYA,EAAM;AAAA,MAAA;AAAA;AAAA,IACpB;AAAA,EACF;AAEJ,GCpDa6B,KAAY,MACVL,EAAa,SAAA,EAAW,MACxB,UAAU,MAIZM,KAAY,MACVN,EAAa,SAAA,EAAW,MACxB,UAAU,MAIZO,KAAY,MACVP,EAAa,SAAA,EAAW,MACxB,UAAU,MAIZQ,KAAc,MACZR,EAAa,SAAA,EAAW,MACxB,YAAY,MAIdS,KAAY,MACVT,EAAa,SAAA,EAAW,MACxB,UAAU,MAIZU,KAAY,MACVV,EAAa,SAAA,EAAW,MACxB,UAAU,MAIZW,KAAY,MACVX,EAAa,SAAA,EAAW,MACxB,UAAU,MAIZY,IAAc,MACZZ,EAAa,SAAA,EAAW,MACxB,YAAY,MAIda,KAAU,CAACC,MAA0B;AAChD,QAAMC,IAAWH,EAAA;AACjB,SAAOG,IAAWA,EAAS,SAASD,CAAI,IAAI;AAC9C,GAGaE,KAAa,CAACC,MAA6B;AACtD,QAAMF,IAAWH,EAAA;AACjB,SAAKG,IACEE,EAAM,KAAK,CAAAH,MAAQC,EAAS,SAASD,CAAI,CAAC,IAD3B;AAExB,GAGaI,KAAc,CAACD,MAA6B;AACvD,QAAMF,IAAWH,EAAA;AACjB,SAAKG,IACEE,EAAM,MAAM,CAAAH,MAAQC,EAAS,SAASD,CAAI,CAAC,IAD5B;AAExB,GAGaK,KAAa,MACjBnB,EAAa,WAAW,YAIpBoB,KAAc,MAClBpB,EAAa,WAAW,MAIpBqB,KAAc,MACZD,GAAA,MACG,MAILE,KAAiB,MAAqB;AACjD,QAAMC,IAAShB,GAAA,GACTiB,IAASlB,GAAA;AACf,SAAOiB,KAAUC,KAAU;AAC7B,GAGaC,KAAoB,MAAqB;AACpD,QAAMC,IAASf,GAAA,GACTgB,IAASjB,GAAA;AACf,SAAOgB,MAAWC,IAAS,OAAOA,CAAM,IAAI;AAC9C,GChGMC,KAAwB;AAAA;AAAA,EAE5B,WAAW;AAAA;AAAA,EACX,WAAW;AAAA;AAAA,EACX,WAAW;AAAA;AAAA;AAAA,EAGX,WAAW;AAAA;AAAA;AAAA,EAGX,WAAW;AAAA;AACb;AAKA,IAAIC,IAAgE,CAAA;AAM7D,SAASC,GAAwBC,GAA0D;AAChG,EAAAF,IAAuBE,GACvB,QAAQ,IAAI,+BAA+BA,CAAS;AACtD;AAQO,SAASC,GAAeC,GAAwC;AAErE,MAAIJ,EAAqBI,CAAc,KAAKJ,EAAqBI,CAAc,EAAG,KAAA,MAAW;AAC3F,mBAAQ,IAAI,sBAAsBA,CAAc,MAAMJ,EAAqBI,CAAc,CAAC,EAAE,GACrFJ,EAAqBI,CAAc;AAI5C,QAAMjL,IAAe4K,GAAsBK,CAAc;AACzD,iBAAQ,IAAI,cAAcA,CAAc,MAAMjL,CAAY,EAAE,GACrDA;AACT;AAMO,SAASkL,KAAqD;AACnE,QAAM3I,IAAS,CAAA;AAEf,aAAW4B,KAAO,OAAO,KAAKyG,EAAqB;AACjD,IAAArI,EAAO4B,CAAG,IAAI6G,GAAe7G,CAAG;AAGlC,SAAO5B;AACT;AC1DA,MAAM4I,IAAiB;AAAA,EAErB,mBAAmB;AAIrB,GA8BMC,KAAa,CAACC,MAClBA,KACA,OAAOA,KAAM,YACb,OAAOA,EAAE,UAAW,YACpB,OAAOA,EAAE,UAAW,YACpB,OAAOA,EAAE,UAAW,UAEhBC,IAAkB,CAACD,MACvB,MAAM,QAAQA,CAAC,KAAKA,EAAE,MAAMD,EAAU;AA0BxC,IAAIG,IAAwB,CAAA,GACxBC,IAA0B,CAAA;AAG9B,MAAMC,KAAoB,CAAC7H,MAA8B;AACvD,MAAIA,KAAQ,OAAOA,KAAS,UAAU;AACpC,UAAM,IAAIA;AACV,QAAI,EAAE,SAAS0H,EAAgB,EAAE,KAAK,UAAU,EAAE;AAClD,QAAIA,EAAgB1H,CAAI,EAAG,QAAOA;AAAA,EACpC;AACA,iBAAQ,KAAK,2BAA2B,GACjC,CAAA;AACT,GAEM8H,KAAa,CAACC,GAAoBC,MACtC,CAAC,CAACA,KACFD,EAAE,WAAWC,EAAE,UACfD,EAAE,WAAWC,EAAE,WACdD,EAAE,YAAYR,EAAe,wBAC3BS,EAAE,YAAYT,EAAe,oBAE5BU,KAAiB,CAACC,MAAiC;AACvD,MACEP,EAAU,WAAWO,EAAK,UAC1BP,EAAU;AAAA,IACR,CAACQ,GAAGvJ,MACFuJ,EAAE,WAAWD,EAAKtJ,CAAC,GAAG,UAAUuJ,EAAE,eAAeD,EAAKtJ,CAAC,GAAG;AAAA,EAAA;AAG9D,WAAOgJ;AAET,MAAI,CAACM,EAAK,OAAQ,QAAO,CAAA;AAEzB,QAAME,wBAAU,IAAA,GACVC,IAAoB,CAAA;AAE1B,EAAAH,EAAK,QAAQ,CAACI,MAAMA,GAAG,UAAUF,EAAI,IAAIE,EAAE,QAAQ,EAAE,GAAGA,GAAG,UAAU,CAAA,EAAC,CAAG,CAAC,GAC1EJ,EAAK,QAAQ,CAACI,MAAM;AAClB,UAAMC,IAAMH,EAAI,IAAIE,EAAE,MAAM;AAC5B,IAAKC,MACDD,EAAE,cAAcA,EAAE,eAAe,MAAMA,EAAE,eAAe,MAChDF,EAAI,IAAIE,EAAE,UAAU,GAC3B,UAAU,KAAKC,CAAG,IAErBF,EAAM,KAAKE,CAAG;AAAA,EAElB,CAAC;AAED,QAAMC,IAAU,CAACC,MACfA,EACG,KAAK,CAACV,GAAGC,OAAOD,GAAG,UAAU,MAAMC,GAAG,UAAU,EAAE,EAClD,IAAI,CAACG,OAAO;AAAA,IACX,GAAGA;AAAA,IACH,UACEA,EAAE,YAAYA,EAAE,SAAS,SAASK,EAAQL,EAAE,QAAQ,IAAI;AAAA,EAAA,EAC1D,GAEAO,IAAMF,EAAQH,CAAK;AACzB,SAAAV,IAAY,CAAC,GAAGO,CAAI,GACpBN,IAAcc,GACPA;AACT,GAGaC,KAAoBtD,EAAuB,CAAC5B,GAAKC,OAAS;AAAA;AAAA,EAErE,UAAU,CAAA;AAAA,EACV,cAAc,CAAA;AAAA,EACd,WAAW;AAAA,EACX,OAAO;AAAA,EACP,kBAAkB;AAAA;AAAA;AAAA,EAIlB,WAAW,OAAO,EAAE,QAAAkF,GAAQ,QAAAhC,GAAQ,UAAAiC,QAAgC;AAClE,UAAMC,IAAI;AAAA,MACR,QAAAF;AAAA,MACA,QAAAhC;AAAA,MACA,UAAUiC,KAAYtB,EAAe;AAAA,IAAA;AAGvC,QAAIO,GAAWgB,GAAGpF,EAAA,EAAM,gBAAgB,GAAG;AACzC,cAAQ,IAAI,iBAAiBoF,CAAC;AAC9B;AAAA,IACF;AACA,IAAArF,EAAI,EAAE,WAAW,IAAM,OAAO,MAAM,kBAAkBqF,GAAG;AACzD,QAAI;AAEF,YAAM9I,IAAO,MAAM+I,EAAY3B,GAAe,WAAW,GAAG0B,CAAC,GACvDZ,IAAOL,GAAkB7H,CAAI,GAC7BgJ,IAAOf,GAAeC,CAAI;AAChC,MAAAzE,EAAI;AAAA,QACF,cAAcyE;AAAA;AAAA,QACd,UAAUc;AAAA;AAAA,QACV,WAAW;AAAA,QACX,OAAO;AAAA,MAAA,CACR;AAAA,IACH,SAAS7F,GAAQ;AACf,MAAAM,EAAI,EAAE,WAAW,IAAO,OAAON,GAAG,WAAW,YAAY;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,WAAW,MAAM;AACf,IAAAM,EAAI;AAAA,MACF,UAAU,CAAA;AAAA,MACV,cAAc,CAAA;AAAA,MACd,OAAO;AAAA,MACP,kBAAkB;AAAA,IAAA,CACnB;AAAA,EACH;AAAA;AAAA;AAAA,EAIA,cAAc,CAACwF,MAAmB;AAChC,UAAM,EAAE,cAAAC,EAAA,IAAiBxF,EAAA;AACzB,WAAOwF,EAAa,KAAK,CAACZ,MAAMA,EAAE,WAAWW,CAAM,KAAK;AAAA,EAC1D;AACF,EAAE,GC9LI1B,IAAiB;AAAA,EAErB,UAAU;AACZ,GAqFa4B,KAAmB9D,EAAsB,CAAC5B,GAAKC,OAAS;AAAA;AAAA,EAEnE,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,MAAM,CAAA;AAAA,EACN,kBAAkB;AAAA,EAClB,SAAS6D,EAAe;AAAA,EACxB,gBAAgB,CAAA;AAAA,EAChB,WAAW,CAAA;AAAA,EACX,mBAAmB,CAAA;AAAA;AAAA;AAAA,EAGnB,iBAAiB,CAAC6B,GAAUC,MAAW;AACrC,UAAM,EAAE,MAAAC,GAAM,cAAAC,EAAA,IAAiB7F,EAAA,GACzB8F,IAASF,EAAK,KAAK,CAACG,MAAMA,EAAE,QAAQL,EAAS,MAAM,GACnDM,IAAUJ,EAAK,KAAK,CAACG,MAAMA,EAAE,QAAQL,EAAS,MAAM;AAG1D,QAAKI;AA4BL,MAAWE,KAAY,QAErBjG,EAAI,EAAE,cAAc2F,EAAS,QAAQ,gBAAgBA,GAAU,GAC/D,QAAQ,IAAI,gCAAgCA,CAAQ,GACpD1F,EAAA,EAAM,aAAa0F,EAAS,QAAQC,KAAU,CAAA,CAAE,GAE5CD,GAAU,eAAe,OAC3B1F,IAAM,qBAAqB0F,EAAS,MAAM,MAG5C,QAAQ,KAAK,kBAAkBA,EAAS,MAAM,GAC9C5H,EAAQ,QAAQ,kBAAkB;AAAA,SAvCvB;AAEX,UAAI8H,EAAK,SAAS/B,EAAe,UAAU;AACzC,gBAAQ,KAAK,oBAAoB,GACjC/F,EAAQ;AAAA,UACN,MAAM+F,EAAe,QAAQ;AAAA;AAAA,QAAA;AAE/B;AAAA,MACF;AACA,YAAMoC,IAAkB;AAAA,QACtB,KAAKP,EAAS;AAAA,QACd,OAAOA,EAAS;AAAA,QAChB,OAAO;AAAA,QACP,UAAAA;AAAA,QACA,UAAU;AAAA,MAAA;AAEZ,MAAA3F,EAAI;AAAA,QACF,MAAM,CAAC,GAAG6F,GAAMK,CAAM;AAAA;AAAA,QACtB,cAAcP,EAAS;AAAA;AAAA,QACvB,gBAAgBA;AAAA;AAAA,MAAA,CACjB,GACD1F,EAAA,EAAM,aAAa0F,EAAS,QAAQC,KAAU,CAAA,CAAE,GAChD,QAAQ,IAAI,8BAA8BD,CAAQ,GAG9CA,GAAU,eAAe,OAC3B1F,IAAM,qBAAqB0F,EAAS,MAAM;AAAA,IAE9C;AAAA,EAaF;AAAA;AAAA;AAAA,EAGA,iBAAiB,CAACH,GAAQI,MAAW;AACnC,UAAMO,IAASjB,GAAkB,SAAA,EAAW,aAAaM,CAAM;AAC/D,IAAKW,IAIHlG,IAAM,gBAAgBkG,GAAQP,CAAM,KAHpC,QAAQ,KAAK,qBAAqBJ,CAAM,GACxCzH,EAAQ,QAAQ,mBAAmB;AAAA,EAIrC;AAAA,EACA,gBAAgB,CAACqI,GAAUC,GAAUC,MAAe;AACpD,UAAM,EAAE,MAAAT,GAAM,cAAAC,EAAA,IAAiB7F,EAAA;AAG/B,QAFe4F,EAAK,KAAK,CAACG,MAAMA,EAAE,QAAQI,EAAS,MAAM;AAqBvD,MAAAnG,IAAM,SAASmG,EAAS,MAAM;AAAA,SAnBnB;AACX,YAAMF,IAAkB;AAAA,QACtB,KAAKE,EAAS;AAAA,QACd,OAAOA,EAAS;AAAA,QAChB,OAAO;AAAA,QACP,eAAe;AAAA,UACb,UAAAC;AAAA,UACA,YAAAC;AAAA,UACA,UAAUF,EAAS;AAAA,QAAA;AAAA,QAErB,UAAU;AAAA,MAAA;AAEZ,MAAApG,EAAI;AAAA,QACF,MAAM,CAAC,GAAG6F,GAAMK,CAAM;AAAA;AAAA,QACtB,cAAcE,EAAS;AAAA;AAAA,QACvB,kBAAkBA;AAAA,MAAA,CACnB,GACDnG,EAAA,EAAM,aAAamG,EAAS,QAAQA,EAAS,cAAc,EAAE;AAAA,IAC/D;AAAA,EAGF;AAAA;AAAA;AAAA,EAGA,UAAU,CAACG,MAAW;AACpB,UAAM,EAAE,MAAAV,GAAM,cAAAC,EAAA,IAAiB7F,EAAA;AACf,IAAA4F,EAAK,KAAK,CAACG,MAAMA,EAAE,QAAQO,CAAM;AACjD,UAAMC,IAAWX,EAAK,OAAO,CAACG,MAAMA,EAAE,QAAQO,CAAM;AAGpD,QAAIE,IAAaX;AACjB,QAAIA,MAAiBS,GAAQ;AAC3B,YAAMG,IAAMb,EAAK,UAAU,CAACG,MAAMA,EAAE,QAAQO,CAAM;AAClD,MAAAE,IAAaD,EAAS,SAClBA,EAAS,KAAK,IAAIE,GAAKF,EAAS,SAAS,CAAC,CAAC,GAAG,OAAO,OACrD;AAAA,IACN;AAEA,IAAAxG,EAAI;AAAA,MACF,MAAMwG;AAAA,IAAA,CACP,GAEGC,KAAYxG,IAAM,SAASwG,CAAU;AAAA,EAC3C;AAAA;AAAA;AAAA,EAGA,UAAU,CAACF,MAAW;AACpB,UAAM,EAAE,MAAAV,EAAA,IAAS5F,EAAA,GACXkG,IAASN,EAAK,KAAK,CAACG,MAAMA,EAAE,QAAQO,CAAM;AAEhD,QAAIJ,GAAQ;AAEV,YAAMQ,IAAmBR,EAAO,UAAU,MAAM;AAAA,QAC9C,QAAQA,EAAO;AAAA,QACf,WAAWA,EAAO;AAAA,QAClB,UAAUA,EAAO,eAAe;AAAA,MAAA,IAC9B;AAEJ,MAAIA,EAAO,UAAU,eAAe,OAClCnG,EAAI;AAAA,QACF,cAAcuG;AAAA,QACd,gBAAgBJ,EAAO;AAAA,QACvB,kBAAAQ;AAAA,MAAA,CACD,GACD,QAAQ;AAAA,QACN;AAAA,QACAR,EAAO;AAAA,MAAA,GAETlG,EAAA,EAAM,qBAAqBsG,CAAM,MAEjCvG,EAAI;AAAA,QACF,cAAcuG;AAAA,QACd,gBAAgBJ,EAAO;AAAA,QACvB,kBAAAQ;AAAA,MAAA,CACD,GACD,QAAQ,IAAI,kCAAkCR,EAAO,QAAQ,GAC7DlG,EAAA,EAAM,uBAAuBsG,CAAM;AAAA,IAEvC;AACE,MAAAvG,EAAI,EAAE,cAAcuG,GAAQ,gBAAgB,MAAM,kBAAkB,MAAM,GAC1E,QAAQ,KAAK,iBAAiBA,CAAM;AAAA,EAExC;AAAA;AAAA;AAAA,EAIA,cAAc,MACZvG,EAAI,EAAE,MAAM,CAAA,GAAI,cAAc,MAAM,gBAAgB,MAAM,kBAAkB,MAAM;AAAA;AAAA;AAAA,EAIpF,eAAe,MAAMA,EAAI,CAAC4G,OAAO,EAAE,kBAAkB,CAACA,EAAE,iBAAA,EAAmB;AAAA;AAAA,EAG3E,aAAa,CAACC,MACZ7G,EAAI,CAACG,MAAU;AACb,UAAMwE,IAAM,IAAI,IAAIxE,EAAM,KAAK,IAAI,CAAC6F,MAAM,CAACA,EAAE,KAAKA,CAAC,CAAC,CAAC;AACrD,WAAO,EAAE,MAAMa,EAAK,IAAI,CAACC,MAAMnC,EAAI,IAAImC,CAAC,CAAE,EAAE,OAAO,OAAO,EAAA;AAAA,EAC5D,CAAC;AAAA;AAAA,EAEH,sBAAsB,CAAChK,MACrBkD,EAAI,CAAC4G,OAAO;AAAA,IACV,gBAAgB,EAAE,GAAGA,EAAE,gBAAgB,CAAC9J,CAAG,GAAG,GAAA;AAAA,EAAK,EACnD;AAAA;AAAA,EAEJ,wBAAwB,CAACA,MACvBkD,EAAI,CAAC4G,MAAM;AACT,UAAMG,IAAW,EAAE,GAAGH,EAAE,eAAA;AACxB,kBAAOG,EAASjK,CAAG,GACZ,EAAE,gBAAgBiK,EAAA;AAAA,EAC3B,CAAC;AAAA;AAAA,EAEH,cAAc,CAACjK,GAAK8I,MAClB5F,EAAI,CAACG,MAAU;AACb,UAAM6G,IAAO7G,EAAM,UAAUrD,CAAG,KAAK,CAAA,GAC/BmK,IAAO,EAAE,GAAIrB,KAAU,GAAC;AAM9B,WAFE,OAAO,KAAKoB,CAAI,EAAE,WAAW,OAAO,KAAKC,CAAI,EAAE,UAC/C,OAAO,KAAKA,CAAI,EAAE,MAAM,CAACH,MAAME,EAAKF,CAAC,MAAMG,EAAKH,CAAC,CAAC,IACzB3G,IAEpB;AAAA,MACL,WAAW,EAAE,GAAGA,EAAM,WAAW,CAACrD,CAAG,GAAGmK,EAAA;AAAA,IAAK;AAAA,EAEjD,CAAC;AAAA;AAAA,EAEH,sBAAsB,CAACtC,GAA6BuC,MAClDlH,EAAI,EAAE,mBAAmB2E,GAAK;AAClC,EAAE,GClSWwC,IAAkBvF,EAAqB,CAAC5B,OAAS;AAAA,EAC5D,cAAc;AAAA,EACd,SAAS;AAAA,EACT,aAAa,MACXA,EAAI,CAACG,MAAU;AACb,UAAMiH,IAAWjH,EAAM,eAAe;AACtC,WAAO,EAAE,cAAciH,GAAU,SAASA,IAAW,EAAA;AAAA,EACvD,CAAC;AAAA,EACH,aAAa,MACXpH,EAAI,CAACG,MAAU;AACb,UAAMiH,IAAW,KAAK,IAAI,GAAGjH,EAAM,eAAe,CAAC;AACnD,WAAO,EAAE,cAAciH,GAAU,SAASA,IAAW,EAAA;AAAA,EACvD,CAAC;AACL,EAAE;ACbF,IAAIC,IAA0B;AAMvB,MAAMC,KAAc,OAAOC,MAA+B;AAE/D,MAAIF,MAAa;AAIjB,QAAIE,MAAO;AACT,UAAI;AAGF,YAAIC,KADQ,MAAMC,EAAM,IAAI,SAAS,GACZ,KAAK,KAAA;AAE9B,QAAAD,IAASA,EAAO,QAAQ,QAAQ,EAAE,GAClCH,IAAWG;AAAA,MACb,SAASxK,GAAO;AACd,gBAAQ,KAAK,eAAeA,CAAK,GAEjCqK,IAAW;AAAA,MACb;AAAA;AAEA,MAAAA,IAAWE;AAEf,GAMaG,KAAc,MAClBL,GAOIM,KAAiB,aAE5B,QAAQ,IAAI,sBAAsB,GAC3BN,KAAY;AA4Dd,MAAMO,UAAiB,MAAM;AAAA,EAMlC,YACE7J,GACA8J,GACAC,GACAC,GACAC,GACA;AACA,UAAMjK,CAAO,GACb,KAAK,OAAO,YACZ,KAAK,YAAY8J,GACjB,KAAK,WAAWC,GAChB,KAAK,QAAQC,GACb,KAAK,YAAYC,GAGb,MAAM,qBACR,MAAM,kBAAkB,MAAMJ,CAAQ;AAAA,EAE1C;AACF;AAGA,MAAMK,IAA8B;AAAA,EAClC,QAAQ;AAAA,EACR,SAAS;AAAA;AAAA,EACT,iBAAiB;AAAA;AAAA,EACjB,aAAa;AAAA,EACb,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AACd,GAGMC,IAAYT,EAAM,OAAO;AAAA,EAC7B,SAASQ,EAAgB;AAAA,EACzB,iBAAiBA,EAAgB;AAAA,EACjC,SAAS;AAAA,IACP,gBAAgB;AAAA,IAChB,QAAQ;AAAA,EAAA;AAEZ,CAAC;AAGDC,EAAU,aAAa,QAAQ;AAAA,EAC7B,CAACpI,MAAW;AAEV,IAAKA,EAAe,eAClBqH,EAAgB,SAAA,EAAW,YAAA;AAI7B,QAAIgB,IAAQ,WACRC,IAAO;AACL,KAAc,oBAAI,KAAA,GAAO,QAAA;AAE/B,QAAI;AACF,MAAItI,EAAO,QAAQA,EAAO,KAAK,UAC7BqI,IAAQrI,EAAO,KAAK,OAAO,SAAS,WACpCsI,IAAOtI,EAAO,KAAK,OAAO,QAAQ,aACzBA,EAAO,UAAUA,EAAO,OAAO,WACxCqI,IAAQrI,EAAO,OAAO,OAAO,SAAS,WACtCsI,IAAOtI,EAAO,OAAO,OAAO,QAAQ;AAAA,IAExC,SAAS9C,GAAO;AACd,cAAQ,KAAK,qBAAqBA,CAAK;AAAA,IACzC;AAGC,IAAA8C,EAAe,QAAQqI,GACvBrI,EAAe,OAAOsI,GACtBtI,EAAe,mBAAmB,KAAK,IAAA,GAGxC,QAAQ,IAAI,uBAAuBqI,CAAK,YAAYC,CAAI,GAAG;AAG3D,UAAMC,IAAQ,aAAa,QAAQ,aAAa;AAChD,WAAIA,MACFvI,EAAO,QAAQ,gBAAgB,UAAUuI,CAAK,KAIhDvI,EAAO,QAAQ,cAAc,IAAI,mCACjCA,EAAO,QAAQ,SAAY,mCAEpBA;AAAA,EACT;AAAA,EACA,CAAC9C,OACC,QAAQ,MAAM,iBAAiBA,CAAK,GAC7B,QAAQ,OAAOA,CAAK;AAE/B;AAGAkL,EAAU,aAAa,SAAS;AAAA,EAC9B,CAACJ,MAA4B;AAE3B,IAAKA,EAAS,OAAe,eAC3BX,EAAgB,SAAA,EAAW,YAAA;AAI7B,QAAIgB,IAAQ,WACRC,IAAO;AACX,UAAME,KAAe,oBAAI,KAAA,GAAO,QAAA;AAEhC,QAAI;AAEF,MAAKR,EAAS,OAAe,UAC3BK,IAASL,EAAS,OAAe,QAE9BA,EAAS,OAAe,OAC3BM,IAAQN,EAAS,OAAe,OAIhCA,EAAS,QACTA,EAAS,KAAK,UACdA,EAAS,KAAK,OAAO,SAErBK,IAAQL,EAAS,KAAK,OAAO,OAC7BM,IAAON,EAAS,KAAK,OAAO,QAAQ,aAG7BA,EAAS,OAAO,QAAQA,EAAS,OAAO,KAAK,UACpDK,IAAQL,EAAS,OAAO,KAAK,OAAO,SAAS,WAC7CM,IAAON,EAAS,OAAO,KAAK,OAAO,QAAQ,aAClCA,EAAS,OAAO,UAAUA,EAAS,OAAO,OAAO,WAC1DK,IAAQL,EAAS,OAAO,OAAO,OAAO,SAAS,WAC/CM,IAAON,EAAS,OAAO,OAAO,OAAO,QAAQ;AAAA,IAEjD,SAAS9K,GAAO;AACd,cAAQ,KAAK,qBAAqBA,CAAK;AAAA,IACzC;AAGA,QAAIiB,IAAW;AACf,WAAK6J,EAAS,OAAe,qBAC3B7J,IAAWqK,IAAgBR,EAAS,OAAe,mBAIrD,QAAQ;AAAA,MACN,sBAAsBK,CAAK,aAAaC,CAAI,eAAenK,CAAQ;AAAA,IAAA,GAG9D6J;AAAA,EACT;AAAA,EACA,OAAO9K,MAAsB;AAwB3B,QAtBIA,EAAM,UAAWA,EAAM,OAAe,eACxCmK,EAAgB,SAAA,EAAW,YAAA,GAG7B,QAAQ,MAAM,gBAAgBnK,CAAK,GAG/BuL,KACF,QAAQ,MAAM,qBAAqB;AAAA,MACjC,SAASvL,EAAM;AAAA,MACf,QAAQA,EAAM,UAAU;AAAA,MACxB,YAAYA,EAAM,UAAU;AAAA,MAC5B,MAAMA,EAAM,UAAU;AAAA,MACtB,QAAQ;AAAA,QACN,KAAKA,EAAM,QAAQ;AAAA,QACnB,QAAQA,EAAM,QAAQ;AAAA,QACtB,SAASA,EAAM,QAAQ;AAAA,MAAA;AAAA,IACzB,CACD,GAICA,EAAM,UAAU,WAAW,KAAK;AAClC,YAAMwL,IAAe,aAAa,QAAQ,cAAc;AACxD,UAAIA;AACF,YAAI;AACF,gBAAMC,IAAkB,MAAMhB,EAAM,KAAK,iBAAiB;AAAA,YACxD,cAAAe;AAAA,UAAA,CACD;AAED,cAAIC,EAAgB,KAAK,aAAa;AACpC,yBAAa;AAAA,cACX;AAAA,cACAA,EAAgB,KAAK;AAAA,YAAA;AAIvB,kBAAMC,IAAkB1L,EAAM;AAC9B,gBAAI0L;AACF,qBAAAA,EAAgB,QAAQ,gBAAgB,UAAUD,EAAgB,KAAK,WAAW,IAC3EP,EAAUQ,CAAe;AAAA,UAEpC;AAAA,QACF,QAAuB;AAErB,uBAAa,WAAW,aAAa,GACrC,aAAa,WAAW,cAAc,GACtC,OAAO,SAAS,OAAO;AAAA,QACzB;AAAA,IAEJ;AAEA,WAAO,QAAQ,OAAO1L,CAAK;AAAA,EAC7B;AACF;AAMO,MAAM2L,KAAU,MACd3M,EAAA,GAUIsJ,IAAc,OACzB6C,GACA5L,GACAuC,MACe;AACf,MAAI;AAEF,UAAM8J,IAA4B;AAAA,MAChC,GAAGX;AAAA,MACH,GAAGnJ;AAAA,IAAA,GAIC,EAAE,cAAAgH,EAAA,IAAiBJ,GAAiB,SAAA;AAG1C,QAAI2B,MAAa,MAAM;AACrB,YAAMwB,IAAc,KAAK,IAAA;AACzB,YAAMvB,GAAA;AACN,YAAMwB,IAAY,KAAK,IAAA;AACvB,cAAQ,IAAI,sBAAsBA,IAAYD,CAAW,IAAI;AAAA,IAC/D;AAGA,UAAM/I,IAAyD;AAAA,MAC7D,QAAQ8I,EAAc;AAAA,MACtB,KAAK;AAAA,MACL,SAASA,EAAc;AAAA,MACvB,iBAAiBA,EAAc;AAAA,MAC/B,aAAaA,EAAc;AAAA,IAAA;AAI7B,IAAIA,EAAc,YAChB9I,EAAO,UAAU8I,EAAc;AAIjC,UAAMG,IAAkB1B,KAAY,WAI9B2B,IAAQ,YACRC,IAAQ,YAERC,IAAc;AAAA,MAClB,QAAQ;AAAA,QACN,OAAAf;AAAA,QACA,MAAMQ,GAAA;AAAA,QACN,UAAU5F,GAAA;AAAA,QACV,UAAUgG;AAAA;AAAA,QACV,UAAU;AAAA,QACV,OAAAC;AAAA,QACA,OAAAC;AAAA,QACA,UAAUnD;AAAA,MAAA;AAAA;AAAA,MAGZ,MAAAvJ;AAAA,IAAA;AAIF,IAAIgM,KACF,QAAQ,IAAI,2BAA2BA,CAAO,GAI5CK,EAAc,WAAW,QAC3B9I,EAAO,SAASoJ,KAAeN,EAAc,UAE7C9I,EAAO,OAAOoJ,KAAeN,EAAc,MACvCA,EAAc,WAChB9I,EAAO,SAAS8I,EAAc;AAKlC,QAAIO;AACJ,aACMC,IAAU,GACdA,MAAYR,EAAc,cAAc,IACxCQ;AAEA,UAAI;AACF,cAAMtB,IAAW,MAAMI,EAAUpI,CAAM;AAGvC,YAAIgI,EAAS,KAAK,QAAQ,SAAS,GAAG;AAEpC,qBAAWhL,KAAOgL,EAAS;AACzB,gBAAIhL,MAAQ;AACV,qBAAOgL,EAAS,KAAKhL,CAAG;AAI5B,iBAAO,CAAA;AAAA,QACT,OAAO;AAEL,gBAAMuM,IAASvB,EAAS,KAAK,QACvBwB,IACJD,GAAQ,MAAM,YAAY,uBACtBxB,IAAYwB,GAAQ,MAAM,cAAcC,GACxCvB,IAAQsB,GAAQ,OAChBrB,IAAYqB,GAAQ,MAAM;AAGhC,gBAAM,IAAIzB,EAAS0B,GAAUzB,GAAWC,GAAUC,GAAOC,CAAS;AAAA,QACpE;AAAA,MACF,SAAShL,GAAO;AAEd,YACGA,EAAqB,gBACrBA,EAAqB,UACtB;AACA,gBAAMuM,IAAavM,GACb8K,IAAWyB,EAAW,UACtBC,IAAe1B,EAAS,MAGxBwB,IACJE,GAAc,QAAQ,MAAM,YAC5BD,EAAW;AAAA,UACX,oBACI1B,IACJ2B,GAAc,QAAQ,MAAM;AAAA,WAE3B,OAAO1B,EAAS,QAAS,WACtBA,EAAS,OACT,KAAK,UAAUA,EAAS,IAAI,MAChCwB,GACIvB,IAAQyB,GAAc,QAAQ,OAC9BxB,IAAYwB,GAAc,QAAQ,MAAM;AAG9C,UAAAL,IAAY,IAAIvB;AAAA,YACd0B;AAAA,YACAzB;AAAA,YACAC;AAAA,YACAC;AAAA,YACAC;AAAA,UAAA;AAAA,QAEJ;AAEE,UAAAmB,IAAYnM;AAId,YACGA,EAAqB,gBACtByM,GAAYzM,CAAmB,KAC/BoM,KAAWR,EAAc,cAAc,IACvC;AACA,gBAAMc,GAAMd,EAAc,cAAc,GAAI;AAC5C;AAAA,QACF;AAGA;AAAA,MACF;AAIF,QAAIO,GAAW;AAEb,UAAIP,EAAc,WAAW;AAC3B,cAAMe,IACJR,aAAqBvB,IACjBuB,EAAU,UACV,uBACAS,IACJT,aAAqBvB,IACjBuB,EAAU,QACV,uBACAU,IACJV,aAAqBvB,IACjBuB,EAAU,YACVA,EAAU,SACVnB,IACJmB,aAAqBvB,IAAWuB,EAAU,YAAY;AAExD,QAAIS,GAAW,WAAW,KAAK,IAC7BvL,GAAa;AAAA,UACX,SAASsL;AAAA,UACT,aAAaE;AAAA,UACb,UAAU;AAAA,QAAA,CACX,IACa7B,KAAP,MACPzJ,GAASoL,GAAcE,GAAkB,CAAC,IAE1CrL,GAAYmL,GAAcE,GAAkB,CAAC;AAAA,MAEjD;AAEA,YAAMV;AAAA,IACR;AAGA,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C,SAASnM,GAAY;AAGnB,kBAAQ,MAAM,sBAAsBA,CAAK,GAEnCA;AAAA,EACR;AACF,GAKMyM,KAAc,CAACzM,MAGjB,CAACA,EAAM,YACNA,EAAM,SAAS,UAAU,OAAOA,EAAM,SAAS,SAAS,KAOvD0M,KAAQ,CAACI,MACN,IAAI,QAAQ,CAACC,MAAY,WAAWA,GAASD,CAAE,CAAC,GAoE5CE,KAAS,CACpB7B,GACAvC,GACA9G,MAEOwG,EAAe6C,GAAOvC,GAAQ,EAAE,GAAG9G,GAAS,QAAQ,OAAO,GAGvDmL,KAAU,CACrB9B,GACA5L,GACAuC,MAEOwG,EAAe6C,GAAO5L,GAAM,EAAE,GAAGuC,GAAS,QAAQ,QAAQ,GAGtDoL,KAAS,CACpB/B,GACA5L,GACAuC,MAEOwG,EAAe6C,GAAO5L,GAAM,EAAE,GAAGuC,GAAS,QAAQ,OAAO,GAGrDqL,KAAY,CACvBhC,GACA5L,GACAuC,MAEOwG,EAAe6C,GAAO5L,GAAM,EAAE,GAAGuC,GAAS,QAAQ,UAAU,GAGxDsL,KAAW,CACtBjC,GACA5L,GACAuC,MAEOwG,EAAe6C,GAAO5L,GAAM,EAAE,GAAGuC,GAAS,QAAQ,SAAS;","x_google_ignoreList":[2]}
@@ -1,4 +0,0 @@
1
- "use strict";const q=require("axios"),d=require("crypto-js"),w=require("antd"),_=require("zustand"),$=require("./envUtils-CduTHoHu.cjs"),P=e=>typeof e!="string"?!e:e.trim().length===0,Q=(e,r)=>P(e)?r:e||"",Xe=e=>!P(e),ee=(e,r,t="...")=>e.length<=r?e:e.substring(0,r)+t,K=e=>P(e)?e:e.charAt(0).toUpperCase()+e.slice(1).toLowerCase(),te=e=>P(e)?e:e.split(" ").map(r=>K(r)).join(" "),re=e=>e.replace(/-([a-z])/g,r=>r[1].toUpperCase()),ne=e=>e.replace(/[A-Z]/g,r=>`_${r.toLowerCase()}`),se=e=>e.replace(/[A-Z]/g,r=>`-${r.toLowerCase()}`),oe=e=>{const t=e.replace(/\D/g,"").match(/^(\d{3})(\d{4})(\d{4})$/);return t?`${t[1]}-${t[2]}-${t[3]}`:e},ae=e=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e),ce=e=>{try{return new URL(e),!0}catch{return!1}},ie=e=>e.replace(/\D/g,""),ue=e=>e.replace(/[^a-zA-Z0-9가-힣\s]/g,""),le=e=>e.replace(/<[^>]*>/g,""),de=e=>e.replace(/\n/g,"<br>"),ge=e=>e.replace(/<br\s*\/?>/gi,`
2
- `),me=(e,r)=>{const t=e.match(r);return t||[]},Je=(e,r)=>e.repeat(r),pe=(e,r,t=" ")=>e.padStart(r,t),he=(e,r,t=" ")=>e.padEnd(r,t),fe=(e,r,t=" ")=>{const n=r-e.length;if(n<=0)return e;const o=Math.floor(n/2),s=n-o;return t.repeat(o)+e+t.repeat(s)},E=(e,r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")=>{let t="";for(let n=0;n<e;n++)t+=r.charAt(Math.floor(Math.random()*r.length));return t},Ie=e=>e.split("").reverse().join(""),ye=(e,r)=>(e.match(new RegExp(r,"g"))||[]).length,Se=e=>e.trim().split(/\s+/).length,Ce=()=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){const r=Math.random()*16|0;return(e==="x"?r:r&3|8).toString(16)}),k=(e=32)=>{const t=Ce().replace(/-/g,"");return e>=32?t+E(e-32,"0123456789abcdef"):t.substring(0,e)},be=()=>k(16),we=()=>k(64),Ue=(e=16)=>E(e,"0123456789"),ve=(e=16)=>E(e,"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"),z=()=>Ce(),V=()=>z().replace(/-/g,""),Ne=()=>{const e=Date.now().toString(36),r=E(8,"0123456789abcdef");return e+r},Me=(e,r="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")=>e.replace(/[X-Z]/g,()=>r.charAt(Math.floor(Math.random()*r.length))),Te=e=>{const r=d.SHA256(e);return d.enc.Base64.stringify(r)},F=()=>"abcdefghij1234567890!@#$%^&*();;",De=()=>"123456098765!@#$",Pe=e=>{if(!e)return"";try{const r=d.enc.Utf8.parse(F()),t=d.enc.Utf8.parse(De());return d.AES.encrypt(e,r,{iv:t,padding:d.pad.Pkcs7,mode:d.mode.CBC}).toString()}catch(r){return console.error("암호화 오류:",r),""}},Ee=e=>{if(!e)return"";try{const r=d.enc.Utf8.parse(F()),t=d.enc.Utf8.parse(De());return d.AES.decrypt(e,r,{iv:t,padding:d.pad.Pkcs7,mode:d.mode.CBC}).toString(d.enc.Utf8)}catch(r){return console.error("복호화 오류:",r),""}},Le=(e,r)=>{if(!e)return"";try{const t=r||F();return d.AES.encrypt(e,t).toString()}catch(t){return console.error("간단한 암호화 오류:",t),""}},Ae=(e,r)=>{if(!e)return"";try{const t=r||F();return d.AES.decrypt(e,t).toString(d.enc.Utf8)}catch(t){return console.error("간단한 복호화 오류:",t),""}},xe=e=>e?d.MD5(e).toString():"",_e=e=>e?d.SHA256(e).toString():"",ke=e=>e?d.enc.Base64.stringify(d.enc.Utf8.parse(e)):"",Fe=e=>{if(!e)return"";try{return d.enc.Base64.parse(e).toString(d.enc.Utf8)}catch(r){return console.error("Base64 디코딩 오류:",r),""}},Ze=Object.freeze(Object.defineProperty({__proto__:null,base64Decode:Fe,base64Encode:ke,br2nl:ge,bxmDecrypt:Ee,bxmEncrypt:Pe,capitalize:K,capitalizeWords:te,center:fe,countChar:ye,countWords:Se,encryptSha256:Te,extractNumbers:ie,findPattern:me,formatPhoneNumber:oe,generateAlphanumericUID:ve,generateCustomUID:Me,generateGUID:z,generateGUIDWithoutHyphens:V,generateLongUID:we,generateNumericUID:Ue,generateRandomString:E,generateShortUID:be,generateTimestampUID:Ne,generateUID:k,isEmpty:P,isNotEmpty:Xe,isSafeEmpty:Q,isValidEmail:ae,isValidUrl:ce,md5Hash:xe,nl2br:de,padLeft:pe,padRight:he,removeHtmlTags:le,removeSpecialChars:ue,repeat:Je,reverse:Ie,sha256Hash:_e,simpleDecrypt:Ae,simpleEncrypt:Le,toCamelCase:re,toKebabCase:se,toSnakeCase:ne,truncate:ee},Symbol.toStringTag,{value:"Module"})),b={duration:4.5,placement:"topRight"};class D{constructor(){}static getInstance(){return D.instance||(D.instance=new D),D.instance}showBwgError(r){const{message:t,description:n,duration:o=b.duration,placement:s=b.placement}=r;w.notification.error({message:`${t}`,description:n||"오류가 발생했습니다. 다시 시도해주세요.",duration:o,placement:s,style:{borderLeft:"4px solid #ff4d4f",backgroundColor:"#fff2f0"}})}showSuccess(r,t,n){w.notification.success({message:`${r}`,description:t,duration:n||b.duration,placement:b.placement})}showInfo(r,t,n){w.notification.info({message:`${r}`,description:t,duration:n||b.duration,placement:b.placement})}showWarning(r,t,n){w.notification.warning({message:`${r}`,description:t,duration:n||b.duration,placement:b.placement})}showError(r,t,n){w.notification.error({message:`${r}`,description:t,duration:n||b.duration,placement:b.placement})}destroy(){w.notification.destroy()}close(r){w.notification.destroy()}}const M=D.getInstance(),Qe=e=>{M.showBwgError(e)},et=(e,r,t)=>{M.showSuccess(e,r,t)},Oe=(e,r,t)=>{M.showInfo(e,r,t)},Re=(e,r,t)=>{M.showWarning(e,r,t)},tt=(e,r,t)=>{M.showError(e,r,t)},rt=()=>{M.destroy()},nt=e=>{M.close(e)};(void 0).DEV;function st(e,r){let t;try{t=e()}catch{return}return{getItem:o=>{var s;const a=u=>u===null?null:JSON.parse(u,void 0),i=(s=t.getItem(o))!=null?s:null;return i instanceof Promise?i.then(a):a(i)},setItem:(o,s)=>t.setItem(o,JSON.stringify(s,void 0)),removeItem:o=>t.removeItem(o)}}const H=e=>r=>{try{const t=e(r);return t instanceof Promise?t:{then(n){return H(n)(t)},catch(n){return this}}}catch(t){return{then(n){return this},catch(n){return H(n)(t)}}}},ot=(e,r)=>(t,n,o)=>{let s={storage:st(()=>localStorage),partialize:c=>c,version:0,merge:(c,y)=>({...y,...c}),...r},a=!1;const i=new Set,u=new Set;let f=s.storage;if(!f)return e((...c)=>{console.warn(`[zustand persist middleware] Unable to update item '${s.name}', the given storage is currently unavailable.`),t(...c)},n,o);const m=()=>{const c=s.partialize({...n()});return f.setItem(s.name,{state:c,version:s.version})},I=o.setState;o.setState=(c,y)=>(I(c,y),m());const l=e((...c)=>(t(...c),m()),n,o);o.getInitialState=()=>l;let g;const h=()=>{var c,y;if(!f)return;a=!1,i.forEach(p=>{var S;return p((S=n())!=null?S:l)});const U=((y=s.onRehydrateStorage)==null?void 0:y.call(s,(c=n())!=null?c:l))||void 0;return H(f.getItem.bind(f))(s.name).then(p=>{if(p)if(typeof p.version=="number"&&p.version!==s.version){if(s.migrate){const S=s.migrate(p.state,p.version);return S instanceof Promise?S.then(R=>[!0,R]):[!0,S]}console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,p.state];return[!1,void 0]}).then(p=>{var S;const[R,Ye]=p;if(g=s.merge(Ye,(S=n())!=null?S:l),t(g,!0),R)return m()}).then(()=>{U?.(g,void 0),g=n(),a=!0,u.forEach(p=>p(g))}).catch(p=>{U?.(void 0,p)})};return o.persist={setOptions:c=>{s={...s,...c},c.storage&&(f=c.storage)},clearStorage:()=>{f?.removeItem(s.name)},getOptions:()=>s,rehydrate:()=>h(),hasHydrated:()=>a,onHydrate:c=>(i.add(c),()=>{i.delete(c)}),onFinishHydration:c=>(u.add(c),()=>{u.delete(c)})},s.skipHydration||h(),g||l},Be=ot,C=_.create()(Be((e,r)=>({user:null,isLoggedIn:!1,login:t=>{e({user:t,isLoggedIn:!0}),console.log("사용자 로그인:",t)},logout:()=>{e({user:null,isLoggedIn:!1}),console.log("사용자 로그아웃")},updateUser:t=>{const n=r().user;n&&e({user:{...n,...t}})}}),{name:"user-storage",partialize:e=>({user:e.user,isLoggedIn:e.isLoggedIn})})),at=()=>C.getState().user?.crprCd||null,We=()=>C.getState().user?.userId||null,$e=()=>C.getState().user?.userNm||null,ct=()=>C.getState().user?.userDvsn||null,it=()=>C.getState().user?.emplNo||null,He=()=>C.getState().user?.dprtCd||null,Ge=()=>C.getState().user?.dprtNm||null,O=()=>C.getState().user?.roleList||null,ut=e=>{const r=O();return r?r.includes(e):!1},lt=e=>{const r=O();return r?e.some(t=>r.includes(t)):!1},dt=e=>{const r=O();return r?e.every(t=>r.includes(t)):!1},gt=()=>C.getState().isLoggedIn,Y=()=>C.getState().user,mt=()=>Y()!==null,pt=()=>{const e=$e(),r=We();return e||r||null},ht=()=>{const e=Ge(),r=He();return e||(r?String(r):null)},je={AUTH_BTNS:"SCMSIGN00202",AUTH_MENU:"SCMSIGN00201",SRCH_CODE:"SCMSIGN00301",SRCH_POPU:"SCMPOPU00101",AUTH_BMRK:"SCMBMRK00101"};let L={};function ft(e){L=e,console.log("🔧 Provider 서비스코드 오버라이드 설정:",e)}function X(e){if(L[e]&&L[e].trim()!=="")return console.log(`🔧 Provider 설정 사용: ${e} = ${L[e]}`),L[e];const r=je[e];return console.log(`🔧 기본값 사용: ${e} = ${r}`),r}function It(){const e={};for(const r of Object.keys(je))e[r]=X(r);return e}const G={DEFAULT_PRNT_GBCD:1},yt=e=>e&&typeof e=="object"&&typeof e.menuId=="string"&&typeof e.menuNm=="string"&&typeof e.crprCd=="string",J=e=>Array.isArray(e)&&e.every(yt);let B=[],Z=[];const St=e=>{if(e&&typeof e=="object"){const r=e;if(r.menus&&J(r.menus))return r.menus;if(J(e))return e}return console.warn("⚠️ 메뉴 응답이 비어있거나 예상과 다릅니다."),[]},Ct=(e,r)=>!!r&&e.crprCd===r.crprCd&&e.userId===r.userId&&(e.prntGbcd??G.DEFAULT_PRNT_GBCD)===(r.prntGbcd??G.DEFAULT_PRNT_GBCD),bt=e=>{if(B.length===e.length&&B.every((s,a)=>s.menuId===e[a]?.menuId&&s.menuPrntId===e[a]?.menuPrntId))return Z;if(!e.length)return[];const r=new Map,t=[];e.forEach(s=>s?.menuId&&r.set(s.menuId,{...s,children:[]})),e.forEach(s=>{const a=r.get(s.menuId);a&&(s.menuPrntId&&s.menuPrntId!==""&&s.menuPrntId!=="-"?r.get(s.menuPrntId)?.children?.push(a):t.push(a))});const n=s=>s.sort((a,i)=>(a?.menuNo??0)-(i?.menuNo??0)).map(a=>({...a,children:a.children&&a.children.length?n(a.children):void 0})),o=n(t);return B=[...e],Z=o,o},qe=_.create((e,r)=>({menuList:[],flatMenuList:[],isLoading:!1,error:null,_lastFetchParams:null,fetchMenu:async({crprCd:t,userId:n,prntGbcd:o})=>{const s={crprCd:t,userId:n,prntGbcd:o??G.DEFAULT_PRNT_GBCD};if(Ct(s,r()._lastFetchParams)){console.log("✅ 중복 fetch 차단",s);return}e({isLoading:!0,error:null,_lastFetchParams:s});try{const a=await T(X("AUTH_MENU"),s),i=St(a),u=bt(i);e({flatMenuList:i,menuList:u,isLoading:!1,error:null})}catch(a){e({isLoading:!1,error:a?.message??"메뉴 로드 실패"})}},clearMenu:()=>{e({menuList:[],flatMenuList:[],error:null,_lastFetchParams:null})},findMenuById:t=>{const{flatMenuList:n}=r();return n.find(o=>o.menuId===t)??null}})),W={MAX_TABS:15},Ke=_.create((e,r)=>({activeMenuId:null,activeMenuItem:null,activeDetailItem:null,tabs:[],sidebarCollapsed:!1,maxTabs:W.MAX_TABS,tabProtectFlag:{},tabParams:{},componentLabelMap:{},openTabFromMenu:(t,n)=>{const{tabs:o,activeMenuId:s}=r(),a=o.find(u=>u.key===t.menuId),i=o.find(u=>u.key===t.menuId);if(a)i!=null?(e({activeMenuId:t.menuId,activeMenuItem:t}),console.log("✅ 기존 탭 활성화 - activeMenuItem:",t),r().setTabParams(t.menuId,n||{}),t?.prsnInfoYn==="Y"&&r().setProtectFlagForKey(t.menuId)):(console.warn("❌ 유효하지 않은 메뉴정보",t.menuId),w.message.warning("유효하지 않은 메뉴정보입니다."));else{if(o.length>W.MAX_TABS){console.warn("❌ 최대 탭 개수를 초과했습니다."),w.message.warning(`최대 ${W.MAX_TABS}개의 탭만 열 수 있습니다.
3
- 기존 탭을 닫고 다시 시도해주세요.`);return}const u={key:t.menuId,label:t.menuNm,gubun:"M",menuItem:t,closable:!0};e({tabs:[...o,u],activeMenuId:t.menuId,activeMenuItem:t}),r().setTabParams(t.menuId,n||{}),console.log("✅ 새 탭 추가 - activeMenuItem:",t),t?.prsnInfoYn==="Y"&&r().setProtectFlagForKey(t.menuId)}},openTabByMenuId:(t,n)=>{const o=qe.getState().findMenuById(t);o?r().openTabFromMenu(o,n):(console.warn("❌ 메뉴 ID를 찾을 수 없음:",t),w.message.warning("메뉴 ID를 찾을 수 없습니다."))},openDetailView:(t,n,o)=>{const{tabs:s,activeMenuId:a}=r();if(s.find(u=>u.key===t.viewId))r().focusTab(t.viewId);else{const u={key:t.viewId,label:t.viewLabel,gubun:"C",componentItem:{scrnPath:n,prsnInfoYn:o,prntInfo:t.prntInfo},closable:!0};e({tabs:[...s,u],activeMenuId:t.viewId,activeDetailItem:t}),r().setTabParams(t.viewId,t.viewParams||{})}},closeTab:t=>{const{tabs:n,activeMenuId:o}=r();n.find(i=>i.key===t);const s=n.filter(i=>i.key!==t);let a=o;if(o===t){const i=n.findIndex(u=>u.key===t);a=s.length?s[Math.min(i,s.length-1)]?.key??null:null}e({tabs:s}),a&&r().focusTab(a)},focusTab:t=>{const{tabs:n}=r(),o=n.find(s=>s.key===t);if(o){const s=o.gubun==="C"?{viewId:o.key,viewLabel:o.label,prntInfo:o.componentItem?.prntInfo}:null;o.menuItem?.prsnInfoYn==="Y"?(e({activeMenuId:t,activeMenuItem:o.menuItem,activeDetailItem:s}),console.log("✅ 탭 포커스 (개인정보) - activeMenuItem:",o.menuItem),r().setProtectFlagForKey(t)):(e({activeMenuId:t,activeMenuItem:o.menuItem,activeDetailItem:s}),console.log("✅ 탭 포커스 (일반) - activeMenuItem:",o.menuItem),r().clearProtectFlagForKey(t))}else e({activeMenuId:t,activeMenuItem:null,activeDetailItem:null}),console.warn("❌ 탭을 찾을 수 없음:",t)},closeAllTabs:()=>e({tabs:[],activeMenuId:null,activeMenuItem:null,activeDetailItem:null}),toggleSidebar:()=>e(t=>({sidebarCollapsed:!t.sidebarCollapsed})),reorderTabs:t=>e(n=>{const o=new Map(n.tabs.map(s=>[s.key,s]));return{tabs:t.map(s=>o.get(s)).filter(Boolean)}}),setProtectFlagForKey:t=>e(n=>({tabProtectFlag:{...n.tabProtectFlag,[t]:!0}})),clearProtectFlagForKey:t=>e(n=>{const o={...n.tabProtectFlag};return delete o[t],{tabProtectFlag:o}}),setTabParams:(t,n)=>e(o=>{const s=o.tabParams[t]||{},a={...n||{}};return Object.keys(s).length===Object.keys(a).length&&Object.keys(a).every(u=>s[u]===a[u])?o:{tabParams:{...o.tabParams,[t]:a}}}),setComponentLabelMap:(t,n)=>e({componentLabelMap:t})})),A=_.create(e=>({requestCount:0,loading:!1,showLoading:()=>e(r=>{const t=r.requestCount+1;return{requestCount:t,loading:t>0}}),hideLoading:()=>e(r=>{const t=Math.max(0,r.requestCount-1);return{requestCount:t,loading:t>0}})}));let N=null;const ze=async e=>{if(N===null)if(e===void 0)try{let t=(await q.get("/api/ip")).data.trim();t=t.replace(/\s+/g,""),N=t}catch(r){console.warn("IP 가져오기 실패:",r),N="unknown"}else N=e},wt=()=>N,Ut=async()=>(console.log("IP 검증 비활성화됨 (성능 최적화)"),N||"unknown");class v extends Error{constructor(r,t,n,o,s){super(r),this.name="ApiError",this.detailMsg=t,this.response=n,this.msgCd=o,this.errorType=s,Error.captureStackTrace&&Error.captureStackTrace(this,v)}}const j={method:"POST",timeout:3e4,withCredentials:!0,showLoading:!0,showError:!0,retryCount:0,retryDelay:1e3},x=q.create({timeout:j.timeout,withCredentials:j.withCredentials,headers:{"Content-Type":"application/json; charset=utf-8",Accept:"application/json; charset=utf-8"}});x.interceptors.request.use(e=>{e.showLoading&&A.getState().showLoading();let r="UNKNOWN",t="UNKNOWN";new Date().getTime();try{e.data&&e.data.header?(r=e.data.header.trxCd||"UNKNOWN",t=e.data.header.guid||"UNKNOWN"):e.params&&e.params.header&&(r=e.params.header.trxCd||"UNKNOWN",t=e.params.header.guid||"UNKNOWN")}catch(o){console.warn("trxCd/guid 추출 실패:",o)}e.trxCd=r,e.guid=t,e.requestStartTime=Date.now(),console.log(`🚀 API 요청 시작 [거래코드: ${r} / GUID: ${t}]`);const n=localStorage.getItem("accessToken");return n&&(e.headers.Authorization=`Bearer ${n}`),e.headers["Content-Type"]="application/json; charset=UTF-8",e.headers.Accept="application/json; charset=UTF-8",e},e=>(console.error("❌ 요청 인터셉터 에러:",e),Promise.reject(e)));x.interceptors.response.use(e=>{e.config.showLoading&&A.getState().hideLoading();let r="UNKNOWN",t="UNKNOWN";const n=new Date().getTime();try{e.config.trxCd&&(r=e.config.trxCd),e.config.guid?t=e.config.guid:e.data&&e.data.header&&e.data.header.trxCd?(r=e.data.header.trxCd,t=e.data.header.guid||"UNKNOWN"):e.config.data&&e.config.data.header?(r=e.config.data.header.trxCd||"UNKNOWN",t=e.config.data.header.guid||"UNKNOWN"):e.config.params&&e.config.params.header&&(r=e.config.params.header.trxCd||"UNKNOWN",t=e.config.params.header.guid||"UNKNOWN")}catch(s){console.warn("trxCd/guid 추출 실패:",s)}let o=0;return e.config.requestStartTime&&(o=n-e.config.requestStartTime),console.log(`✅ API 응답 성공 [거래코드: ${r} / GUID : ${t}] - (소요시간: ${o}ms)`),e},async e=>{if(e.config&&e.config.showLoading&&A.getState().hideLoading(),console.error("❌ API 응답 에러:",e),$.isLocal&&console.error("🚨 Error Details:",{message:e.message,status:e.response?.status,statusText:e.response?.statusText,data:e.response?.data,config:{url:e.config?.url,method:e.config?.method,baseURL:e.config?.baseURL}}),e.response?.status===401){const r=localStorage.getItem("refreshToken");if(r)try{const t=await q.post("/auth/refresh",{refreshToken:r});if(t.data.accessToken){localStorage.setItem("accessToken",t.data.accessToken);const n=e.config;if(n)return n.headers.Authorization=`Bearer ${t.data.accessToken}`,x(n)}}catch{localStorage.removeItem("accessToken"),localStorage.removeItem("refreshToken"),window.location.href="/login"}}return Promise.reject(e)});const Ve=()=>V(),T=async(e,r,t)=>{try{const n={...j,...t},{activeMenuId:o}=Ke.getState();if(N===null){const I=Date.now();await ze();const l=Date.now();console.log(`[INFO] IP 조회 소요시간: ${l-I}ms`)}const s={method:n.method,url:"/api/service",timeout:n.timeout,withCredentials:n.withCredentials,showLoading:n.showLoading};n.headers&&(s.headers=n.headers);const a=N||"unknown",i=__APP_CD__,u=__SYS_CD__,f={header:{trxCd:e,guid:Ve(),userInfo:Y(),clientIp:a,domainId:"DEFAULT",appCd:i,sysCd:u,screenId:o},data:r};$.isLocal&&console.log("__BWG_LOCAL__ 테스트 입니다. ",$.isLocal),n.method==="GET"?s.params=f||n.params:(s.data=f||n.data,n.params&&(s.params=n.params));let m;for(let I=0;I<=(n.retryCount||0);I++)try{const l=await x(s);if(l.data.header?.resCd==0){for(const g in l.data)if(g!=="header")return l.data[g];return{}}else{const g=l.data.header,h=g?.msgs?.basicMsg||"요청 처리 중 오류가 발생했습니다.",c=g?.msgs?.detailMsgs||h,y=g?.msgCd,U=g?.msgs?.type;throw new v(h,c,l,y,U)}}catch(l){if(l.isAxiosError&&l.response){const g=l,h=g.response,c=h.data,y=c?.header?.msgs?.basicMsg||g.message||"서버에서 오류가 발생했습니다.",U=c?.header?.msgs?.detailMsgs||(typeof h.data=="string"?h.data:JSON.stringify(h.data))||y,p=c?.header?.msgCd,S=c?.header?.msgs?.type;m=new v(y,U,h,p,S)}else m=l;if(l.isAxiosError&&vt(l)&&I<(n.retryCount||0)){await Nt(n.retryDelay||1e3);continue}break}if(m){if(n.showError){const I=m instanceof v?m.message:"요청 처리 중 오류가 발생했습니다.",l=m instanceof v?m.msgCd:"요청 처리 중 오류가 발생했습니다.",g=m instanceof v?m.detailMsg:m.message,h=m instanceof v?m.errorType:"";l?.startsWith("BXM")?Qe({message:I,description:g,duration:5}):h=="I"?Oe(I,g,5):Re(I,g,5)}throw m}throw new Error("알 수 없는 API 오류가 발생했습니다.")}catch(n){throw console.error("callService 최종 에러:",n),n}},vt=e=>!e.response||e.response.status>=500&&e.response.status<600,Nt=e=>new Promise(r=>setTimeout(r,e)),Mt=(e,r,t)=>T(e,r,{...t,method:"GET"}),Tt=(e,r,t)=>T(e,r,{...t,method:"POST"}),Dt=(e,r,t)=>T(e,r,{...t,method:"PUT"}),Pt=(e,r,t)=>T(e,r,{...t,method:"DELETE"}),Et=(e,r,t)=>T(e,r,{...t,method:"PATCH"});exports.apiDelete=Pt;exports.apiGet=Mt;exports.apiPatch=Et;exports.apiPost=Tt;exports.apiPut=Dt;exports.base64Decode=Fe;exports.base64Encode=ke;exports.br2nl=ge;exports.bxmDecrypt=Ee;exports.bxmEncrypt=Pe;exports.callService=T;exports.capitalize=K;exports.capitalizeWords=te;exports.center=fe;exports.closeNotification=nt;exports.countChar=ye;exports.countWords=Se;exports.destroyNotifications=rt;exports.encryptSha256=Te;exports.extractNumbers=ie;exports.findPattern=me;exports.formatPhoneNumber=oe;exports.generateAlphanumericUID=ve;exports.generateCustomUID=Me;exports.generateGUID=z;exports.generateGUIDWithoutHyphens=V;exports.generateLongUID=we;exports.generateNumericUID=Ue;exports.generateRandomString=E;exports.generateShortUID=be;exports.generateTimestampUID=Ne;exports.generateUID=k;exports.getAllServiceCodes=It;exports.getClientIp=wt;exports.getCrprCd=at;exports.getDepartmentInfo=ht;exports.getDisplayName=pt;exports.getDprtCd=He;exports.getDprtNm=Ge;exports.getEmplNo=it;exports.getGuid=Ve;exports.getRoleList=O;exports.getServiceCode=X;exports.getUserDvsn=ct;exports.getUserId=We;exports.getUserInfo=Y;exports.getUserNm=$e;exports.hasAllRoles=dt;exports.hasAnyRole=lt;exports.hasRole=ut;exports.hasUserInfo=mt;exports.isEmpty=P;exports.isLoggedIn=gt;exports.isSafeEmpty=Q;exports.isValidEmail=ae;exports.isValidUrl=ce;exports.md5Hash=xe;exports.nl2br=de;exports.notificationService=M;exports.padLeft=pe;exports.padRight=he;exports.persist=Be;exports.removeHtmlTags=le;exports.removeSpecialChars=ue;exports.reverse=Ie;exports.setClientIp=ze;exports.setServiceCodeOverrides=ft;exports.sha256Hash=_e;exports.showError=tt;exports.showInfo=Oe;exports.showSuccess=et;exports.showWarning=Re;exports.simpleDecrypt=Ae;exports.simpleEncrypt=Le;exports.stringUtils=Ze;exports.toCamelCase=re;exports.toKebabCase=se;exports.toSnakeCase=ne;exports.truncate=ee;exports.useLoadingStore=A;exports.useMenuModelStore=qe;exports.useMenuViewStore=Ke;exports.useUserStore=C;exports.verifyClientIp=Ut;
4
- //# sourceMappingURL=apiUtils-Cbg6NQLv.cjs.map