@bwg-ui/core 1.1.11 → 1.1.13
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.
- package/dist/chunks/BwgLargeUploader-CgrJUwFW.cjs +3 -0
- package/dist/chunks/BwgLargeUploader-CgrJUwFW.cjs.map +1 -0
- package/dist/chunks/{BwgLargeUploader-B5EtYKUz.js → BwgLargeUploader-Nx2-wiD8.js} +802 -776
- package/dist/chunks/BwgLargeUploader-Nx2-wiD8.js.map +1 -0
- package/dist/chunks/{FileUtils-CaU9Bzu2.js → FileUtils-Bbz3AvQn.js} +2 -2
- package/dist/chunks/{FileUtils-CaU9Bzu2.js.map → FileUtils-Bbz3AvQn.js.map} +1 -1
- package/dist/chunks/FileUtils-D73GVmB8.cjs +2 -0
- package/dist/chunks/{FileUtils-BweAWoJt.cjs.map → FileUtils-D73GVmB8.cjs.map} +1 -1
- package/dist/chunks/SSOHandler-CZHPiuEh.js +25397 -0
- package/dist/chunks/SSOHandler-CZHPiuEh.js.map +1 -0
- package/dist/chunks/SSOHandler-rq0OGrpX.cjs +236 -0
- package/dist/chunks/SSOHandler-rq0OGrpX.cjs.map +1 -0
- package/dist/chunks/{SearchBoxContext-CY4tAQcg.js → SearchBoxContext-BxtHF9BO.js} +2 -2
- package/dist/chunks/{SearchBoxContext-CY4tAQcg.js.map → SearchBoxContext-BxtHF9BO.js.map} +1 -1
- package/dist/chunks/SearchBoxContext-Cpr9xa1S.cjs +2 -0
- package/dist/chunks/{SearchBoxContext-DDBY44Wr.cjs.map → SearchBoxContext-Cpr9xa1S.cjs.map} +1 -1
- package/dist/chunks/TabContainer-B7-6AQXV.js +254 -0
- package/dist/chunks/TabContainer-B7-6AQXV.js.map +1 -0
- package/dist/chunks/TabContainer-Dx2PVShz.cjs +36 -0
- package/dist/chunks/TabContainer-Dx2PVShz.cjs.map +1 -0
- package/dist/chunks/_commonjsHelpers-DKOUU3wS.cjs +2 -0
- package/dist/chunks/_commonjsHelpers-DKOUU3wS.cjs.map +1 -0
- package/dist/chunks/_commonjsHelpers-DaMA6jEr.js +9 -0
- package/dist/chunks/_commonjsHelpers-DaMA6jEr.js.map +1 -0
- package/dist/chunks/apiUtils-C45AWfu-.js +957 -0
- package/dist/chunks/apiUtils-C45AWfu-.js.map +1 -0
- package/dist/chunks/apiUtils-Cbg6NQLv.cjs +4 -0
- package/dist/chunks/apiUtils-Cbg6NQLv.cjs.map +1 -0
- package/dist/chunks/codeStore-BGLhSpAM.cjs +2 -0
- package/dist/chunks/{codeStore-KPL92rcv.cjs.map → codeStore-BGLhSpAM.cjs.map} +1 -1
- package/dist/chunks/{codeStore-IIp25egq.js → codeStore-BzT5wSd9.js} +2 -2
- package/dist/chunks/{codeStore-IIp25egq.js.map → codeStore-BzT5wSd9.js.map} +1 -1
- package/dist/chunks/commonUtils-BH6QwGUb.cjs +2 -0
- package/dist/chunks/commonUtils-BH6QwGUb.cjs.map +1 -0
- package/dist/chunks/{commonUtils-Cvx6_eK2.js → commonUtils-Bb16Yqjk.js} +24 -25
- package/dist/chunks/commonUtils-Bb16Yqjk.js.map +1 -0
- package/dist/chunks/envUtils-C9Gf5aek.js.map +1 -1
- package/dist/chunks/envUtils-CduTHoHu.cjs.map +1 -1
- package/dist/chunks/favoriteStore-3YceyayF.cjs +2 -0
- package/dist/chunks/favoriteStore-3YceyayF.cjs.map +1 -0
- package/dist/chunks/favoriteStore-C9utQ6sm.js +112 -0
- package/dist/chunks/favoriteStore-C9utQ6sm.js.map +1 -0
- package/dist/chunks/{popupStore-D8RI04bU.js → popupStore-DmFbkkjd.js} +19 -18
- package/dist/chunks/popupStore-DmFbkkjd.js.map +1 -0
- package/dist/chunks/popupStore-DnWLaQ70.cjs +2 -0
- package/dist/chunks/popupStore-DnWLaQ70.cjs.map +1 -0
- package/dist/chunks/usePopup-C8FrbrDD.cjs +2 -0
- package/dist/chunks/{UtilsContext-JSHHfnWl.js.map → usePopup-C8FrbrDD.cjs.map} +1 -1
- package/dist/chunks/{UtilsContext-JSHHfnWl.js → usePopup-pfh-ajfP.js} +82 -82
- package/dist/chunks/usePopup-pfh-ajfP.js.map +1 -0
- package/dist/components/common/BwgDetail.d.ts +5 -0
- package/dist/components/common/BwgDetail.d.ts.map +1 -0
- package/dist/components/common/BwgDrawer.d.ts.map +1 -1
- package/dist/components/common/BwgEditor.d.ts +7 -0
- package/dist/components/common/BwgEditor.d.ts.map +1 -0
- package/dist/components/common/BwgView.d.ts.map +1 -1
- package/dist/components/common/index.cjs +1 -1
- package/dist/components/common/index.d.ts +2 -0
- package/dist/components/common/index.d.ts.map +1 -1
- package/dist/components/common/index.js +23 -21
- package/dist/components/core/BwgDatePicker.d.ts +1 -1
- package/dist/components/core/BwgDatePicker.d.ts.map +1 -1
- package/dist/components/core/BwgRangePicker.d.ts +1 -1
- package/dist/components/core/BwgRangePicker.d.ts.map +1 -1
- package/dist/components/core/BwgUploader.d.ts.map +1 -1
- package/dist/components/core/index.cjs +1 -1
- package/dist/components/core/index.js +1 -1
- package/dist/components/layout/ErrorBound.d.ts +29 -0
- package/dist/components/layout/ErrorBound.d.ts.map +1 -0
- package/dist/components/layout/TabContainer.d.ts +9 -0
- package/dist/components/layout/TabContainer.d.ts.map +1 -0
- package/dist/components/layout/index.cjs +1 -1
- package/dist/components/layout/index.d.ts +3 -1
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +6 -4
- package/dist/index.cjs +1 -1
- package/dist/index.js +301 -296
- package/dist/provider/index.cjs +1 -1
- package/dist/provider/index.js +2 -2
- package/dist/stores/favoriteStore.d.ts.map +1 -1
- package/dist/stores/index.cjs +1 -1
- package/dist/stores/index.cjs.map +1 -1
- package/dist/stores/index.d.ts +3 -1
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +18 -16
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/loadingStore.d.ts +9 -0
- package/dist/stores/loadingStore.d.ts.map +1 -0
- package/dist/stores/menuViewStore.d.ts +28 -3
- package/dist/stores/menuViewStore.d.ts.map +1 -1
- package/dist/stores/popupStore.d.ts.map +1 -1
- package/dist/styles/assets/images/header/icon/ico-bell.svg +3 -3
- package/dist/styles/assets/images/header/icon/ico-logout.svg +10 -10
- package/dist/styles/assets/images/header/icon/ico-setting.svg +4 -4
- package/dist/styles/assets/images/header/icon/ico-sidebar-arrow.svg +3 -3
- package/dist/utils/apiUtils.d.ts +3 -2
- package/dist/utils/apiUtils.d.ts.map +1 -1
- package/dist/utils/index.cjs +1 -1
- package/dist/utils/index.js +3 -3
- package/dist/utils/notificationUtils.d.ts +0 -1
- package/dist/utils/notificationUtils.d.ts.map +1 -1
- package/package.json +6 -7
- package/dist/chunks/BwgLargeUploader-B5EtYKUz.js.map +0 -1
- package/dist/chunks/BwgLargeUploader-BPJcShgF.cjs +0 -3
- package/dist/chunks/BwgLargeUploader-BPJcShgF.cjs.map +0 -1
- package/dist/chunks/FileUtils-BweAWoJt.cjs +0 -2
- package/dist/chunks/PublicLayout-3v46YZdi.cjs +0 -36
- package/dist/chunks/PublicLayout-3v46YZdi.cjs.map +0 -1
- package/dist/chunks/PublicLayout-B4wGo0ut.js +0 -139
- package/dist/chunks/PublicLayout-B4wGo0ut.js.map +0 -1
- package/dist/chunks/SSOHandler-C72Do3RD.js +0 -15717
- package/dist/chunks/SSOHandler-C72Do3RD.js.map +0 -1
- package/dist/chunks/SSOHandler-ColywAGZ.cjs +0 -184
- package/dist/chunks/SSOHandler-ColywAGZ.cjs.map +0 -1
- package/dist/chunks/SearchBoxContext-DDBY44Wr.cjs +0 -2
- package/dist/chunks/UtilsContext-C4tlOndT.cjs +0 -2
- package/dist/chunks/UtilsContext-C4tlOndT.cjs.map +0 -1
- package/dist/chunks/_commonjsHelpers-C6fGbg64.js +0 -7
- package/dist/chunks/_commonjsHelpers-C6fGbg64.js.map +0 -1
- package/dist/chunks/_commonjsHelpers-DwGv2jUC.cjs +0 -2
- package/dist/chunks/_commonjsHelpers-DwGv2jUC.cjs.map +0 -1
- package/dist/chunks/codeStore-KPL92rcv.cjs +0 -2
- package/dist/chunks/commonUtils-Cvx6_eK2.js.map +0 -1
- package/dist/chunks/commonUtils-DaFg0y7C.cjs +0 -2
- package/dist/chunks/commonUtils-DaFg0y7C.cjs.map +0 -1
- package/dist/chunks/menuViewStore-DuS0VmkB.cjs +0 -3
- package/dist/chunks/menuViewStore-DuS0VmkB.cjs.map +0 -1
- package/dist/chunks/menuViewStore-OKcSQq-s.js +0 -343
- package/dist/chunks/menuViewStore-OKcSQq-s.js.map +0 -1
- package/dist/chunks/popupStore-BEoWGajT.cjs +0 -2
- package/dist/chunks/popupStore-BEoWGajT.cjs.map +0 -1
- package/dist/chunks/popupStore-D8RI04bU.js.map +0 -1
- package/dist/chunks/serviceConfig-9dHegQIK.cjs +0 -3
- package/dist/chunks/serviceConfig-9dHegQIK.cjs.map +0 -1
- package/dist/chunks/serviceConfig-Dhe7neaj.js +0 -709
- package/dist/chunks/serviceConfig-Dhe7neaj.js.map +0 -1
- package/scripts/gen-component-registry.js +0 -138
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"serviceConfig-Dhe7neaj.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/apiUtils.ts","../../src/utils/serviceConfig.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 errorCode?: 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 errorCode,\r\n duration = DEFAULT_CONFIG.duration,\r\n placement = DEFAULT_CONFIG.placement,\r\n } = props;\r\n\r\n if (errorCode?.startsWith(\"BXM\")) {\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 } else {\r\n notification.warning({\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 */\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} ","import axios, { AxiosError } from \"axios\";\nimport type { AxiosRequestConfig, AxiosResponse } from \"axios\";\nimport { generateGUIDWithoutHyphens, bxmEncrypt } from \"./stringUtils\";\nimport { showBwgError } from \"./notificationUtils\";\nimport { getUserInfo } from \"./userUtils\";\nimport { getEnvCode, isLocal } from \"./envUtils\";\n\n// 클라이언트 IP 저장 변수 (읽기 전용)\nlet clientIp: string | null = null;\n\n/**\n * 클라이언트 IP 설정 (초기화 시에만 사용)\n * @param ip - 클라이언트 IP 주소\n */\nexport const setClientIp = (ip: string): void => {\n // 이미 설정된 경우 재설정 방지\n if (clientIp === null) {\n clientIp = ip;\n //console.log('🌐 클라이언트 IP 초기화:', ip);\n } else {\n //console.warn('⚠️ IP는 이미 설정되어 있어 재설정할 수 없습니다.');\n }\n};\n\n/**\n * 클라이언트 IP 가져오기 (읽기 전용)\n * @returns 클라이언트 IP 주소 또는 null\n */\nexport const getClientIp = (): string | null => {\n return clientIp;\n};\n\n/**\n * 서버에서 실제 클라이언트 IP 확인 (보안 강화)\n * @returns Promise<string> - 서버가 확인한 실제 IP\n */\nexport const verifyClientIp = async (): Promise<string> => {\n // IP 검증 비활성화 (성능 최적화)\n console.log(\"IP 검증 비활성화됨 (성능 최적화)\");\n return clientIp || \"unknown\";\n\n // 아래 코드는 주석 처리 (필요시 활성화)\n /*\n try {\n const response = await axios.get('/api/ip', {\n headers: {\n 'Cache-Control': 'no-cache',\n Pragma: 'no-cache',\n },\n });\n\n let serverIp = response.data.trim().replace(/\\s+/g, '');\n\n // 클라이언트 IP와 서버 IP 비교\n if (clientIp && clientIp !== serverIp) {\n console.warn('⚠️ IP 불일치 감지:', {\n client: clientIp,\n server: serverIp,\n });\n }\n\n return serverIp;\n } catch (error) {\n console.error('IP 확인 실패:', error);\n return clientIp || 'unknown';\n }\n */\n};\n\n// API 응답 타입 정의\nexport interface ApiResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n error?: string;\n code?: number;\n}\n\n// API 요청 옵션 타입 정의\nexport interface ApiOptions {\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n headers?: Record<string, string>;\n timeout?: number;\n withCredentials?: boolean;\n params?: Record<string, any>;\n data?: any;\n showLoading?: boolean;\n showError?: boolean;\n retryCount?: number;\n retryDelay?: number;\n}\n\n/**\n * 사용자 정의 API 에러 클래스\n * @param {string} message - 기본 에러 메시지 (basicMsg)\n * @param {string} detailMsg - 상세 에러 메시지 (detailMsgs)\n * @param {AxiosResponse} [response] - Axios 응답 객체 (선택 사항)\n * @param {string} [msgCd] - 서버 메시지 코드 (선택 사항)\n */\nexport class ApiError extends Error {\n detailMsg: string;\n response?: AxiosResponse;\n msgCd?: string;\n\n constructor(\n message: string,\n detailMsg: string,\n response?: AxiosResponse,\n msgCd?: string\n ) {\n super(message);\n this.name = \"ApiError\";\n this.detailMsg = detailMsg;\n this.response = response;\n this.msgCd = msgCd;\n\n // 스택 트레이스 복원 (V8 엔진 환경 등)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n}\n\n// 기본 설정\nconst DEFAULT_OPTIONS: ApiOptions = {\n method: \"POST\",\n timeout: 30000, // 30초\n withCredentials: true, // 쿠키 포함\n showLoading: true,\n showError: true,\n retryCount: 3,\n retryDelay: 1000,\n};\n\n// axios 인스턴스 생성\nconst apiClient = axios.create({\n timeout: DEFAULT_OPTIONS.timeout,\n withCredentials: DEFAULT_OPTIONS.withCredentials,\n headers: {\n \"Content-Type\": \"application/json; charset=utf-8\",\n Accept: \"application/json; charset=utf-8\",\n },\n});\n\n// 개발 환경에서 API 설정 정보 출력\nif (isLocal) {\n console.log(\"🔧 API Client Configuration:\");\n console.log(\" - Timeout:\", apiClient.defaults.timeout);\n console.log(\" - With Credentials:\", apiClient.defaults.withCredentials);\n console.log(\" - Environment:\", getEnvCode());\n}\n\n// 요청 인터셉터\napiClient.interceptors.request.use(\n (config) => {\n // trxCd와 guid 추출 (requestData에서)\n let trxCd = \"UNKNOWN\";\n let guid = \"UNKNOWN\";\n const requestTime = new Date().getTime();\n\n try {\n if (config.data && config.data.header) {\n trxCd = config.data.header.trxCd || \"UNKNOWN\";\n guid = config.data.header.guid || \"UNKNOWN\";\n } else if (config.params && config.params.header) {\n trxCd = config.params.header.trxCd || \"UNKNOWN\";\n guid = config.params.header.guid || \"UNKNOWN\";\n }\n } catch (error) {\n console.warn(\"trxCd/guid 추출 실패:\", error);\n }\n\n // trxCd, guid와 요청 시작 시간을 config에 저장 (응답 인터셉터에서 사용)\n (config as any).trxCd = trxCd;\n (config as any).guid = guid;\n (config as any).requestStartTime = Date.now();\n\n // 로딩 표시\n console.log(`🚀 API 요청 시작 [거래코드: ${trxCd} / GUID: ${guid}]`);\n\n // 개발 환경에서 요청 정보 출력\n // if (isLocal) {\n // console.log('📤 Request Details:', {\n // method: config.method?.toUpperCase(),\n // url: config.url,\n // data: config.data,\n // params: config.params,\n // headers: config.headers,\n // });\n // }\n\n // 토큰이 있다면 헤더에 추가\n const token = localStorage.getItem(\"accessToken\");\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n\n // UTF-8 인코딩 명시적 설정\n config.headers[\"Content-Type\"] = \"application/json; charset=UTF-8\";\n config.headers[\"Accept\"] = \"application/json; charset=UTF-8\";\n\n return config;\n },\n (error) => {\n console.error(\"❌ 요청 인터셉터 에러:\", error);\n return Promise.reject(error);\n }\n);\n\n// 응답 인터셉터\napiClient.interceptors.response.use(\n (response: AxiosResponse) => {\n // trxCd와 guid 추출 (요청 시 저장된 값 사용)\n let trxCd = \"UNKNOWN\";\n let guid = \"UNKNOWN\";\n const responseTime = new Date().getTime();\n\n try {\n // 요청 시 저장된 trxCd와 guid 사용\n if ((response.config as any).trxCd) {\n trxCd = (response.config as any).trxCd;\n }\n if ((response.config as any).guid) {\n guid = (response.config as any).guid;\n }\n // 응답 데이터에서도 확인\n else if (\n response.data &&\n response.data.header &&\n response.data.header.trxCd\n ) {\n trxCd = response.data.header.trxCd;\n guid = response.data.header.guid || \"UNKNOWN\";\n }\n // 요청 설정에서도 확인\n else if (response.config.data && response.config.data.header) {\n trxCd = response.config.data.header.trxCd || \"UNKNOWN\";\n guid = response.config.data.header.guid || \"UNKNOWN\";\n } else if (response.config.params && response.config.params.header) {\n trxCd = response.config.params.header.trxCd || \"UNKNOWN\";\n guid = response.config.params.header.guid || \"UNKNOWN\";\n }\n } catch (error) {\n console.warn(\"trxCd/guid 추출 실패:\", error);\n }\n\n // 소요 시간 계산\n let duration = 0;\n if ((response.config as any).requestStartTime) {\n duration = responseTime - (response.config as any).requestStartTime;\n }\n\n // 로딩 숨김\n console.log(\n `✅ API 응답 성공 [거래코드: ${trxCd} / GUID : ${guid}] - (소요시간: ${duration}ms)`\n );\n\n // 개발 환경에서 응답 정보 출력\n // if (isLocal) {\n // console.log('📥 Response Details:', {\n // status: response.status,\n // statusText: response.statusText,\n // data: response.data,\n // headers: response.headers,\n // });\n // }\n\n return response;\n },\n async (error: AxiosError) => {\n console.error(\"❌ API 응답 에러:\", error);\n\n // 개발 환경에서 에러 정보 출력\n if (isLocal) {\n console.error(\"🚨 Error Details:\", {\n message: error.message,\n status: error.response?.status,\n statusText: error.response?.statusText,\n data: error.response?.data,\n config: {\n url: error.config?.url,\n method: error.config?.method,\n baseURL: error.config?.baseURL,\n },\n });\n }\n\n // 401 에러 시 토큰 갱신 시도\n if (error.response?.status === 401) {\n const refreshToken = localStorage.getItem(\"refreshToken\");\n if (refreshToken) {\n try {\n const refreshResponse = await axios.post(\"/auth/refresh\", {\n refreshToken,\n });\n\n if (refreshResponse.data.accessToken) {\n localStorage.setItem(\n \"accessToken\",\n refreshResponse.data.accessToken\n );\n\n // 원래 요청 재시도\n const originalRequest = error.config;\n if (originalRequest) {\n originalRequest.headers.Authorization = `Bearer ${refreshResponse.data.accessToken}`;\n return apiClient(originalRequest);\n }\n }\n } catch (refreshError) {\n // 토큰 갱신 실패 시 로그아웃\n localStorage.removeItem(\"accessToken\");\n localStorage.removeItem(\"refreshToken\");\n window.location.href = \"/login\";\n }\n }\n }\n\n return Promise.reject(error);\n }\n);\n\n/**\n * GUID 생성 함수 (API 요청용)\n * @returns 하이픈이 제거된 GUID\n */\nexport const getGuid = (): string => {\n return generateGUIDWithoutHyphens();\n};\n\n/**\n * Tomcat WAS와 통신하는 범용 API 호출 함수\n * @param trxCd - 거래코드드\n * @param data - 요청 데이터 (GET 요청 시 params로 사용)\n * @param options - 옵션 파라미터 (선택사항)\n * @returns Promise<ApiResponse<T>>\n */\nexport const callService = async <T = any>(\n trxCd: string,\n data?: any,\n options?: ApiOptions\n): Promise<T> => {\n try {\n // 옵션 병합\n const mergedOptions: ApiOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n\n // 요청 설정\n const config: AxiosRequestConfig = {\n method: mergedOptions.method,\n url: \"/api/service\",\n timeout: mergedOptions.timeout,\n withCredentials: mergedOptions.withCredentials,\n };\n\n // 헤더 설정\n if (mergedOptions.headers) {\n config.headers = mergedOptions.headers;\n }\n\n // IP가 설정되지 않은 경우 기본값 사용 (추가 IP 호출 방지)\n const currentClientIp = clientIp || \"unknown\";\n\n // vite.config.ts에서 define으로 주입된 전역 변수를 사용합니다.\n // @ts-ignore - __APP_CD__는 Vite에 의해 빌드 시점에 주입되는 전역 변수입니다.\n const appCd = __APP_CD__;\n const sysCd = __SYS_CD__;\n console.log(\"@@ request param :: \", data);\n\n const requestData = {\n header: {\n trxCd: trxCd,\n guid: getGuid(),\n userInfo: getUserInfo(),\n clientIp: currentClientIp, // 클라이언트 IP 추가 (서버에서 재확인 권장)\n domainId: \"DEFAULT\",\n appCd,\n sysCd,\n },\n // data: bxmEncrypt(JSON.stringify(data)),\n data: data,\n };\n\n // 개발 환경에서 요청 정보 출력\n if (isLocal) {\n console.log(\"__BWG_LOCAL__ 테스트 입니다. \", isLocal);\n console.log(\"📤 Request Data:\", requestData);\n }\n\n // HTTP 메서드에 따른 데이터 설정\n if (mergedOptions.method === \"GET\") {\n config.params = requestData || mergedOptions.params;\n } else {\n config.data = requestData || mergedOptions.data;\n if (mergedOptions.params) {\n config.params = mergedOptions.params;\n }\n }\n\n // 재시도 로직\n let lastError: Error | undefined;\n for (\n let attempt = 0;\n attempt <= (mergedOptions.retryCount || 0);\n attempt++\n ) {\n try {\n const response = await apiClient(config);\n\n // 성공 응답 처리\n if (response.data.header?.resCd == 0) {\n // resCd가 0인 경우, header를 제외한 데이터 반환\n for (const key in response.data) {\n if (key !== \"header\") {\n return response.data[key];\n }\n }\n // 데이터 필드가 없는 성공 응답의 경우, 빈 객체를 반환\n return {} as T;\n } else {\n // 실패 시 에러 생성 및 throw (비즈니스 에러)\n const header = response.data.header;\n const basicMsg =\n header?.msgs?.basicMsg || \"요청 처리 중 오류가 발생했습니다.\";\n const detailMsg = header?.msgs?.detailMsgs || basicMsg;\n const msgCd = header?.msgCd;\n\n // ApiError를 생성하여 throw\n throw new ApiError(basicMsg, detailMsg, response, msgCd);\n }\n } catch (error) {\n // Axios 에러이고, 서버 응답이 있는 경우 (e.g., 500 에러)\n if (\n (error as AxiosError).isAxiosError &&\n (error as AxiosError).response\n ) {\n const axiosError = error as AxiosError;\n const response = axiosError.response!;\n const responseData = response.data as any;\n\n // 서버 응답 본문에서 메시지 추출 시도\n const basicMsg =\n responseData?.header?.msgs?.basicMsg ||\n axiosError.message || // 실패 시 Axios 에러 메시지 사용\n \"서버에서 오류가 발생했습니다.\";\n const detailMsg =\n responseData?.header?.msgs?.detailMsgs ||\n // 상세 메시지로 응답 본문 제공 (문자열이 아니면 JSON으로 변환)\n (typeof response.data === \"string\"\n ? response.data\n : JSON.stringify(response.data)) ||\n basicMsg;\n const msgCd = responseData?.header?.msgCd;\n\n // AxiosError를 ApiError로 변환하여 lastError에 저장\n lastError = new ApiError(basicMsg, detailMsg, response, msgCd);\n } else {\n // 네트워크 에러 또는 try 블록에서 throw된 커스텀 에러(ApiError)\n lastError = error as Error;\n }\n\n // 재시도 로직\n if (\n (error as AxiosError).isAxiosError &&\n shouldRetry(error as AxiosError) &&\n attempt < (mergedOptions.retryCount || 0)\n ) {\n await delay(mergedOptions.retryDelay || 1000);\n continue;\n }\n\n // 재시도 불가능하거나 재시도 횟수 초과 시 루프 중단\n break;\n }\n }\n\n // 루프 종료 후 에러 처리 (lastError가 설정된 경우)\n if (lastError) {\n // 에러 표시 옵션이 활성화된 경우, 통합된 에러 메시지를 표시합니다.\n if (mergedOptions.showError) {\n const errorMessage =\n lastError instanceof ApiError\n ? lastError.message\n : \"요청 처리 중 오류가 발생했습니다.\";\n const errorCode =\n lastError instanceof ApiError\n ? lastError.msgCd\n : \"요청 처리 중 오류가 발생했습니다.\";\n const errorDescription =\n lastError instanceof ApiError\n ? lastError.detailMsg\n : lastError.message;\n\n showBwgError({\n message: errorMessage,\n errorCode: errorCode,\n description: errorDescription,\n duration: 5,\n });\n }\n // 최종 에러를 호출자에게 throw합니다.\n throw lastError;\n }\n\n // 이 코드는 이론적으로 도달할 수 없지만, lastError가 없는 경우를 대비한 방어 코드입니다.\n throw new Error(\"알 수 없는 API 오류가 발생했습니다.\");\n } catch (error: any) {\n // 최종 에러 처리 및 전파\n // callService에서 발생하는 모든 에러는 ApiError 형태로 변환하여 throw합니다.\n console.error(\"callService 최종 에러:\", error);\n\n throw error;\n }\n};\n\n/**\n * 재시도 가능한 에러인지 확인\n */\nconst shouldRetry = (error: AxiosError): boolean => {\n // 네트워크 에러 또는 5xx 서버 에러만 재시도\n return (\n !error.response ||\n (error.response.status >= 500 && error.response.status < 600)\n );\n};\n\n/**\n * 지연 함수\n */\nconst delay = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms));\n};\n\n/**\n * 에러 처리 함수\n */\nconst handleError = (\n error: AxiosError,\n showError: boolean = true\n): ApiResponse => {\n let errorMessage = \"알 수 없는 오류가 발생했습니다.\";\n let errorCode = 500;\n\n if (error.response) {\n // 서버 응답이 있는 경우\n errorCode = error.response.status;\n const responseData = error.response.data as any;\n\n errorMessage =\n responseData?.message ||\n responseData?.error ||\n getErrorMessage(errorCode);\n } else if (error.request) {\n // 요청은 보냈지만 응답이 없는 경우\n errorMessage = \"서버에 연결할 수 없습니다.\";\n errorCode = 0;\n } else {\n // 요청 설정 중 에러\n errorMessage = error.message || \"요청 설정 중 오류가 발생했습니다.\";\n }\n\n // 에러 메시지 표시 (옵션)\n if (showError) {\n console.error(`API 에러 [${errorCode}]: ${errorMessage}`);\n // 여기서 전역 에러 처리 (예: toast, alert 등)를 할 수 있습니다\n }\n\n return {\n success: false,\n error: errorMessage,\n code: errorCode,\n };\n};\n\n/**\n * HTTP 상태 코드별 에러 메시지\n */\nconst getErrorMessage = (statusCode: number): string => {\n const errorMessages: Record<number, string> = {\n 400: \"잘못된 요청입니다.\",\n 401: \"인증이 필요합니다.\",\n 403: \"접근이 거부되었습니다.\",\n 404: \"요청한 리소스를 찾을 수 없습니다.\",\n 405: \"허용되지 않는 메서드입니다.\",\n 408: \"요청 시간이 초과되었습니다.\",\n 409: \"요청이 충돌했습니다.\",\n 422: \"처리할 수 없는 엔티티입니다.\",\n 429: \"너무 많은 요청이 발생했습니다.\",\n 500: \"서버 내부 오류가 발생했습니다.\",\n 502: \"잘못된 게이트웨이입니다.\",\n 503: \"서비스를 사용할 수 없습니다.\",\n 504: \"게이트웨이 시간 초과입니다.\",\n };\n\n return errorMessages[statusCode] || \"알 수 없는 오류가 발생했습니다.\";\n};\n\n// 편의 함수들\nexport const apiGet = <T = any>(\n trxCd: string,\n params?: any,\n options?: ApiOptions\n): Promise<T> => {\n return callService<T>(trxCd, params, { ...options, method: \"GET\" });\n};\n\nexport const apiPost = <T = any>(\n trxCd: string,\n data?: any,\n options?: ApiOptions\n): Promise<T> => {\n return callService<T>(trxCd, data, { ...options, method: \"POST\" });\n};\n\nexport const apiPut = <T = any>(\n trxCd: string,\n data?: any,\n options?: ApiOptions\n): Promise<T> => {\n return callService<T>(trxCd, data, { ...options, method: \"PUT\" });\n};\n\nexport const apiDelete = <T = any>(\n trxCd: string,\n data?: any,\n options?: ApiOptions\n): Promise<T> => {\n return callService<T>(trxCd, data, { ...options, method: \"DELETE\" });\n};\n\nexport const apiPatch = <T = any>(\n trxCd: string,\n data?: any,\n options?: ApiOptions\n): Promise<T> => {\n return callService<T>(trxCd, data, { ...options, method: \"PATCH\" });\n};\n\n/**\n * 권한 확인 서비스\n * @param userId 사용자 ID\n * @param menuId 메뉴 ID\n * @param popupId 팝업 ID (선택사항)\n * @returns 권한 정보\n */\nexport const getPermissionService = async (\n userId: string,\n menuId: string,\n popupId?: string\n) => {\n try {\n const response = await fetch(\"/api/permissions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n userId,\n menuId,\n popupId,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`권한 확인 실패: ${response.status}`);\n }\n\n const data = await response.json();\n return data;\n } catch (error) {\n console.error(\"권한 확인 서비스 오류:\", error);\n throw error;\n }\n};\n\n/**\n * 권한 정보 타입\n */\nexport interface PermissionInfo {\n // 공통 권한 버튼들\n commonButtons: Array<{\n id: string;\n label: string;\n type: \"primary\" | \"default\" | \"dashed\" | \"link\" | \"text\";\n disabled?: boolean;\n visible?: boolean;\n }>;\n // 커스텀 버튼 그룹들\n customButtonGroups: {\n [groupId: string]: {\n [buttonId: string]: {\n label: string;\n type: \"primary\" | \"default\" | \"dashed\" | \"link\" | \"text\";\n disabled?: boolean;\n visible?: boolean;\n isHeader?: boolean;\n };\n };\n };\n // 전체 권한 여부\n hasAccess: boolean;\n // 에러 메시지\n errorMessage?: string;\n}\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"],"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","r","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","errorCode","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","clientIp","setClientIp","ip","getClientIp","verifyClientIp","ApiError","detailMsg","response","msgCd","DEFAULT_OPTIONS","apiClient","axios","isLocal","getEnvCode","trxCd","guid","token","responseTime","refreshToken","refreshResponse","originalRequest","getGuid","callService","mergedOptions","currentClientIp","appCd","sysCd","requestData","lastError","attempt","header","basicMsg","axiosError","responseData","shouldRetry","delay","errorMessage","errorDescription","ms","resolve","apiGet","params","apiPost","apiPut","apiDelete","apiPatch","DEFAULT_SERVICE_CODES","serviceCodeOverrides","setServiceCodeOverrides","overrides","getServiceCode","serviceCodeKey","getAllServiceCodes"],"mappings":"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","x_google_ignoreList":[2]}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// dev_core/scripts/gen-component-registry.js
|
|
3
|
-
// ★ 자동 생성 스크립트 (marker-only)
|
|
4
|
-
// - export const cpntTabId (필수), export const cpntTabTitle (선택) 이 있는 파일만 레지스트리에 포함
|
|
5
|
-
// - 중복 cpntTabId 발견 시 빌드 실패
|
|
6
|
-
// - 접미사/폴더 규칙 없음 (원하면 GLOB_PATTERN 좁혀도 됨)
|
|
7
|
-
|
|
8
|
-
import fs from "node:fs";
|
|
9
|
-
import path from "node:path";
|
|
10
|
-
import fg from "fast-glob";
|
|
11
|
-
|
|
12
|
-
// ── CLI 인자 처리 ───────────────────────────────────────────────
|
|
13
|
-
const args = process.argv.slice(2);
|
|
14
|
-
let rootDir = process.cwd();
|
|
15
|
-
let includePattern = "src/pages/views/content/**/*.tsx";
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < args.length; i++) {
|
|
18
|
-
if (args[i] === "--root" && args[i + 1]) {
|
|
19
|
-
rootDir = path.resolve(args[i + 1]);
|
|
20
|
-
i++;
|
|
21
|
-
} else if (args[i] === "--include" && args[i + 1]) {
|
|
22
|
-
includePattern = args[i + 1];
|
|
23
|
-
i++;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ── 설정 ───────────────────────────────────────────────────────
|
|
28
|
-
const PKG_ROOT = rootDir;
|
|
29
|
-
const SRC_DIR = path.join(PKG_ROOT, "src");
|
|
30
|
-
|
|
31
|
-
// 스캔할 범위
|
|
32
|
-
const GLOB_PATTERN = includePattern;
|
|
33
|
-
const EXCLUDES = ["**/*.internal.*"];
|
|
34
|
-
|
|
35
|
-
// 생성 대상 파일(이 모듈을 앱에서 import)
|
|
36
|
-
const OUT_FILE = path.join(SRC_DIR, "pages", "views", "componentRegistry.ts");
|
|
37
|
-
|
|
38
|
-
// ── 유틸 ───────────────────────────────────────────────────────
|
|
39
|
-
function readFileSafe(p) {
|
|
40
|
-
try {
|
|
41
|
-
return fs.readFileSync(p, "utf8");
|
|
42
|
-
} catch {
|
|
43
|
-
return "";
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function extractMeta(src) {
|
|
48
|
-
// export const cpntTabId = '...'; export const cpntTabTitle = '...';
|
|
49
|
-
const id = src.match(/export\s+const\s+cpntTabId\s*=\s*["'`](.+?)["'`]/);
|
|
50
|
-
const cpntTabTitle = src.match(
|
|
51
|
-
/export\s+const\s+cpntTabTitle\s*=\s*["'`](.+?)["'`]/
|
|
52
|
-
);
|
|
53
|
-
return {
|
|
54
|
-
cpntTabId: id?.[1] ?? null,
|
|
55
|
-
cpntTabTitle: cpntTabTitle?.[1] ?? null,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function importPathFromRel(rel) {
|
|
60
|
-
// ./views로 시작하도록 경로 변경 (src/pages/ 제거)
|
|
61
|
-
return "./" + rel.replace(/\\/g, "/").replace("src/pages/views/", "");
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ── 메인 ───────────────────────────────────────────────────────
|
|
65
|
-
async function run() {
|
|
66
|
-
const files = await fg(GLOB_PATTERN, { ignore: EXCLUDES, onlyFiles: true });
|
|
67
|
-
const idSet = new Set();
|
|
68
|
-
const entries = [];
|
|
69
|
-
|
|
70
|
-
for (const rel of files) {
|
|
71
|
-
const abs = path.join(PKG_ROOT, rel);
|
|
72
|
-
const src = readFileSafe(abs);
|
|
73
|
-
if (!src) continue;
|
|
74
|
-
|
|
75
|
-
const { cpntTabId, cpntTabTitle } = extractMeta(src);
|
|
76
|
-
if (!cpntTabId) continue; // ✅ 마커 없는 파일 제외
|
|
77
|
-
|
|
78
|
-
if (idSet.has(cpntTabId)) {
|
|
79
|
-
console.error(`\n❌ 중복 cpntTabId 감지: "${cpntTabId}"`);
|
|
80
|
-
console.error(` 충돌 파일 중 하나: ${rel}`);
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
idSet.add(cpntTabId);
|
|
84
|
-
|
|
85
|
-
const importPath = importPathFromRel(rel);
|
|
86
|
-
const baseNameNoExt = path.basename(rel).replace(/\.[tj]sx?$/i, "");
|
|
87
|
-
entries.push({
|
|
88
|
-
cpntTabId,
|
|
89
|
-
label: cpntTabTitle || baseNameNoExt,
|
|
90
|
-
importPath,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// 정렬(가독성)
|
|
95
|
-
entries.sort((a, b) => a.cpntTabId.localeCompare(b.cpntTabId));
|
|
96
|
-
|
|
97
|
-
const header = `// ★ 자동 생성 파일 (수정 금지)
|
|
98
|
-
// 생성시각: ${new Date().toISOString()}
|
|
99
|
-
// 기준: export const cpntTabId[; cpntTabTitle] 마커가 있는 파일만 포함됩니다.
|
|
100
|
-
|
|
101
|
-
`;
|
|
102
|
-
|
|
103
|
-
const componentsBlock = `export const COMPONENTS: Record<string, () => Promise<any>> = {
|
|
104
|
-
${entries
|
|
105
|
-
.map(
|
|
106
|
-
(e) =>
|
|
107
|
-
` ${JSON.stringify(e.cpntTabId)}: () => import(${JSON.stringify(
|
|
108
|
-
e.importPath
|
|
109
|
-
)}),`
|
|
110
|
-
)
|
|
111
|
-
.join("\n")}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
`;
|
|
115
|
-
|
|
116
|
-
const labelsBlock = `export const COMPONENT_LABEL: Record<string, string> = {
|
|
117
|
-
${entries
|
|
118
|
-
.map((e) => ` ${JSON.stringify(e.cpntTabId)}: ${JSON.stringify(e.label)},`)
|
|
119
|
-
.join("\n")}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
`;
|
|
123
|
-
|
|
124
|
-
const code = header + componentsBlock + labelsBlock;
|
|
125
|
-
|
|
126
|
-
fs.mkdirSync(path.dirname(OUT_FILE), { recursive: true });
|
|
127
|
-
fs.writeFileSync(OUT_FILE, code, "utf8");
|
|
128
|
-
console.log(
|
|
129
|
-
`✅ Generated: ${path.relative(PKG_ROOT, OUT_FILE)} (entries: ${
|
|
130
|
-
entries.length
|
|
131
|
-
})`
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
run().catch((err) => {
|
|
136
|
-
console.error(err);
|
|
137
|
-
process.exit(1);
|
|
138
|
-
});
|