From faff32475f2c38870a5acc7c939399a4e999dd29 Mon Sep 17 00:00:00 2001 From: siujamo Date: Thu, 25 Dec 2025 16:12:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 0 .env.development | 0 .env.example | 6 + .env.production | 0 .gitignore | 105 + .prettierrc.yml | 24 + eslint.config.js | 42 + index.html | 13 + package.json | 42 + pnpm-lock.yaml | 3045 +++++++++++++++++++ public/vite.svg | 21 + src/api/auth/index.ts | 68 + src/api/department/index.ts | 13 + src/api/index.ts | 6 + src/api/menu/index.ts | 8 + src/api/position/index.ts | 9 + src/api/role/index.ts | 26 + src/api/user/index.ts | 88 + src/assets/dingtalk.svg | 1 + src/assets/discord.svg | 1 + src/assets/email.svg | 1 + src/assets/gitlab.svg | 1 + src/assets/google.svg | 1 + src/assets/lark.svg | 1 + src/assets/logo.svg | 66 + src/assets/microsoft.svg | 1 + src/assets/password.svg | 1 + src/assets/react.svg | 1 + src/assets/slack.svg | 1 + src/assets/wecom.svg | 1 + src/components/add-user-dialogue/index.tsx | 30 + src/components/edit-user-dialogue/index.tsx | 22 + src/components/icon/index.tsx | 99 + src/components/loading-fallback/index.tsx | 5 + src/components/protected-route/index.tsx | 22 + src/components/user-display-form/index.tsx | 200 ++ src/config/dayjs-config/index.ts | 11 + src/config/msal-config/index.ts | 17 + src/constant/http-status/index.ts | 66 + src/constant/index.ts | 1 + src/hooks/index.tsx | 20 + src/index.css | 13 + src/layouts/dashboard-layout/index.tsx | 134 + src/main.tsx | 32 + src/page/error/index.tsx | 33 + src/page/home/index.tsx | 7 + src/page/login/index.tsx | 373 +++ src/page/menu/index.tsx | 7 + src/page/not-found/index.tsx | 30 + src/page/register/index.tsx | 49 + src/page/role/index.tsx | 190 ++ src/page/user/index.tsx | 463 +++ src/router/index.tsx | 86 + src/service/auth/index.ts | 0 src/service/auth/msal/index.ts | 29 + src/service/web-client/index.ts | 38 + src/store/auth-slice/index.ts | 46 + src/store/index.ts | 47 + src/types/antd/index.ts | 14 + src/types/config/index.ts | 14 + src/types/constant/index.ts | 6 + src/types/entity/index.ts | 73 + src/types/form/index.ts | 31 + src/types/index.ts | 0 src/types/page/index.ts | 14 + src/types/route/index.ts | 6 + src/types/tree/index.ts | 37 + src/types/web/request/index.ts | 54 + src/types/web/response/index.ts | 39 + src/utils/department-utils/index.ts | 28 + src/utils/index.ts | 2 + src/utils/phone-number-utils/index.ts | 28 + src/vite-env.d.ts | 27 + tsconfig.app.json | 32 + tsconfig.json | 13 + tsconfig.node.json | 24 + vite.config.ts | 18 + 77 files changed, 6123 insertions(+) create mode 100644 .env create mode 100644 .env.development create mode 100644 .env.example create mode 100644 .env.production create mode 100644 .gitignore create mode 100644 .prettierrc.yml create mode 100644 eslint.config.js create mode 100644 index.html create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 public/vite.svg create mode 100644 src/api/auth/index.ts create mode 100644 src/api/department/index.ts create mode 100644 src/api/index.ts create mode 100644 src/api/menu/index.ts create mode 100644 src/api/position/index.ts create mode 100644 src/api/role/index.ts create mode 100644 src/api/user/index.ts create mode 100644 src/assets/dingtalk.svg create mode 100644 src/assets/discord.svg create mode 100644 src/assets/email.svg create mode 100644 src/assets/gitlab.svg create mode 100644 src/assets/google.svg create mode 100644 src/assets/lark.svg create mode 100644 src/assets/logo.svg create mode 100644 src/assets/microsoft.svg create mode 100644 src/assets/password.svg create mode 100644 src/assets/react.svg create mode 100644 src/assets/slack.svg create mode 100644 src/assets/wecom.svg create mode 100644 src/components/add-user-dialogue/index.tsx create mode 100644 src/components/edit-user-dialogue/index.tsx create mode 100644 src/components/icon/index.tsx create mode 100644 src/components/loading-fallback/index.tsx create mode 100644 src/components/protected-route/index.tsx create mode 100644 src/components/user-display-form/index.tsx create mode 100644 src/config/dayjs-config/index.ts create mode 100644 src/config/msal-config/index.ts create mode 100644 src/constant/http-status/index.ts create mode 100644 src/constant/index.ts create mode 100644 src/hooks/index.tsx create mode 100644 src/index.css create mode 100644 src/layouts/dashboard-layout/index.tsx create mode 100644 src/main.tsx create mode 100644 src/page/error/index.tsx create mode 100644 src/page/home/index.tsx create mode 100644 src/page/login/index.tsx create mode 100644 src/page/menu/index.tsx create mode 100644 src/page/not-found/index.tsx create mode 100644 src/page/register/index.tsx create mode 100644 src/page/role/index.tsx create mode 100644 src/page/user/index.tsx create mode 100644 src/router/index.tsx create mode 100644 src/service/auth/index.ts create mode 100644 src/service/auth/msal/index.ts create mode 100644 src/service/web-client/index.ts create mode 100644 src/store/auth-slice/index.ts create mode 100644 src/store/index.ts create mode 100644 src/types/antd/index.ts create mode 100644 src/types/config/index.ts create mode 100644 src/types/constant/index.ts create mode 100644 src/types/entity/index.ts create mode 100644 src/types/form/index.ts create mode 100644 src/types/index.ts create mode 100644 src/types/page/index.ts create mode 100644 src/types/route/index.ts create mode 100644 src/types/tree/index.ts create mode 100644 src/types/web/request/index.ts create mode 100644 src/types/web/response/index.ts create mode 100644 src/utils/department-utils/index.ts create mode 100644 src/utils/index.ts create mode 100644 src/utils/phone-number-utils/index.ts create mode 100644 src/vite-env.d.ts create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..e69de29 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..a2f6b70 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +# Backend base URL +VITE_API_BASE_URL=/api +# Microsoft Entra ID Client ID +VITE_MSAL_CLIENT_ID=msal-client-id +# Microsoft Entra ID Tenant ID +VITE_MSAL_TENANT_ID=msal-tenant-id diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..22f6f8b --- /dev/null +++ b/.gitignore @@ -0,0 +1,105 @@ +### macOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Linux +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# Metadata left by Dolphin file manager, which comes with KDE Plasma +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# Log files created by default by the nohup command +nohup.out + +### Windows + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### JetBrains IDE +# Covers JetBrains IDEs: IntelliJ, GoLand, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea + +# Gradle and Maven with auto-import +*.iml +*.ipr + +# File-based project format +*.iws + +# IntelliJ +out/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based HTTP Client +http-client.private.env.json + +# Node libraries +node_modules/ + +# Config +.env.local +.env.*.local diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..7612d53 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,24 @@ +printWidth: 100 +tabWidth: 2 +useTabs: false +semi: false +singleQuote: false +quoteProps: as-needed +jsxSingleQuote: false +trailingComma: es5 +bracketSpacing: true +bracketSameLine: true +arrowParens: always +#rangeStart: 0 +#rangeEnd: n +#parser: +#filepath: +#requirePragma: false +#insertPragma: false +#proseWrap: preserve +htmlWhitespaceSensitivity: css +#vueIndentScriptAndStyle: false +endOfLine: lf +#embeddedLanguageFormatting: auto +# Enforce single attribute per line in HTML, Vue and JSX +#singleAttributePerLine: false \ No newline at end of file diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..6f4a2f1 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,42 @@ +import js from "@eslint/js" +import globals from "globals" +import reactHooks from "eslint-plugin-react-hooks" +import reactRefresh from "eslint-plugin-react-refresh" +import tseslint from "typescript-eslint" +import { globalIgnores } from "eslint/config" + +export default tseslint.config([ + globalIgnores(["dist"]), + { + files: ["**/*.{ts,tsx}"], + extends: [ + js.configs.recommended, + reactHooks.configs["recommended-latest"], + reactRefresh.configs.vite, + // Remove tseslint.configs.recommended and use this for stricter rules + ...tseslint.configs.strictTypeChecked, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + project: ["./tsconfig.node.json", "./tsconfig.app.json"], + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + "@typescript-eslint/no-unused-vars": 0, + "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/restrict-template-expressions": 0, + "@typescript-eslint/no-unsafe-assignment": 0, + "@typescript-eslint/no-unsafe-call": 0, + "no-empty": 0, + "@typescript-eslint/no-unsafe-member-access": 0, + "no-empty-pattern": 0, + "@typescript-eslint/no-unnecessary-condition": 0, + "@typescript-eslint/no-confusing-void-expression": 0, + "@typescript-eslint/no-empty-object-type": 0, + "react-refresh/only-export-components": 0, + }, + }, +]) diff --git a/index.html b/index.html new file mode 100644 index 0000000..48e94cc --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Helix + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..dcbd0b8 --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "helix-web", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@ant-design/cssinjs": "^2.0.1", + "@ant-design/icons": "^6.1.0", + "@azure/msal-browser": "^4.27.0", + "@azure/msal-react": "^3.0.23", + "@reduxjs/toolkit": "^2.11.1", + "@tailwindcss/vite": "^4.1.17", + "antd": "^6.1.0", + "axios": "^1.13.2", + "dayjs": "^1.11.19", + "libphonenumber-js": "^1.12.31", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "react-redux": "^9.2.0", + "react-router": "^7.10.1", + "react-router-dom": "^7.10.1", + "redux-persist": "^6.0.0", + "tailwindcss": "^4.1.17" + }, + "devDependencies": { + "@types/node": "^20.19.26", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.7.0", + "globals": "^16.5.0", + "prettier": "^3.7.4", + "typescript": "^5.9.3", + "vite": "^7.2.7", + "vite-plugin-svgr": "^4.5.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..ead17ad --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3045 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ant-design/cssinjs': + specifier: ^2.0.1 + version: 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@ant-design/icons': + specifier: ^6.1.0 + version: 6.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@azure/msal-browser': + specifier: ^4.27.0 + version: 4.27.0 + '@azure/msal-react': + specifier: ^3.0.23 + version: 3.0.23(@azure/msal-browser@4.27.0)(react@19.2.1) + '@reduxjs/toolkit': + specifier: ^2.11.1 + version: 2.11.1(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1))(react@19.2.1) + '@tailwindcss/vite': + specifier: ^4.1.17 + version: 4.1.17(vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2)) + antd: + specifier: ^6.1.0 + version: 6.1.0(moment@2.30.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + axios: + specifier: ^1.13.2 + version: 1.13.2 + dayjs: + specifier: ^1.11.19 + version: 1.11.19 + libphonenumber-js: + specifier: ^1.12.31 + version: 1.12.31 + react: + specifier: ^19.2.1 + version: 19.2.1 + react-dom: + specifier: ^19.2.1 + version: 19.2.1(react@19.2.1) + react-redux: + specifier: ^9.2.0 + version: 9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1) + react-router: + specifier: ^7.10.1 + version: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react-router-dom: + specifier: ^7.10.1 + version: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + redux-persist: + specifier: ^6.0.0 + version: 6.0.0(react@19.2.1)(redux@5.0.1) + tailwindcss: + specifier: ^4.1.17 + version: 4.1.17 + devDependencies: + '@types/node': + specifier: ^20.19.26 + version: 20.19.26 + '@types/react': + specifier: ^19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@vitejs/plugin-react': + specifier: ^4.7.0 + version: 4.7.0(vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2)) + globals: + specifier: ^16.5.0 + version: 16.5.0 + prettier: + specifier: ^3.7.4 + version: 3.7.4 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: ^7.2.7 + version: 7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2) + vite-plugin-svgr: + specifier: ^4.5.0 + version: 4.5.0(rollup@4.53.3)(typescript@5.9.3)(vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2)) + +packages: + + '@ant-design/colors@8.0.0': + resolution: {integrity: sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==} + + '@ant-design/cssinjs-utils@2.0.2': + resolution: {integrity: sha512-Mq3Hm6fJuQeFNKSp3+yT4bjuhVbdrsyXE2RyfpJFL0xiYNZdaJ6oFaE3zFrzmHbmvTd2Wp3HCbRtkD4fU+v2ZA==} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + '@ant-design/cssinjs@2.0.1': + resolution: {integrity: sha512-Lw1Z4cUQxdMmTNir67gU0HCpTl5TtkKCJPZ6UBvCqzcOTl/QmMFB6qAEoj8qFl0CuZDX9qQYa3m9+rEKfaBSbA==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@ant-design/fast-color@3.0.0': + resolution: {integrity: sha512-eqvpP7xEDm2S7dUzl5srEQCBTXZMmY3ekf97zI+M2DHOYyKdJGH0qua0JACHTqbkRnD/KHFQP9J1uMJ/XWVzzA==} + engines: {node: '>=8.x'} + + '@ant-design/icons-svg@4.4.2': + resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} + + '@ant-design/icons@6.1.0': + resolution: {integrity: sha512-KrWMu1fIg3w/1F2zfn+JlfNDU8dDqILfA5Tg85iqs1lf8ooyGlbkA+TkwfOKKgqpUmAiRY1PTFpuOU2DAIgSUg==} + engines: {node: '>=8'} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@ant-design/react-slick@2.0.0': + resolution: {integrity: sha512-HMS9sRoEmZey8LsE/Yo6+klhlzU12PisjrVcydW3So7RdklyEd2qehyU6a7Yp+OYN72mgsYs3NFCyP2lCPFVqg==} + peerDependencies: + react: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@azure/msal-browser@4.27.0': + resolution: {integrity: sha512-bZ8Pta6YAbdd0o0PEaL1/geBsPrLEnyY/RDWqvF1PP9RUH8EMLvUMGoZFYS6jSlUan6KZ9IMTLCnwpWWpQRK/w==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@15.13.3': + resolution: {integrity: sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==} + engines: {node: '>=0.8.0'} + + '@azure/msal-react@3.0.23': + resolution: {integrity: sha512-tHvq441nwlJD9QfQP4ZStiw6xb2hQoujNHZhZb+wpUbImb3wyr2FF6/umhX/p+yzc/aq0Lee7mbdDDpzRZzxcA==} + engines: {node: '>=10'} + peerDependencies: + '@azure/msal-browser': ^4.27.0 + react: ^16.8.0 || ^17 || ^18 || ^19.2.1 + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@emotion/hash@0.8.0': + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + + '@emotion/unitless@0.7.5': + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@rc-component/async-validator@5.0.4': + resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} + engines: {node: '>=14.x'} + + '@rc-component/cascader@1.9.0': + resolution: {integrity: sha512-2jbthe1QZrMBgtCvNKkJFjZYC3uKl4N/aYm5SsMvO3T+F+qRT1CGsSM9bXnh1rLj7jDk/GK0natShWF/jinhWQ==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/checkbox@1.0.1': + resolution: {integrity: sha512-08yTH8m+bSm8TOqbybbJ9KiAuIATti6bDs2mVeSfu4QfEnyeF6X0enHVvD1NEAyuBWEAo56QtLe++MYs2D9XiQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/collapse@1.1.2': + resolution: {integrity: sha512-ilBYk1dLLJHu5Q74dF28vwtKUYQ42ZXIIDmqTuVy4rD8JQVvkXOs+KixVNbweyuIEtJYJ7+t+9GVD9dPc6N02w==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/color-picker@3.0.3': + resolution: {integrity: sha512-V7gFF9O7o5XwIWafdbOtqI4BUUkEUkgdBwp6favy3xajMX/2dDqytFaiXlcwrpq6aRyPLp5dKLAG5RFKLXMeGA==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/context@2.0.1': + resolution: {integrity: sha512-HyZbYm47s/YqtP6pKXNMjPEMaukyg7P0qVfgMLzr7YiFNMHbK2fKTAGzms9ykfGHSfyf75nBbgWw+hHkp+VImw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/dialog@1.5.1': + resolution: {integrity: sha512-by4Sf/a3azcb89WayWuwG19/Y312xtu8N81HoVQQtnsBDylfs+dog98fTAvLinnpeoWG52m/M7QLRW6fXR3l1g==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/drawer@1.3.0': + resolution: {integrity: sha512-rE+sdXEmv2W25VBQ9daGbnb4J4hBIEKmdbj0b3xpY+K7TUmLXDIlSnoXraIbFZdGyek9WxxGKK887uRnFgI+pQ==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/dropdown@1.0.2': + resolution: {integrity: sha512-6PY2ecUSYhDPhkNHHb4wfeAya04WhpmUSKzdR60G+kMNVUCX2vjT/AgTS0Lz0I/K6xrPMJ3enQbwVpeN3sHCgg==} + peerDependencies: + react: '>=16.11.0' + react-dom: '>=16.11.0' + + '@rc-component/form@1.4.0': + resolution: {integrity: sha512-C8MN/2wIaW9hSrCCtJmcgCkWTQNIspN7ARXLFA4F8PGr8Qxk39U5pS3kRK51/bUJNhb/fEtdFnaViLlISGKI2A==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/image@1.5.3': + resolution: {integrity: sha512-/NR7QW9uCN8Ugar+xsHZOPvzPySfEhcW2/vLcr7VPRM+THZMrllMRv7LAUgW7ikR+Z67Ab67cgPp5K5YftpJsQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/input-number@1.6.2': + resolution: {integrity: sha512-Gjcq7meZlCOiWN1t1xCC+7/s85humHVokTBI7PJgTfoyw5OWF74y3e6P8PHX104g9+b54jsodFIzyaj6p8LI9w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/input@1.1.2': + resolution: {integrity: sha512-Q61IMR47piUBudgixJ30CciKIy9b1H95qe7GgEKOmSJVJXvFRWJllJfQry9tif+MX2cWFXWJf/RXz4kaCeq/Fg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@rc-component/mentions@1.6.0': + resolution: {integrity: sha512-KIkQNP6habNuTsLhUv0UGEOwG67tlmE7KNIJoQZZNggEZl5lQJTytFDb69sl5CK3TDdISCTjKP3nGEBKgT61CQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/menu@1.2.0': + resolution: {integrity: sha512-VWwDuhvYHSnTGj4n6bV3ISrLACcPAzdPOq3d0BzkeiM5cve8BEYfvkEhNoM0PLzv51jpcejeyrLXeMVIJ+QJlg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/mini-decimal@1.1.0': + resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} + engines: {node: '>=8.x'} + + '@rc-component/motion@1.1.6': + resolution: {integrity: sha512-aEQobs/YA0kqRvHIPjQvOytdtdRVyhf/uXAal4chBjxDu6odHckExJzjn2D+Ju1aKK6hx3pAs6BXdV9+86xkgQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/mutate-observer@2.0.1': + resolution: {integrity: sha512-AyarjoLU5YlxuValRi+w8JRH2Z84TBbFO2RoGWz9d8bSu0FqT8DtugH3xC3BV7mUwlmROFauyWuXFuq4IFbH+w==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/notification@1.2.0': + resolution: {integrity: sha512-OX3J+zVU7rvoJCikjrfW7qOUp7zlDeFBK2eA3SFbGSkDqo63Sl4Ss8A04kFP+fxHSxMDIS9jYVEZtU1FNCFuBA==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/overflow@1.0.0': + resolution: {integrity: sha512-GSlBeoE0XTBi5cf3zl8Qh7Uqhn7v8RrlJ8ajeVpEkNe94HWy5l5BQ0Mwn2TVUq9gdgbfEMUmTX7tJFAg7mz0Rw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/pagination@1.2.0': + resolution: {integrity: sha512-YcpUFE8dMLfSo6OARJlK6DbHHvrxz7pMGPGmC/caZSJJz6HRKHC1RPP001PRHCvG9Z/veD039uOQmazVuLJzlw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/picker@1.8.0': + resolution: {integrity: sha512-ek4efrIy+peC8WFJg6Lg7c+WNkykr+wUGQGBNoKmlF0K752aIJuaPcBj6p8CceT9vSJ9gOeeclQCBQIFWVDk1A==} + engines: {node: '>=12.x'} + peerDependencies: + date-fns: '>= 2.x' + dayjs: '>= 1.x' + luxon: '>= 3.x' + moment: '>= 2.x' + react: '>=16.9.0' + react-dom: '>=16.9.0' + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + + '@rc-component/portal@2.0.1': + resolution: {integrity: sha512-46KYuA7Udb1LAaLIdDrfmDz3wzyeEZxIURJCn+heoQVbhtW5PQkhBSQtRus+DUdsknmTFQulxSnqrbX3CI4yXw==} + engines: {node: '>=12.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/progress@1.0.2': + resolution: {integrity: sha512-WZUnH9eGxH1+xodZKqdrHke59uyGZSWgj5HBM5Kwk5BrTMuAORO7VJ2IP5Qbm9aH3n9x3IcesqHHR0NWPBC7fQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/qrcode@1.1.1': + resolution: {integrity: sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/rate@1.0.1': + resolution: {integrity: sha512-bkXxeBqDpl5IOC7yL7GcSYjQx9G8H+6kLYQnNZWeBYq2OYIv1MONd6mqKTjnnJYpV0cQIU2z3atdW0j1kttpTw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/resize-observer@1.0.1': + resolution: {integrity: sha512-r+w+Mz1EiueGk1IgjB3ptNXLYSLZ5vnEfKHH+gfgj7JMupftyzvUUl3fRcMZe5uMM04x0n8+G2o/c6nlO2+Wag==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/segmented@1.2.3': + resolution: {integrity: sha512-L7G4S6zUpqHclOXK0wKKN2/VyqHa9tfDNxkoFjWOTPtQ0ROFaBwZhbf1+9sdZfIFkxJkpcShAmDOMEIBaFFqkw==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@rc-component/select@1.3.4': + resolution: {integrity: sha512-NKhzahL/lXk3aKtmeH5W/jIqaPKcx9QiFXOvJxKe8eiuusIcSCW+XvJdjY3nRvCpTZCZDp7e1RaCU95gohx6Ow==} + engines: {node: '>=8.x'} + peerDependencies: + react: '*' + react-dom: '*' + + '@rc-component/slider@1.0.1': + resolution: {integrity: sha512-uDhEPU1z3WDfCJhaL9jfd2ha/Eqpdfxsn0Zb0Xcq1NGQAman0TWaR37OWp2vVXEOdV2y0njSILTMpTfPV1454g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/steps@1.2.2': + resolution: {integrity: sha512-/yVIZ00gDYYPHSY0JP+M+s3ZvuXLu2f9rEjQqiUDs7EcYsUYrpJ/1bLj9aI9R7MBR3fu/NGh6RM9u2qGfqp+Nw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/switch@1.0.3': + resolution: {integrity: sha512-Jgi+EbOBquje/XNdofr7xbJQZPYJP+BlPfR0h+WN4zFkdtB2EWqEfvkXJWeipflwjWip0/17rNbxEAqs8hVHfw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/table@1.9.0': + resolution: {integrity: sha512-cq3P9FkD+F3eglkFYhBuNlHclg+r4jY8+ZIgK7zbEFo6IwpnA77YL/Gq4ensLw9oua3zFCTA6JDu6YgBei0TxA==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/tabs@1.7.0': + resolution: {integrity: sha512-J48cs2iBi7Ho3nptBxxIqizEliUC+ExE23faspUQKGQ550vaBlv3aGF8Epv/UB1vFWeoJDTW/dNzgIU0Qj5i/w==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/textarea@1.1.2': + resolution: {integrity: sha512-9rMUEODWZDMovfScIEHXWlVZuPljZ2pd1LKNjslJVitn4SldEzq5vO1CL3yy3Dnib6zZal2r2DPtjy84VVpF6A==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/tooltip@1.4.0': + resolution: {integrity: sha512-8Rx5DCctIlLI4raR0I0xHjVTf1aF48+gKCNeAAo5bmF5VoR5YED+A/XEqzXv9KKqrJDRcd3Wndpxh2hyzrTtSg==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/tour@2.2.1': + resolution: {integrity: sha512-BUCrVikGJsXli38qlJ+h2WyDD6dYxzDA9dV3o0ij6gYhAq6ooT08SUMWOikva9v4KZ2BEuluGl5bPcsjrSoBgQ==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/tree-select@1.4.0': + resolution: {integrity: sha512-I3UAlO2hNqy9CSKc8EBaESgnmKk2QaRzuZ2XHZGFCgsSMkGl06mdF97sVfROM02YIb64ocgLKefsjE0Ch4ocwQ==} + peerDependencies: + react: '*' + react-dom: '*' + + '@rc-component/tree@1.1.0': + resolution: {integrity: sha512-HZs3aOlvFgQdgrmURRc/f4IujiNBf4DdEeXUlkS0lPoLlx9RoqsZcF0caXIAMVb+NaWqKtGQDnrH8hqLCN5zlA==} + engines: {node: '>=10.x'} + peerDependencies: + react: '*' + react-dom: '*' + + '@rc-component/trigger@3.7.1': + resolution: {integrity: sha512-+YNP8FywxKJpdqzlAp6TN8UbSK6YsQtIs3kI13mHfm87qi3qUd5Q9AGW8Unfv76kXFUSu7U7D0FygRsGH+6MiA==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/upload@1.1.0': + resolution: {integrity: sha512-LIBV90mAnUE6VK5N4QvForoxZc4XqEYZimcp7fk+lkE4XwHHyJWxpIXQQwMU8hJM+YwBbsoZkGksL1sISWHQxw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/util@1.6.0': + resolution: {integrity: sha512-YbjuIVAm8InCnXVoA4n6G+uh31yESTxQ6fSY2frZ2/oMSvktoB+bumFUfNN7RKh7YeOkZgOvN2suGtEDhJSX0A==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + '@rc-component/virtual-list@1.0.2': + resolution: {integrity: sha512-uvTol/mH74FYsn5loDGJxo+7kjkO4i+y4j87Re1pxJBs0FaeuMuLRzQRGaXwnMcV1CxpZLi2Z56Rerj2M00fjQ==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@reduxjs/toolkit@2.11.1': + resolution: {integrity: sha512-HjhlEREguAyBTGNzRlGNiDHGQ2EjLSPWwdhhpoEqHYy8hWak3Dp6/fU72OfqVsiMb8S6rbfPsWUF24fxpilrVA==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + cpu: [x64] + os: [win32] + + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + + '@svgr/plugin-jsx@8.1.0': + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@tailwindcss/node@4.1.17': + resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + + '@tailwindcss/oxide-android-arm64@4.1.17': + resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.17': + resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.17': + resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.17': + resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node@20.19.26': + resolution: {integrity: sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.7': + resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + antd@6.1.0: + resolution: {integrity: sha512-RIe4W5saaL9SWgvqCcvz6LZta/KwT50B0YF7xYiWVZh0Gqfw2rJAsOMcp202Hxgm+YiyoSp4QqqvexKhuGGarw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + + baseline-browser-mapping@2.9.5: + resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==} + hasBin: true + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + compute-scroll-into-view@3.1.1: + resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + immer@11.0.1: + resolution: {integrity: sha512-naDCyggtcBWANtIrjQEajhhBEuL9b0Zg4zmlWK2CzS6xCWSE39/vvf4LqnMjUAWHBhot4m9MHCM/Z+mfWhUkiA==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-mobile@5.0.0: + resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json2mq@0.2.0: + resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + libphonenumber-js@1.12.31: + resolution: {integrity: sha512-Z3IhgVgrqO1S5xPYM3K5XwbkDasU67/Vys4heW+lfSBALcUZjeIIzI8zCLifY+OCzSq+fpDdywMDa7z+4srJPQ==} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + engines: {node: '>=14'} + hasBin: true + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + react-dom@19.2.1: + resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} + peerDependencies: + react: ^19.2.1 + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-redux@9.2.0: + resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-router-dom@7.10.1: + resolution: {integrity: sha512-JNBANI6ChGVjA5bwsUIwJk7LHKmqB4JYnYfzFwyp2t12Izva11elds2jx7Yfoup2zssedntwU0oZ5DEmk5Sdaw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.10.1: + resolution: {integrity: sha512-gHL89dRa3kwlUYtRQ+m8NmxGI6CgqN+k4XyGjwcFoQwwCWF6xXpOCUlDovkXClS0d0XJN/5q7kc5W3kiFEd0Yw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react@19.2.1: + resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} + engines: {node: '>=0.10.0'} + + redux-persist@6.0.0: + resolution: {integrity: sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==} + peerDependencies: + react: '>=16' + redux: '>4.0.0' + peerDependenciesMeta: + react: + optional: true + + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scroll-into-view-if-needed@3.1.0: + resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + string-convert@0.2.1: + resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + + tailwindcss@4.1.17: + resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.2.2: + resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + vite-plugin-svgr@4.5.0: + resolution: {integrity: sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==} + peerDependencies: + vite: '>=2.6.0' + + vite@7.2.7: + resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + +snapshots: + + '@ant-design/colors@8.0.0': + dependencies: + '@ant-design/fast-color': 3.0.0 + + '@ant-design/cssinjs-utils@2.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@ant-design/cssinjs': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@babel/runtime': 7.28.4 + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@ant-design/cssinjs@2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.8.0 + '@emotion/unitless': 0.7.5 + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + csstype: 3.2.3 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + stylis: 4.3.6 + + '@ant-design/fast-color@3.0.0': {} + + '@ant-design/icons-svg@4.4.2': {} + + '@ant-design/icons@6.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@ant-design/colors': 8.0.0 + '@ant-design/icons-svg': 4.4.2 + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@ant-design/react-slick@2.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + clsx: 2.1.1 + json2mq: 0.2.0 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + throttle-debounce: 5.0.2 + + '@azure/msal-browser@4.27.0': + dependencies: + '@azure/msal-common': 15.13.3 + + '@azure/msal-common@15.13.3': {} + + '@azure/msal-react@3.0.23(@azure/msal-browser@4.27.0)(react@19.2.1)': + dependencies: + '@azure/msal-browser': 4.27.0 + react: 19.2.1 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@emotion/hash@0.8.0': {} + + '@emotion/unitless@0.7.5': {} + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@rc-component/async-validator@5.0.4': + dependencies: + '@babel/runtime': 7.28.4 + + '@rc-component/cascader@1.9.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/select': 1.3.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tree': 1.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/checkbox@1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/collapse@1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/color-picker@3.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@ant-design/fast-color': 3.0.0 + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/context@2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/dialog@1.5.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/portal': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/drawer@1.3.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/portal': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/dropdown@1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/form@1.4.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/async-validator': 5.0.4 + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/image@1.5.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/portal': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/input-number@1.6.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/mini-decimal': 1.1.0 + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/input@1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/mentions@1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/input': 1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/menu': 1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/textarea': 1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/menu@1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/overflow': 1.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/mini-decimal@1.1.0': + dependencies: + '@babel/runtime': 7.28.4 + + '@rc-component/motion@1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/mutate-observer@2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/notification@1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/overflow@1.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/pagination@1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/picker@1.8.0(dayjs@1.11.19)(moment@2.30.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + optionalDependencies: + dayjs: 1.11.19 + moment: 2.30.1 + + '@rc-component/portal@2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/progress@1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/qrcode@1.1.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/rate@1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/resize-observer@1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/segmented@1.2.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/select@1.3.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/slider@1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/steps@1.2.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/switch@1.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/table@1.9.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/context': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/tabs@1.7.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/dropdown': 1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/menu': 1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/textarea@1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/input': 1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/tooltip@1.4.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/tour@2.2.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/portal': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/tree-select@1.4.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/select': 1.3.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tree': 1.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/tree@1.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/trigger@3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/portal': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/upload@1.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@rc-component/util@1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + is-mobile: 5.0.0 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-is: 18.3.1 + + '@rc-component/virtual-list@1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@reduxjs/toolkit@2.11.1(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1))(react@19.2.1)': + dependencies: + '@standard-schema/spec': 1.0.0 + '@standard-schema/utils': 0.3.0 + immer: 11.0.1 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.2.1 + react-redux: 9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1) + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/pluginutils@5.3.0(rollup@4.53.3)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.53.3 + + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true + + '@rollup/rollup-android-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-x64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + + '@standard-schema/spec@1.0.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) + + '@svgr/core@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.28.5 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + + '@tailwindcss/node@4.1.17': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.17 + + '@tailwindcss/oxide-android-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide@4.1.17': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-x64': 4.1.17 + '@tailwindcss/oxide-freebsd-x64': 4.1.17 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-x64-musl': 4.1.17 + '@tailwindcss/oxide-wasm32-wasi': 4.1.17 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 + + '@tailwindcss/vite@4.1.17(vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@tailwindcss/node': 4.1.17 + '@tailwindcss/oxide': 4.1.17 + tailwindcss: 4.1.17 + vite: 7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2) + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/estree@1.0.8': {} + + '@types/node@20.19.26': + dependencies: + undici-types: 6.21.0 + + '@types/react-dom@19.2.3(@types/react@19.2.7)': + dependencies: + '@types/react': 19.2.7 + + '@types/react@19.2.7': + dependencies: + csstype: 3.2.3 + + '@types/use-sync-external-store@0.0.6': {} + + '@vitejs/plugin-react@4.7.0(vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - supports-color + + antd@6.1.0(moment@2.30.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + '@ant-design/colors': 8.0.0 + '@ant-design/cssinjs': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@ant-design/cssinjs-utils': 2.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@ant-design/fast-color': 3.0.0 + '@ant-design/icons': 6.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@ant-design/react-slick': 2.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@babel/runtime': 7.28.4 + '@rc-component/cascader': 1.9.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/checkbox': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/collapse': 1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/color-picker': 3.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/dialog': 1.5.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/drawer': 1.3.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/dropdown': 1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/form': 1.4.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/image': 1.5.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/input': 1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/input-number': 1.6.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/mentions': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/menu': 1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/motion': 1.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/notification': 1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/pagination': 1.2.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/picker': 1.8.0(dayjs@1.11.19)(moment@2.30.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/progress': 1.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/qrcode': 1.1.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/rate': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/segmented': 1.2.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/select': 1.3.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/slider': 1.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/steps': 1.2.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/switch': 1.0.3(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/table': 1.9.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tabs': 1.7.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/textarea': 1.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tooltip': 1.4.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tour': 2.2.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tree': 1.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/tree-select': 1.4.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/trigger': 3.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/upload': 1.1.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@rc-component/util': 1.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + dayjs: 1.11.19 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + scroll-into-view-if-needed: 3.1.0 + throttle-debounce: 5.0.2 + transitivePeerDependencies: + - date-fns + - luxon + - moment + + argparse@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.13.2: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + baseline-browser-mapping@2.9.5: {} + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.5 + caniuse-lite: 1.0.30001760 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.2(browserslist@4.28.1) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001760: {} + + clsx@2.1.1: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + compute-scroll-into-view@3.1.1: {} + + convert-source-map@2.0.0: {} + + cookie@1.1.1: {} + + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + + csstype@3.2.3: {} + + dayjs@1.11.19: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.267: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@4.5.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escalade@3.2.0: {} + + estree-walker@2.0.2: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + follow-redirects@1.15.11: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + globals@16.5.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + immer@11.0.1: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + is-arrayish@0.2.1: {} + + is-mobile@5.0.0: {} + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json2mq@0.2.0: + dependencies: + string-convert: 0.2.1 + + json5@2.2.3: {} + + libphonenumber-js@1.12.31: {} + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + lines-and-columns@1.2.4: {} + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + moment@2.30.1: + optional: true + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-releases@2.0.27: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-type@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.7.4: {} + + proxy-from-env@1.1.0: {} + + react-dom@19.2.1(react@19.2.1): + dependencies: + react: 19.2.1 + scheduler: 0.27.0 + + react-is@18.3.1: {} + + react-redux@9.2.0(@types/react@19.2.7)(react@19.2.1)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.1 + use-sync-external-store: 1.6.0(react@19.2.1) + optionalDependencies: + '@types/react': 19.2.7 + redux: 5.0.1 + + react-refresh@0.17.0: {} + + react-router-dom@7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-router: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + + react-router@7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + cookie: 1.1.1 + react: 19.2.1 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.1(react@19.2.1) + + react@19.2.1: {} + + redux-persist@6.0.0(react@19.2.1)(redux@5.0.1): + dependencies: + redux: 5.0.1 + optionalDependencies: + react: 19.2.1 + + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + + reselect@5.1.1: {} + + resolve-from@4.0.0: {} + + rollup@4.53.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 + fsevents: 2.3.3 + + scheduler@0.27.0: {} + + scroll-into-view-if-needed@3.1.0: + dependencies: + compute-scroll-into-view: 3.1.1 + + semver@6.3.1: {} + + set-cookie-parser@2.7.2: {} + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + source-map-js@1.2.1: {} + + string-convert@0.2.1: {} + + stylis@4.3.6: {} + + svg-parser@2.0.4: {} + + tailwindcss@4.1.17: {} + + tapable@2.3.0: {} + + throttle-debounce@5.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tslib@2.8.1: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.2.2(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-sync-external-store@1.6.0(react@19.2.1): + dependencies: + react: 19.2.1 + + vite-plugin-svgr@4.5.0(rollup@4.53.3)(typescript@5.9.3)(vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2)): + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.53.3) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + vite: 7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + + vite@7.2.7(@types/node@20.19.26)(jiti@2.6.1)(lightningcss@1.30.2): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 20.19.26 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + + yallist@3.1.1: {} diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..a8bc145 --- /dev/null +++ b/public/vite.svg @@ -0,0 +1,21 @@ + diff --git a/src/api/auth/index.ts b/src/api/auth/index.ts new file mode 100644 index 0000000..d750f62 --- /dev/null +++ b/src/api/auth/index.ts @@ -0,0 +1,68 @@ +import webClient from "@/service/web-client" +import { HttpStatus } from "@/constant" +import type { CaptchaResponse, UserAuthResponse } from "@/types/web/response" +import type { UsernamePasswordLoginRequest } from "@/types/web/request" + +/** + * 获取验证码图片及验证码 UUID + */ +async function getCaptcha(): Promise { + const { data, status } = await webClient.get("/captcha") + if (status == HttpStatus.OK) { + return data as CaptchaResponse + } else { + return null + } +} + +/** + * 使用用户名密码登录 + * @param request 用户名密码 + */ +async function usernamePasswordLogin( + request: UsernamePasswordLoginRequest +): Promise { + const { data } = await webClient.post("/auth/login", request) + return data +} + +/** + * 使用企业微信登录 + * @param code 由企业微信提供的身份验证 code + */ +async function wecomLogin(code: string): Promise { + const urlSearchParams = new URLSearchParams() + urlSearchParams.append("code", code) + + + const { data } = await webClient.get(`/auth/wecom/login?${urlSearchParams.toString()}`) + return data +} + +/** + * 使用 Microsoft Entra 登录 + * @param msalToken 由 Microsoft Entra 提供的用户身份令牌 + */ +async function msalLogin(msalToken: string): Promise { + const { data, headers } = await webClient.post(`/auth/msal/login`, { + msalToken, + }) + + const token = (headers as Record).authorization ?? "" + + if (!token) { + return Promise.reject(new Error("未获取到身份令牌,登录失败")) + } + + return data +} + +/** + * 获取注册功能是否启用 + */ +async function fetchRegisterEnabled() { + const { data } = await webClient.get("/auth/register-enabled") + return data +} + +export { usernamePasswordLogin, wecomLogin, msalLogin, getCaptcha, fetchRegisterEnabled } diff --git a/src/api/department/index.ts b/src/api/department/index.ts new file mode 100644 index 0000000..e7bd189 --- /dev/null +++ b/src/api/department/index.ts @@ -0,0 +1,13 @@ +import webClient from "@/service/web-client" +import type { TreeNode } from "@/types/tree" +import type { Department } from "@/types/entity" + +export async function fetchDepartmentTree(): Promise> { + const { data } = await webClient.get>("/departments/tree") + return data +} + +export async function fetchDepartments(): Promise { + const { data } = await webClient.get("/departments") + return data +} diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..5c1d525 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,6 @@ +export * as AuthApi from "./auth" +export * as MenuApi from "./menu" +export * as DeptApi from "./department" +export * as UserApi from "./user" +export * as PositionApi from "./position" +export * as RoleApi from "./role" diff --git a/src/api/menu/index.ts b/src/api/menu/index.ts new file mode 100644 index 0000000..4defb0e --- /dev/null +++ b/src/api/menu/index.ts @@ -0,0 +1,8 @@ +import webClient from "@/service/web-client" +import type { TreeNode } from "@/types/tree" +import type { MenuItem } from "@/types/entity" + +export async function fetchMenuTree() { + const { data } = await webClient.get[]>("/menus") + return data +} diff --git a/src/api/position/index.ts b/src/api/position/index.ts new file mode 100644 index 0000000..0c8a79b --- /dev/null +++ b/src/api/position/index.ts @@ -0,0 +1,9 @@ +import webClient from "@/service/web-client" +import type { QueryPositionRequest } from "@/types/web/request" +import type { PageResponse } from "@/types/web/response" +import type { Position } from "@/types/entity" + +export async function fetchPositions(request: QueryPositionRequest): Promise> { + const { data } = await webClient.get>("/positions") + return data +} diff --git a/src/api/role/index.ts b/src/api/role/index.ts new file mode 100644 index 0000000..df036ac --- /dev/null +++ b/src/api/role/index.ts @@ -0,0 +1,26 @@ +import type { QueryRoleRequest } from "@/types/web/request" +import webClient from "@/service/web-client" +import type { PageResponse, RoleResponse } from "@/types/web/response" + +export async function fetchRoles( + request: QueryRoleRequest | null +): Promise { + const params = new URLSearchParams() + params.append("pageNum", `${request?.pageNum ?? 1}`) + params.append("pageSize", `${request?.pageSize ?? 1}`) + + if (request?.name) { + params.append("name", request.name) + } + + if (request?.code) { + params.append("code", request.code) + } + + if (request?.status) { + params.append("status", request.status) + } + + const { data } = await webClient.get(`/roles?${params.toString()}`) + return data +} diff --git a/src/api/user/index.ts b/src/api/user/index.ts new file mode 100644 index 0000000..34adf46 --- /dev/null +++ b/src/api/user/index.ts @@ -0,0 +1,88 @@ +import webClient from "@/service/web-client" +import { getCountryCallingCode } from "libphonenumber-js" +import { getDefaultCountryCode } from "@/utils/phone-number-utils" +import type { AddUserRequest, EditUserRequest, QueryUserRequest } from "@/types/web/request" +import type { PageResponse, UserDetailResponse } from "@/types/web/response" +import type { UserFormValues } from "@/types/form" + +export async function fetchUsers( + request?: QueryUserRequest +): Promise> { + const urlSearchParam = new URLSearchParams() + urlSearchParam.append("pageNum", `${request?.pageNum ?? 1}`) + urlSearchParam.append("pageSize", `${request?.pageSize ?? 10}`) + + if (request?.departmentId) { + urlSearchParam.append("departmentId", `${request.departmentId}`) + } + + if (request?.username) { + urlSearchParam.append("username", request.username) + } + + if (request?.regionAbbreviation) { + urlSearchParam.append("regionAbbreviation", request.regionAbbreviation) + } + + if (request?.phoneNumber) { + urlSearchParam.append("phoneNumber", request.phoneNumber) + } + + if (request?.status) { + urlSearchParam.append("status", request.status) + } + + if (request?.createdAtStart) { + urlSearchParam.append("createdAtStart", request.createdAtStart) + } + + if (request?.createdAtEnd) { + urlSearchParam.append("createdAtEnd", request.createdAtEnd) + } + + const { data } = await webClient.get>( + `/users?${urlSearchParam.toString()}` + ) + return data +} + +export async function fetchUserById(userId: number): Promise { + const { data } = await webClient.get(`/users/${userId}`) + return data +} + +export async function addUser(values: UserFormValues) { + await webClient.post("/users", { + username: values.username, + password: values.password, + fullName: values.fullName, + email: values.email, + regionAbbreviation: values.regionAbbreviation ?? getDefaultCountryCode(), + phoneNumber: values.phoneNumber, + avatarUrl: values.avatarUrl, + status: values.status, + departmentId: values.departmentId, + positionId: values.positionId, + roleIds: [], + } as AddUserRequest) +} + +export async function editUser(values: UserFormValues) { + await webClient.put("/users", { + id: values.id, + username: values.username, + fullName: values.fullName, + email: values.email, + regionAbbreviation: values.regionAbbreviation ?? getDefaultCountryCode(), + phoneNumber: values.phoneNumber, + avatarUrl: values.avatarUrl, + status: values.status, + departmentId: values.departmentId, + positionId: values.positionId, + roleIds: [], + } as EditUserRequest) +} + +export async function deleteUser(userId: number | string) { + await webClient.delete(`/users/${userId}`) +} diff --git a/src/assets/dingtalk.svg b/src/assets/dingtalk.svg new file mode 100644 index 0000000..97fb5a3 --- /dev/null +++ b/src/assets/dingtalk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/discord.svg b/src/assets/discord.svg new file mode 100644 index 0000000..fb73caa --- /dev/null +++ b/src/assets/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/email.svg b/src/assets/email.svg new file mode 100644 index 0000000..f878707 --- /dev/null +++ b/src/assets/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/gitlab.svg b/src/assets/gitlab.svg new file mode 100644 index 0000000..e3c800e --- /dev/null +++ b/src/assets/gitlab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/google.svg b/src/assets/google.svg new file mode 100644 index 0000000..77cdb81 --- /dev/null +++ b/src/assets/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/lark.svg b/src/assets/lark.svg new file mode 100644 index 0000000..c26c6a7 --- /dev/null +++ b/src/assets/lark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..e958d9c --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/microsoft.svg b/src/assets/microsoft.svg new file mode 100644 index 0000000..89f6237 --- /dev/null +++ b/src/assets/microsoft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/password.svg b/src/assets/password.svg new file mode 100644 index 0000000..7ceee90 --- /dev/null +++ b/src/assets/password.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/react.svg b/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/slack.svg b/src/assets/slack.svg new file mode 100644 index 0000000..2514288 --- /dev/null +++ b/src/assets/slack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/wecom.svg b/src/assets/wecom.svg new file mode 100644 index 0000000..91b6f30 --- /dev/null +++ b/src/assets/wecom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/add-user-dialogue/index.tsx b/src/components/add-user-dialogue/index.tsx new file mode 100644 index 0000000..f0d7898 --- /dev/null +++ b/src/components/add-user-dialogue/index.tsx @@ -0,0 +1,30 @@ +import { type FormInstance } from "antd" +import UserDisplayForm from "@/components/user-display-form" +import type { UserFormValues } from "@/types/form" + +interface AddUserProps { + form: FormInstance +} + +export default function AddUserDialogue({ form }: AddUserProps) { + return ( + + ) +} diff --git a/src/components/edit-user-dialogue/index.tsx b/src/components/edit-user-dialogue/index.tsx new file mode 100644 index 0000000..2703e62 --- /dev/null +++ b/src/components/edit-user-dialogue/index.tsx @@ -0,0 +1,22 @@ +import type { FormInstance } from "antd" +import UserDisplayForm from "@/components/user-display-form" +import type { User } from "@/types/entity" +import type { UserFormValues } from "@/types/form" + +interface EditUserProps { + user: User + form: FormInstance +} + +export default function EditUserDialogue({ user, form }: EditUserProps) { + return ( + + ) +} diff --git a/src/components/icon/index.tsx b/src/components/icon/index.tsx new file mode 100644 index 0000000..192dc40 --- /dev/null +++ b/src/components/icon/index.tsx @@ -0,0 +1,99 @@ +import type { ForwardRefExoticComponent } from "react" +import Icon from "@ant-design/icons" + +import BrandMicrosoft from "@/assets/microsoft.svg?react" +import BrandDingTalk from "@/assets/dingtalk.svg?react" +import BrandWeCom from "@/assets/wecom.svg?react" +import BrandLark from "@/assets/lark.svg?react" +import BrandSlack from "@/assets/slack.svg?react" +import BrandGoogle from "@/assets/google.svg?react" +import BrandGitlab from "@/assets/gitlab.svg?react" +import BrandEmail from "@/assets/email.svg?react" +import BrandDiscord from "@/assets/discord.svg?react" +import Logo from "@/assets/logo.svg?react" +import type { AntIconComponentProps } from "@/types/antd" + +/** + * Microsoft 图标 + * @param props Icon 属性 + * @constructor + */ +export function MicrosoftFilled(props: Partial) { + return } {...props} /> +} + +/** + * 钉钉图标 + * @param props Icon 属性 + * @constructor + */ +export function DingTalkFilled(props: Partial) { + return } {...props} /> +} + +/** + * 企业微信图标 + * @param props Icon 属性 + * @constructor + */ +export function WeComFilled(props: Partial) { + return } {...props} /> +} + +/** + * 飞书图标 + * @param props Icon 属性 + * @constructor + */ +export function LarkFilled(props: Partial) { + return } {...props} /> +} + +/** + * Slack 图标 + * @param props Icon 属性 + * @constructor + */ +export function SlackFilled(props: Partial) { + return } {...props} /> +} + +/** + * Google 图标 + * @param props Icon 属性 + * @constructor + */ +export function GoogleFilled(props: Partial) { + return } {...props} /> +} + +/** + * GitLab 图标 + * @param props Icon 属性 + * @constructor + */ +export function GitlabFilled(props: Partial) { + return } {...props} /> +} + +/** + * Email 图标 + * @param props Icon 属性 + * @constructor + */ +export function EmailFilled(props: Partial) { + return } {...props} /> +} + +/** + * Discord 图标 + * @param props Icon 属性 + * @constructor + */ +export function DiscordFilled(props: Partial) { + return } {...props} /> +} + +export function ApplicationLogo(props: Partial) { + return } {...props} /> +} diff --git a/src/components/loading-fallback/index.tsx b/src/components/loading-fallback/index.tsx new file mode 100644 index 0000000..fc1adb9 --- /dev/null +++ b/src/components/loading-fallback/index.tsx @@ -0,0 +1,5 @@ +import { Spin } from "antd" + +export default function LoadingFallback() { + return +} diff --git a/src/components/protected-route/index.tsx b/src/components/protected-route/index.tsx new file mode 100644 index 0000000..b93b92b --- /dev/null +++ b/src/components/protected-route/index.tsx @@ -0,0 +1,22 @@ +import { Navigate, Outlet, useLocation } from "react-router" +import { useAppSelector } from "@/store" +import DashboardLayout from "@/layouts/dashboard-layout" + +/** + * 需要身份验证的前置组件 + * @constructor + */ +export default function ProtectedRoute() { + const isAuthenticated = useAppSelector((state) => state.auth.isAuthenticated) + const location = useLocation() + + if (!isAuthenticated) { + return + } + + return ( + + + + ) +} diff --git a/src/components/user-display-form/index.tsx b/src/components/user-display-form/index.tsx new file mode 100644 index 0000000..69225bf --- /dev/null +++ b/src/components/user-display-form/index.tsx @@ -0,0 +1,200 @@ +import { useEffect, useMemo, useState } from "react" +import { App, Checkbox, Form, type FormInstance, Input, Select, Space, TreeSelect } from "antd" +import type { AxiosError } from "axios" +import { getCountries, getCountryCallingCode } from "libphonenumber-js" +import { DeptApi, PositionApi } from "@/api" +import type { UserFormValues } from "@/types/form" +import type { Department, Position } from "@/types/entity" +import type { GeneralErrorResponse } from "@/types/web/response" +import type { AntTreeSelectOption } from "@/types/antd" + +interface UserDisplayFormProps { + initialValues?: UserFormValues + isEditing: boolean + isAdding?: boolean + form: FormInstance +} + +const countryOptions = getCountries().map((country) => { + const callingCode = getCountryCallingCode(country) + return { + label: `${country} (+${callingCode})`, + value: country, + key: country, + } +}) + +function transformDepartmentToTree(departments: Department[]): AntTreeSelectOption[] { + const sortedDepartments = [...departments].sort((a, b) => a.sort - b.sort) + + const map: Record> = {} + const tree: AntTreeSelectOption[] = [] + + sortedDepartments.forEach((dept) => { + map[dept.id] = { + label: dept.name, + value: dept.id, + children: [], + } + }) + + sortedDepartments.forEach((dept) => { + const node = map[dept.id] + if (dept.parentId !== null && map[dept.parentId]) { + map[dept.parentId].children!.push(node) + } else { + tree.push(node) + } + }) + return tree +} + +export default function UserDisplayForm({ + initialValues, + isEditing, + form, + isAdding = false, +}: UserDisplayFormProps) { + // Get message wrapper from Antd + const { message } = App.useApp() + + // Build form values. + const initialFormValues: UserFormValues | undefined = initialValues + ? ({ + ...initialValues, + password: "", + } as UserFormValues) + : undefined + + // Department state used to save all departments + const [departments, setDepartments] = useState([]) + // Position state used to save all positions + const [positions, setPositions] = useState([]) + + // Departments options + const departmentOptions = useMemo(() => { + return transformDepartmentToTree(departments) + }, [departments]) + + const positionOptions = useMemo(() => { + return positions.map((position) => ({ + label: position.name, + value: position.id, + key: position.id, + })) + }, [positions]) + + // Initialise form values + useEffect(() => { + if (initialFormValues) { + form.setFieldsValue(initialFormValues) + } else { + form.resetFields() + } + }, [initialValues, form]) + + // Initialise department data on component mounted + useEffect(() => { + const fetchDepartmentsFuture = DeptApi.fetchDepartments() + const fetchPositionsFuture = PositionApi.fetchPositions({ pageNum: 1, pageSize: 999 }) + + Promise.all([fetchDepartmentsFuture, fetchPositionsFuture]) + .then(([departments, positionPage]) => { + setDepartments(departments) + setPositions(positionPage.content) + }) + .catch((error: unknown) => { + const err = error as AxiosError + void message.error(err.response?.data.message ?? "获取部门或岗位数据失败,请稍后再试") + }) + }, []) + + return ( + + form={form} + initialValues={initialFormValues} + layout="vertical" + labelAlign="right" + disabled={!isEditing}> + label="用户 ID" name="id" hidden={isAdding}> + + + + + label="全名" + name="fullName" + rules={[{ required: true, message: "用户全名不能为空" }]}> + + + + + label="用户名" + name="username" + rules={[{ required: true, message: "请输入用户名" }]}> + + + + {isAdding && ( + + label="密码" + name="password" + rules={[{ required: true, message: "请输入密码" }]}> + + + )} + + + label="电子邮箱" + name="email" + rules={[ + { type: "email", message: "邮箱格式不正确" }, + { required: true, message: "邮箱不能为空" }, + ]}> + + + + label="联系电话" required> + + + noStyle + name="regionAbbreviation" + rules={[{ required: true, message: "请选择国际电信区域码" }]}> + + + + + + + label="用户状态" + name="status" + rules={[{ required: true, message: "用户状态不能为空" }]}> + + + + ) +} diff --git a/src/config/dayjs-config/index.ts b/src/config/dayjs-config/index.ts new file mode 100644 index 0000000..b48e603 --- /dev/null +++ b/src/config/dayjs-config/index.ts @@ -0,0 +1,11 @@ +// 配置插件 +import dayjs from "dayjs" + +import duration from "dayjs/plugin/duration" +dayjs.extend(duration) + +// 配置语言 +import "dayjs/locale/zh-cn" +dayjs.locale("zh-cn") + +console.log("Global Dayjs plugins initialised.") diff --git a/src/config/msal-config/index.ts b/src/config/msal-config/index.ts new file mode 100644 index 0000000..81bfabb --- /dev/null +++ b/src/config/msal-config/index.ts @@ -0,0 +1,17 @@ +import { type Configuration, PublicClientApplication } from "@azure/msal-browser" + +const clientId = import.meta.env.VITE_MSAL_CLIENT_ID +const tenantId = import.meta.env.VITE_MSAL_TENANT_ID + +const msalConfig: Configuration = { + auth: { + clientId, + authority: `https://login.microsoftonline.com/${tenantId}`, + redirectUri: "http://localhost:5173" + }, + cache: { + cacheLocation: "localStorage", + } +} + +export const msalInstance = new PublicClientApplication(msalConfig) \ No newline at end of file diff --git a/src/constant/http-status/index.ts b/src/constant/http-status/index.ts new file mode 100644 index 0000000..8d79423 --- /dev/null +++ b/src/constant/http-status/index.ts @@ -0,0 +1,66 @@ +/** + * HTTP 状态码 + */ +export const HttpStatus = { + CONTINUE: 100, + SWITCHING_PROTOCOLS: 101, + PROCESSING: 102, + EARLY_HINTS: 103, + OK: 200, + CREATED: 201, + ACCEPTED: 202, + NON_AUTHORITATIVE_INFORMATION: 203, + NO_CONTENT: 204, + RESET_CONTENT: 205, + PARTIAL_CONTENT: 206, + MULTI_STATUS: 207, + ALREADY_REPORTED: 208, + IM_USED: 226, + MULTIPLE_CHOICES: 300, + MOVED_PERMANENTLY: 301, + FOUND: 302, + SEE_OTHER: 303, + NOT_MODIFIED: 304, + USE_PROXY: 305, + TEMPORARY_REDIRECT: 307, + PERMANENT_REDIRECT: 308, + BAD_REQUEST: 400, + UNAUTHORIZED: 401, + PAYMENT_REQUIRED: 402, + FORBIDDEN: 403, + NOT_FOUND: 404, + METHOD_NOT_ALLOWED: 405, + NOT_ACCEPTABLE: 406, + PROXY_AUTHENTICATION_REQUIRED: 407, + REQUEST_TIMEOUT: 408, + CONFLICT: 409, + GONE: 410, + LENGTH_REQUIRED: 411, + PRECONDITION_FAILED: 412, + PAYLOAD_TOO_LARGE: 413, + URI_TOO_LONG: 414, + UNSUPPORTED_MEDIA_TYPE: 415, + RANGE_NOT_SATISFIABLE: 416, + EXPECTATION_FAILED: 417, + I_AM_A_TEAPOT: 418, + UNPROCESSABLE_ENTITY: 422, + LOCKED: 423, + FAILED_DEPENDENCY: 424, + TOO_EARLY: 425, + UPGRADE_REQUIRED: 426, + PRECONDITION_REQUIRED: 428, + TOO_MANY_REQUESTS: 429, + REQUEST_HEADER_FIELDS_TOO_LARGE: 431, + UNAVAILABLE_FOR_LEGAL_REASONS: 451, + INTERNAL_SERVER_ERROR: 500, + NOT_IMPLEMENTED: 501, + BAD_GATEWAY: 502, + SERVICE_UNAVAILABLE: 503, + GATEWAY_TIMEOUT: 504, + HTTP_VERSION_NOT_SUPPORTED: 505, + VARIANT_ALSO_NEGOTIATES: 506, + INSUFFICIENT_STORAGE: 507, + LOOP_DETECTED: 508, + NOT_EXTENDED: 510, + NETWORK_AUTHENTICATION_REQUIRED: 511, +} diff --git a/src/constant/index.ts b/src/constant/index.ts new file mode 100644 index 0000000..4b4f38e --- /dev/null +++ b/src/constant/index.ts @@ -0,0 +1 @@ +export { HttpStatus } from "./http-status" diff --git a/src/hooks/index.tsx b/src/hooks/index.tsx new file mode 100644 index 0000000..bf22bea --- /dev/null +++ b/src/hooks/index.tsx @@ -0,0 +1,20 @@ +import { useMatches } from "react-router" +import type { BreadcrumbItemType } from "antd/es/breadcrumb/Breadcrumb" +import type { RouteHandle } from "@/types/route" + +export function useAntBreadcrumbs(): BreadcrumbItemType[] { + const matches = useMatches() + + return matches + .filter((match) => (match.handle as RouteHandle)?.label) + .map((match) => { + const handle = match.handle as RouteHandle + + const path = match.pathname + const title = handle.label || "" + + return { + title, + } + }) +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..8e47a54 --- /dev/null +++ b/src/index.css @@ -0,0 +1,13 @@ +@layer theme, base, antd, components, utilities; +@import "tailwindcss"; + +html, body { + margin: 0; + padding: 0; + height: 100vh; + overflow: hidden; +} + +#root { + height: 100%; +} diff --git a/src/layouts/dashboard-layout/index.tsx b/src/layouts/dashboard-layout/index.tsx new file mode 100644 index 0000000..3a18e6f --- /dev/null +++ b/src/layouts/dashboard-layout/index.tsx @@ -0,0 +1,134 @@ +import React, { useEffect, useState } from "react" +import { useNavigate } from "react-router" +import { Avatar, Breadcrumb, Dropdown, Layout, Menu, type MenuProps, Modal, Space } from "antd" +import { DownOutlined } from "@ant-design/icons" +import { ApplicationLogo } from "@/components/icon" +import { useAppDispatch, useAppSelector } from "@/store" +import { useAntBreadcrumbs } from "@/hooks" +import { logout } from "@/store/auth-slice" +import { MenuApi } from "@/api" +import type { AxiosError } from "axios" +import type { TreeNode } from "@/types/tree" +import type { MenuItem } from "@/types/entity" + +const { Header, Footer, Sider, Content } = Layout +type AntMenuItem = Required["items"][number] + +function transformMenuData(nodes: TreeNode[]): AntMenuItem[] { + if (!nodes || nodes.length === 0) { + return [] + } + + return nodes + .sort((a, b) => a.item.sort - b.item.sort) + .map((node) => { + const { item, children } = node + const hasChildren = children && children.length > 0 + + const menuItem: AntMenuItem = { + key: item.code, + label: item.name, + } + + if (hasChildren) { + // Append children + return { ...menuItem, children: transformMenuData(children) } + } + + return menuItem + }) +} + +export default function DashboardLayout({ children }: { children: React.ReactNode }) { + const user = useAppSelector((store) => store.auth.user!) + const dispatch = useAppDispatch() + const breadcrumbItems = useAntBreadcrumbs() + const navigate = useNavigate() + + const onLogout = ({ key }: { key: string }) => { + if (key == "logout") { + Modal.confirm({ + title: "确定要注销吗?", + okText: "确定", + cancelText: "取消", + onOk: () => { + dispatch(logout()) + void navigate("/login") + }, + maskClosable: false, + keyboard: false, + }) + } + } + + const [menuItems, setMenuItems] = useState([]) + + useEffect(() => { + MenuApi.fetchMenuTree() + .then((response) => { + setMenuItems(transformMenuData(response)) + }) + .catch((error: unknown) => { + const err = error as AxiosError + console.log(err) + }) + }, []) + + const dropDownMenuItems: MenuProps["items"] = [ + { + key: "logout", + danger: true, + label: "注销", + }, + ] + + return ( + +
+
+ + Onixbyte Hi-Tech Co., Ltd +
+ +
+ + + {user.fullName} + + + + +
+
+ + + { + console.log(`key = ${key}`) + switch (key) { + case "user-mgmt": + void navigate("/users") + break + case "role-mgmt": + void navigate("/roles") + break + case "menu-mgmt": + void navigate("/menus") + break + } + }} + /> + + + + {children} + + + + ) +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..aa00697 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,32 @@ +import { StrictMode } from "react" +import { createRoot } from "react-dom/client" +import { Provider as ReduxProvider } from "react-redux" +import { PersistGate } from "redux-persist/integration/react" +import { RouterProvider } from "react-router" +import { App as AntApp, ConfigProvider as AntConfigProvider } from "antd" +import { StyleProvider } from "@ant-design/cssinjs" +import AntSimplifiedChinese from "antd/locale/zh_CN" +import "./index.css" +import "@/config/dayjs-config" +import store, { persistor } from "@/store" +import router from "@/router" + +createRoot(document.getElementById("root")!).render( + + + + + + + + + + + + + +) diff --git a/src/page/error/index.tsx b/src/page/error/index.tsx new file mode 100644 index 0000000..8cadb5f --- /dev/null +++ b/src/page/error/index.tsx @@ -0,0 +1,33 @@ +import React from "react" +import { Link } from "react-router-dom" + +/** + * 携带错误信息的通用错误展示页 + * + * @param message 自定义的错误信息,默认为`发生了未知错误,请稍后再试` + * @constructor + */ +export default function ErrorPage({ message = "发生了未知错误,请稍后再试" }) { + return ( +
+
+
+
+
+

⚠️

+

+ 系统出现了一些异常。 +

+

{message}

+

我们已经知晓该问题并正在进行处理。

+ + 返回主页 + +
+
+ ) +} diff --git a/src/page/home/index.tsx b/src/page/home/index.tsx new file mode 100644 index 0000000..cec1b11 --- /dev/null +++ b/src/page/home/index.tsx @@ -0,0 +1,7 @@ +import { useAppSelector } from "@/store" + +export default function HomePage() { + const user = useAppSelector((store) => store.auth.user!) + + return <>Welcome to Helix, {user.fullName} +} diff --git a/src/page/login/index.tsx b/src/page/login/index.tsx new file mode 100644 index 0000000..f439e5b --- /dev/null +++ b/src/page/login/index.tsx @@ -0,0 +1,373 @@ +import { type MouseEvent, useCallback, useEffect, useState } from "react" +import { Link, useNavigate } from "react-router" +import { Form, Input, Button, Card, message, Divider } from "antd" +import dayjs from "dayjs" +import type { AxiosError } from "axios" +// import { useMsal } from "@azure/msal-react" +import { AuthApi } from "@/api" +import { useAppDispatch, useAppSelector } from "@/store" +import { loginSuccess, updateRegistrationEnabled } from "@/store/auth-slice" +import { + DingTalkFilled, + GoogleFilled, + LarkFilled, + MicrosoftFilled, + SlackFilled, + WeComFilled, + GitlabFilled, + DiscordFilled, + EmailFilled, +} from "@/components/icon" + +import { GithubFilled } from "@ant-design/icons" +import { fetchRegisterEnabled } from "@/api/auth" +import type { UsernamePasswordLoginRequest } from "@/types/web/request" +import type { CaptchaResponse, GeneralErrorResponse } from "@/types/web/response" + +export default function LoginPage() { + const registrationEnabled = useAppSelector((state) => state.auth.registrationEnabled) + const dispatch = useAppDispatch() + const navigate = useNavigate() + + // const msalContext = useMsal() + + const [messageApi, contextHolder] = message.useMessage() + const [form] = Form.useForm() + + // const [isLoading, setIsLoading] = useState(false) + const [hasCaptcha, setHasCaptcha] = useState(false) + const [captchaData, setCaptchaData] = useState() + + const fetchCaptcha = useCallback(async () => { + try { + const response = await AuthApi.getCaptcha() + if (response) { + setHasCaptcha(true) + setCaptchaData(response) + form.setFieldValue("uuid", response.uuid) + } else { + setHasCaptcha(false) + setCaptchaData(null) + form.setFieldValue("uuid", null) + } + } catch (error) { + console.error("Failed to fetch captcha due to an error:", error) + setHasCaptcha(false) + setCaptchaData(null) + form.setFieldValue("uuid", null) + } + }, [form]) + + useEffect(() => { + void fetchCaptcha() + }, [fetchCaptcha]) + + useEffect(() => { + void fetchRegisterEnabled().then((enabled) => { + dispatch(updateRegistrationEnabled(enabled)) + }) + }, [dispatch]) + + /** + * 用户名密码登录 + */ + const performLogin = useCallback( + async (values: UsernamePasswordLoginRequest) => { + try { + console.log("Login values:", values) + + const loginResponse = await AuthApi.usernamePasswordLogin(values) + if (loginResponse) { + dispatch( + loginSuccess({ + user: loginResponse.user, + token: loginResponse.accessToken, + }) + ) + messageApi.success("登录成功", dayjs.duration({ seconds: 3 }).asSeconds()) + await navigate("/") + } else { + messageApi.error("登录失败:服务器响应异常。") + } + } catch (errorInfo: unknown) { + const error = errorInfo as AxiosError + console.log(error) + messageApi.error( + error.response?.data.message ?? "登录失败,请稍后再试", + dayjs.duration({ seconds: 3 }).asSeconds() + ) + } + }, + [dispatch, navigate, messageApi] + ) + + /** + * 刷新验证码图片 + */ + const refreshCaptcha = (event: MouseEvent) => { + event.preventDefault() + void fetchCaptcha() + } + + /** + * 使用 Microsoft Entra ID 登录 + */ + const performMsalLogin = () => { + console.log("使用 Microsoft 账号登录") + // void doMsalLogin(msalContext.instance, dispatch, () => void navigate("/")) + } + + /** + * 使用 DingTalk 登录 + */ + const performDingTalkLogin = () => { + console.log("使用钉钉登录") + // todo implement this + } + + /** + * 使用 WeCom 登录 + */ + const performWeComLogin = () => { + console.log("使用企业微信登录") + // todo implement this + } + + /** + * 使用 Lark 登录 + */ + const performLarkLogin = () => { + console.log("使用飞书登录") + // todo implement this + } + + /** + * 使用 Slack 登录 + */ + const performSlackLogin = () => { + console.log("使用 Slack 登录") + // todo implement this + } + + /** + * 使用 Github 登录 + */ + const performGithubLogin = () => { + console.log("使用 GitHub 登录") + // todo implement this + } + + /** + * 使用 Google 登录 + */ + const performGoogleLogin = () => { + console.log("使用 Google 登录") + // todo implement this + } + + /** + * 使用 Gitlab 登录 + */ + const performGitlabLogin = () => { + console.log("使用 Gitlab 登录") + // todo implement this + } + + /** + * 使用 Discord 登录 + */ + const performDiscordLogin = () => { + console.log("使用 Discord 登录") + // todo implement this + } + + /** + * 使用 Email 登录 + */ + const performEmailLogin = () => { + console.log("使用 Email 登录") + // todo implement this + } + + return ( +
+ {contextHolder} + + {/* 背景装饰元素 */} +
+
+
+ + +

欢迎回来

+

请登录您的账户

+
+ } + className="w-full max-w-md shadow-2xl border-0 backdrop-blur-sm bg-white/90 relative z-10" + styles={{ + body: { + padding: "32px", + }, + }}> + + name="usernamePasswordLoginForm" + form={form} + onFinish={(values) => { + void performLogin(values) + }} + layout="vertical" + className="space-y-4"> + + label={用户名} + name="username" + rules={[{ required: true, message: "请输入用户名!" }]}> + + + + + label={密码} + name="password" + rules={[{ required: true, message: "请输入密码!" }]}> + + + + {hasCaptcha ? ( + <> + + label={验证码} + name="captcha" + rules={[{ required: true, message: "请输入验证码!" }]}> +
+ + {captchaData?.captcha && ( + 验证码 + )} +
+ + name="uuid" hidden> +
Placeholder
+ + + ) : null} + + + + + + + {registrationEnabled ? ( +
+ 还没有账号?立即注册 +
+ ) : null} + + + 第三方帐号登录 + + +
+
+ +
+

© 2024 Your Company. All rights reserved.

+
+ + + ) +} diff --git a/src/page/menu/index.tsx b/src/page/menu/index.tsx new file mode 100644 index 0000000..d466fd1 --- /dev/null +++ b/src/page/menu/index.tsx @@ -0,0 +1,7 @@ +export default function MenuPage() { + return ( + <> +
菜单管理
+ + ) +} diff --git a/src/page/not-found/index.tsx b/src/page/not-found/index.tsx new file mode 100644 index 0000000..664bb41 --- /dev/null +++ b/src/page/not-found/index.tsx @@ -0,0 +1,30 @@ +import { Link } from "react-router" + +/** + * General page not found page. + * @constructor + */ +export default function NotFoundPage() { + return ( +
+
+
+
+ +
+

404

+

找不到页面

+

+ 找不到您需要的页面,您是否输入了错误的地址? +

+ + 返回主页 + +
+
+ ) +} diff --git a/src/page/register/index.tsx b/src/page/register/index.tsx new file mode 100644 index 0000000..fcfe59c --- /dev/null +++ b/src/page/register/index.tsx @@ -0,0 +1,49 @@ +import { useEffect } from "react" +import { useNavigate } from "react-router" +import dayjs from "dayjs" +import type { AxiosError } from "axios" +import { message } from "antd" + +import { AuthApi } from "@/api" +import type { GeneralErrorResponse } from "@/types/web/response" + +export default function RegisterPage() { + const [messageApi, contextHolder] = message.useMessage() + const navigate = useNavigate() + + useEffect(() => { + let cancelled = false + + AuthApi.fetchRegisterEnabled() + .then((enabled) => { + if (!enabled && !cancelled) { + void messageApi + .error("注册功能暂未开放", dayjs.duration({ seconds: 3 }).asSeconds()) + .then(() => { + if (!cancelled) { + void navigate("/login") + } + }) + } + }) + .catch((reason: unknown) => { + if (cancelled) return + const error = reason as AxiosError + void messageApi.error(error.response?.data.message ?? "发生未知错误,请稍后再试") + }) + + return () => { + cancelled = true + } + }, [messageApi, navigate]) + + return ( +
+ {contextHolder} +
+
+
+
注册页
+
+ ) +} diff --git a/src/page/role/index.tsx b/src/page/role/index.tsx new file mode 100644 index 0000000..e8b4cf8 --- /dev/null +++ b/src/page/role/index.tsx @@ -0,0 +1,190 @@ +import { useEffect, useState } from "react" +import type { AxiosError } from "axios" +import { App, Button, Form, Input, Select, Space, Switch, Table } from "antd" +import type { Role } from "@/types/entity" +import { RoleApi } from "@/api" +import type { QueryRoleRequest } from "@/types/web/request" +import type { GeneralErrorResponse, RoleResponse } from "@/types/web/response" +import { + DeleteOutlined, + ExportOutlined, + ImportOutlined, + PlusOutlined, + SearchOutlined, + UndoOutlined, +} from "@ant-design/icons" +import type { QueryRoleForm } from "@/types/form" +import type { Status } from "@/types/constant" + +export default function RolePage() { + const { message } = App.useApp() + + const [queryForm] = Form.useForm() + const [roles, setRoles] = useState([]) + const [pageNum, setPageNum] = useState(1) + const [pageSize, setPageSize] = useState(10) + const [totalElementCount, setTotalElementCount] = useState(0) + + const queryRoles = (pageNum: number, pageSize: number, queryRoleForm: QueryRoleForm | null) => { + const queryRoleRequest: QueryRoleRequest = { + code: queryRoleForm?.qCode ?? null, + name: queryRoleForm?.qName ?? null, + status: queryRoleForm?.qStatus ?? null, + pageNum, + pageSize, + } + + RoleApi.fetchRoles(queryRoleRequest) + .then((response) => { + console.log("role response", response) + setPageNum(response.pageable.pageNumber + 1) + setPageSize(response.pageable.pageSize) + setTotalElementCount(response.totalElements) + setRoles(response.content.sort((role1, role2) => role1.sort - role2.sort)) + }) + .catch((error) => { + const err = error as AxiosError + void message.error(err.response?.data.message ?? "获取角色失败") + }) + } + + const changeRoleStatus = (roleId: number | string, checked: boolean) => { + const status: Status = checked ? "ACTIVE" : "INACTIVE" + setRoles((prevRoles) => + prevRoles.map((role) => (role.id === roleId ? { ...role, status } : role)) + ) + } + + useEffect(() => { + queryRoles(pageNum, pageSize, null) + }, [pageNum, pageSize]) + + return ( +
+ + form={queryForm} + className="mt-0 mb-6" + layout="inline" + labelAlign="right" + onFinish={(values) => { + queryRoles(pageNum, pageSize, values) + }} + onReset={() => { + queryRoles(pageNum, pageSize, null) + }}> + label="角色名称" name="qName"> + + + label="角色编码" name="qCode"> + + + label="角色状态" name="qStatus"> + + className="w-26" + options={[ + { + label: "已启用", + value: "ACTIVE", + }, + { + label: "未启用", + value: "INACTIVE", + }, + ]} + /> + + > + + + + + + + + + + + + + + + + columns={[ + { title: "角色编号", dataIndex: "id" }, + { title: "角色名称", dataIndex: "name" }, + { title: "角色编码", dataIndex: "code" }, + { title: "显示顺序", dataIndex: "sort" }, + { + title: "状态", + key: "status", + render: (role: Role) => ( + <> + changeRoleStatus(role.id, checked)} + /> + + ), + }, + { + title: "默认角色", + key: "defaultValue", + render: (role: Role) => ( + <> + + + ), + }, + { title: "创建时间", dataIndex: "createdAt" }, + { + title: "操作", + render: (role: Role) => ( + <> + + + + + + ), + key: "operations", + }, + ]} + dataSource={roles} + rowKey="id" + pagination={{ + current: pageNum, + total: totalElementCount, + pageSize: pageSize, + defaultCurrent: 1, + defaultPageSize: 10, + pageSizeOptions: [10, 25, 50], + showSizeChanger: true, + onShowSizeChange: (pageNum, pageSize) => { + console.log(`onSizeChange ==> pageNum = ${pageNum}, pageSize = ${pageSize}`) + setPageNum(pageNum) + setPageSize(pageSize) + }, + onChange: (pageNum, pageSize) => { + console.log(`onChange ==> pageNum = ${pageNum}, pageSize = ${pageSize}`) + setPageNum(pageNum) + setPageSize(pageSize) + }, + }} + /> +
+ ) +} diff --git a/src/page/user/index.tsx b/src/page/user/index.tsx new file mode 100644 index 0000000..963f7ff --- /dev/null +++ b/src/page/user/index.tsx @@ -0,0 +1,463 @@ +import { type Key, useEffect, useState } from "react" +import { + Avatar, + Button, + DatePicker, + Form, + Input, + Select, + Space, + Table, + Tag, + Tree, + type TreeDataNode, + Typography, +} from "antd" +import { App } from "antd" +import { type AxiosError } from "axios" +import { getCountries, getCountryCallingCode } from "libphonenumber-js" +import { DeptApi, UserApi } from "@/api" +import { PhoneNumberUtils, DepartmentUtils } from "@/utils" +import { + DeleteOutlined, + EditOutlined, + ExportOutlined, + ImportOutlined, + KeyOutlined, + PlusOutlined, + SearchOutlined, + UndoOutlined, +} from "@ant-design/icons" +import AddUserDialogue from "@/components/add-user-dialogue" +import EditUserDialogue from "@/components/edit-user-dialogue" +import type { QueryUserRequest } from "@/types/web/request" +import type { QueryUserForm, UserFormValues } from "@/types/form" +import type { GeneralErrorResponse, UserDetailResponse } from "@/types/web/response" +import type { Department } from "@/types/entity" +import type { TreeNode } from "@/types/tree" +import { useAppSelector } from "@/store" + +export default function UserPage() { + const { message, modal } = App.useApp() + + const user = useAppSelector((state) => state.auth.user!) + + const [queryForm] = Form.useForm() + const [addUserForm] = Form.useForm() + const [editUserForm] = Form.useForm() + const [department, setDepartment] = useState>() + const [departmentTree, setDepartmentTree] = useState([]) + const [selectedDepartment, setSelectedDepartment] = useState(1) + const [users, setUsers] = useState([]) + const [pageNum, setPageNum] = useState(1) + const [totalElementCount, setTotalElementCount] = useState(0) + const [pageSize, setPageSize] = useState(10) + + const onAddUserFinish = async () => { + try { + const values = await addUserForm.validateFields() + + await UserApi.addUser(values) + + void message.success(`用户 ${values.username} 创建成功`) + return true + } catch (error: unknown) { + console.log(error) + if (error instanceof Error && error.message.includes("Validation Failed")) { + return false + } + const err = error as AxiosError + void message.error(err.response?.data.message ?? "创建失败,请稍后再试") + return false + } + } + + const handleAddUser = () => { + modal + .confirm({ + title: "添加用户", + content: , + width: 600, + onOk: onAddUserFinish, + }) + .then( + () => { + const formValues = queryForm.getFieldsValue() + queryUsers(pageNum, pageSize, selectedDepartment!, formValues) + }, + () => { + console.error("用户取消添加用户") + } + ) + } + + const onEditUserFinish = async () => { + try { + const values = await editUserForm.validateFields() + + await UserApi.editUser(values) + + void message.success(`用户更新成功`) + return true + } catch (error: unknown) { + if (error instanceof Error && error.message.includes("Validation Failed")) { + return false + } + const err = error as AxiosError + void message.error(err.response?.data.message ?? "更新失败,请稍后再试") + return false + } + } + + const handleEditUser = (user: UserDetailResponse) => { + modal + .confirm({ + title: `编辑用户: ${user.username}`, + content: , + width: 600, + onOk: onEditUserFinish, + }) + .then( + () => { + const formValues = queryForm.getFieldsValue() + queryUsers(pageNum, pageSize, selectedDepartment, formValues) + }, + () => { + console.error("用户取消添加用户") + } + ) + } + + const handleDeleteUser = (user: UserDetailResponse) => { + const isLastElementOnPage = users.length === 1 && pageNum > 1 + modal.confirm({ + title: ( + <> + 确认删除用户 {user.username} 吗? + + ), + content: "删除后数据将无法恢复。", + okText: "删除", + cancelText: "取消", + okButtonProps: { danger: true }, + onOk: async () => { + try { + await UserApi.deleteUser(user.id) + void message.success(`用户 ${user.username} 删除成功`) + setTotalElementCount((count) => count - 1) + if (isLastElementOnPage) { + setPageNum((prevPage) => prevPage - 1) + } else { + queryUsers(pageNum, pageSize, selectedDepartment, queryForm.getFieldsValue()) + } + } catch (error: unknown) { + const err = error as AxiosError + void message.error(err.response?.data.message ?? "删除失败,请稍后再试") + } + }, + }) + } + + // Query users + const queryUsers = ( + pageNum: number, + pageSize: number, + departmentId: number, + formValues: QueryUserForm | null + ) => { + const queryUserRequest: QueryUserRequest = { + createdAtEnd: null, + createdAtStart: null, + phoneNumber: null, + regionAbbreviation: null, + status: null, + username: null, + pageNum, + pageSize, + departmentId, + } + + if (formValues && formValues.qUsername) { + queryUserRequest.username = formValues.qUsername + } + + if (formValues && formValues.qRegionAbbreviation) { + queryUserRequest.regionAbbreviation = formValues.qRegionAbbreviation + } + + if (formValues && formValues.qPhoneNumber) { + queryUserRequest.phoneNumber = formValues.qPhoneNumber + } + + if (formValues && formValues.qStatus) { + queryUserRequest.status = formValues.qStatus + } + + if (formValues && formValues.qCreatedAtStart) { + queryUserRequest.createdAtStart = formValues.qCreatedAtStart.format("YYYY-MM-DD HH:mm:ss") + } + + if (formValues && formValues.qCreatedAtEnd) { + queryUserRequest.createdAtEnd = formValues.qCreatedAtEnd.format("YYYY-MM-DD HH:mm:ss") + } + + console.log(`queryUsers ==> `, queryUserRequest) + + UserApi.fetchUsers(queryUserRequest) + .then((userResponse) => { + console.log(userResponse) + setUsers(userResponse.content) + setPageNum(userResponse.pageable.pageNumber + 1) + setPageSize(userResponse.pageable.pageSize) + setTotalElementCount(userResponse.totalElements) + }) + .catch((error: unknown) => { + const err = error as AxiosError + void message.error(err.response?.data.message ?? "发生未知错误,请稍后再试") + }) + } + + useEffect(() => { + DeptApi.fetchDepartmentTree() + .then((departmentResponse) => { + setDepartment(departmentResponse) + setDepartmentTree(DepartmentUtils.transformDepartmentData([departmentResponse])) + }) + .catch((error: unknown) => { + const err = error as AxiosError + void message.error(err.response?.data.message ?? "发生未知错误,请稍后再试") + }) + }, []) + + useEffect(() => { + const formValues = queryForm.getFieldsValue() + queryUsers(pageNum, pageSize, selectedDepartment, formValues) + }, [pageNum, pageSize, selectedDepartment]) + + const regionOptions = getCountries().map((country) => { + const callingCode = getCountryCallingCode(country) + return { + label: `${country} (+${callingCode})`, + value: country, + key: country, + } + }) + + const userStatusOptions = [ + { + label: "已启用", + value: "ACTIVE", + key: "ACTIVE", + }, + { + label: "已停用", + value: "INACTIVE", + key: "INACTIVE", + }, + { + label: "已禁用", + value: "LOCKED", + key: "LOCKED", + }, + ] + + return ( +
+ { + if (typeof selectedKey == "number") { + setSelectedDepartment(selectedKey) + } + }} + selectedKeys={[selectedDepartment]} + /> +
+ + className="mt-0 mb-6" + form={queryForm} + layout="inline" + labelAlign="right" + onFinish={(values) => { + console.log("Query User Form ==> ", values) + queryUsers(pageNum, pageSize, Number(selectedDepartment), values) + }} + onReset={() => { + queryUsers(pageNum, pageSize, Number(selectedDepartment), null) + }}> + label="用户名" name="qUsername"> + + + + label="用户状态" name="qStatus"> + + + + noStyle name="qPhoneNumber"> + + + + + + + + name="qCreatedAtStart"> + + + name="qCreatedAtEnd"> + + + + + + + + + + + + + + + + + + + + + + rowKey="id" + dataSource={users} + pagination={{ + current: pageNum, + total: totalElementCount, + pageSize: pageSize, + defaultCurrent: 1, + defaultPageSize: 10, + pageSizeOptions: [10, 25, 50], + showSizeChanger: true, + onShowSizeChange: (pageNum, pageSize) => { + console.log(`onSizeChange ==> pageNum = ${pageNum}, pageSize = ${pageSize}`) + setPageNum(pageNum) + setPageSize(pageSize) + }, + onChange: (pageNum, pageSize) => { + console.log(`onChange ==> pageNum = ${pageNum}, pageSize = ${pageSize}`) + setPageNum(pageNum) + setPageSize(pageSize) + }, + }} + columns={[ + { title: "用户 ID", dataIndex: "id" }, + { title: "用户名称", dataIndex: "username" }, + { title: "姓名", dataIndex: "fullName" }, + { title: "电子邮箱", dataIndex: "email" }, + { + title: "联系电话", + render: (user: UserDetailResponse) => { + return PhoneNumberUtils.formatInternationalPhoneNumber( + user.regionAbbreviation, + user.phoneNumber + ) + }, + key: "phoneNumber", + }, + { + title: "头像", + render: (user: UserDetailResponse) => { + return + }, + key: "avatarUrl", + }, + { + title: "用户状态", + render: (user: UserDetailResponse) => { + const colour = user.status == "ACTIVE" ? "green" : "red" + return ( + + {user.status} + + ) + }, + key: "status", + }, + { title: "所在部门", dataIndex: "departmentName" }, + { title: "用户岗位", dataIndex: "positionName" }, + { + title: "操作", + render: (value: UserDetailResponse) => { + return String(value.id) == String(user.id) ? ( + <> + ) : ( + + + + + + ) + }, + }, + ]} + /> +
+
+ ) +} diff --git a/src/router/index.tsx b/src/router/index.tsx new file mode 100644 index 0000000..5c38b51 --- /dev/null +++ b/src/router/index.tsx @@ -0,0 +1,86 @@ +import type { ComponentType } from "react" +import { createBrowserRouter } from "react-router-dom" +import ErrorPage from "@/page/error" +import LoadingFallback from "@/components/loading-fallback" + +/** + * 懒加载组件 + * @param importer + */ +function lazyLoading }>(importer: () => Promise) { + return async () => { + const module = await importer() + return { + Component: module.default, + } + } +} + +const router = createBrowserRouter([ + { + path: "/login", + lazy: lazyLoading(() => import("@/page/login")), + handle: { + label: "用户登录", + }, + hydrateFallbackElement: , + }, + { + path: "/register", + lazy: lazyLoading(() => import("@/page/register")), + handle: { + label: "用户注册", + }, + hydrateFallbackElement: , + }, + { + path: "/", + lazy: lazyLoading(() => import("@/components/protected-route")), + errorElement: , + handle: { + label: "控制台", + }, + hydrateFallbackElement: , + children: [ + { + index: true, + lazy: lazyLoading(() => import("@/page/home")), + handle: { + label: "用户主页", + }, + hydrateFallbackElement: , + }, + { + path: "users", + lazy: lazyLoading(() => import("@/page/user")), + handle: { + label: "用户管理", + }, + hydrateFallbackElement: , + }, + { + path: "roles", + lazy: lazyLoading(() => import("@/page/role")), + handle: { + label: "角色管理", + }, + hydrateFallbackElement: , + }, + { + path: "menus", + lazy: lazyLoading(() => import("@/page/menu")), + handle: { + label: "菜单管理", + }, + hydrateFallbackElement: , + }, + ], + }, + { + path: "*", + lazy: lazyLoading(() => import("@/page/not-found")), + hydrateFallbackElement: , + }, +]) + +export default router diff --git a/src/service/auth/index.ts b/src/service/auth/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/service/auth/msal/index.ts b/src/service/auth/msal/index.ts new file mode 100644 index 0000000..4eec775 --- /dev/null +++ b/src/service/auth/msal/index.ts @@ -0,0 +1,29 @@ +import type { IPublicClientApplication } from "@azure/msal-browser" +import * as AuthApi from "@/api/auth" +import type { AppDispatch } from "@/store" +import { loginSuccess } from "@/store/auth-slice" + +/** + * Login with Microsoft Entra ID. + * + * @param instance Microsoft Entra ID application instance + * @param dispatch app dispatcher + * @param onSuccess callback when login succeeded + */ +export async function doMsalLogin( + instance: IPublicClientApplication, + dispatch: AppDispatch, + onSuccess?: () => void +) { + try { + const response = await instance.loginPopup({ + scopes: ["openid", "profile", "email"], + }) + + const { accessToken, user } = await AuthApi.msalLogin(response.idToken) + dispatch(loginSuccess({ user, token: accessToken })) + if (onSuccess) onSuccess() + } catch (err) { + console.error("MSAL login failed", err) + } +} diff --git a/src/service/web-client/index.ts b/src/service/web-client/index.ts new file mode 100644 index 0000000..5e933ba --- /dev/null +++ b/src/service/web-client/index.ts @@ -0,0 +1,38 @@ +import axios, { type AxiosError } from "axios" +import dayjs from "dayjs" +import store from "@/store" +import type { GeneralErrorResponse } from "@/types" +import { HttpStatus } from "@/constant" +import { logout } from "@/store/auth-slice" + +const webClient = axios.create({ + baseURL: import.meta.env.VITE_API_BASE_URL, + timeout: dayjs.duration({ seconds: 10 }).asMilliseconds(), +}) + +webClient.interceptors.request.use( + (config) => { + const state = store.getState() + if (state.auth.isAuthenticated) { + config.headers["Authorization"] = `Bearer ${state.auth.token!}` + } + + return config + }, + (error: unknown) => { + console.log(error) + return Promise.reject(new Error("请求错误,请稍后再试")) + } +) + +webClient.interceptors.response.use((response) => { + return response +}, (error: unknown) => { + const err = error as AxiosError + if (err.response?.status == HttpStatus.UNAUTHORIZED) { + store.dispatch(logout()) + } + return Promise.reject(error as AxiosError) +}) + +export default webClient diff --git a/src/store/auth-slice/index.ts b/src/store/auth-slice/index.ts new file mode 100644 index 0000000..0c58e44 --- /dev/null +++ b/src/store/auth-slice/index.ts @@ -0,0 +1,46 @@ +import { createSlice, type PayloadAction } from "@reduxjs/toolkit" +import type { User } from "@/types/entity" + +interface AuthState { + isAuthenticated: boolean + user: User | null + token: string | null, + registrationEnabled: boolean +} + +const initialState: AuthState = { + isAuthenticated: false, + user: null, + token: null, + registrationEnabled: false +} + +const authSlice = createSlice({ + name: "auth", + initialState, + reducers: { + loginSuccess( + state, + action: PayloadAction<{ + user: User + token: string + }> + ) { + console.log("更新用户信息:", action.payload.user) + state.isAuthenticated = true + state.user = action.payload.user + state.token = action.payload.token + }, + logout(state) { + state.isAuthenticated = false + state.user = null + state.token = null + }, + updateRegistrationEnabled(state, action: PayloadAction) { + state.registrationEnabled = action.payload + } + }, +}) + +export const { loginSuccess, logout, updateRegistrationEnabled } = authSlice.actions +export default authSlice.reducer diff --git a/src/store/index.ts b/src/store/index.ts new file mode 100644 index 0000000..b786fc2 --- /dev/null +++ b/src/store/index.ts @@ -0,0 +1,47 @@ +import { configureStore, combineReducers } from "@reduxjs/toolkit" +import { useDispatch, useSelector } from "react-redux" +import authReducer from "./auth-slice" +import { + persistStore, + persistReducer, + FLUSH, + REHYDRATE, + PAUSE, + PERSIST, + PURGE, + REGISTER, +} from "redux-persist" +import storage from "redux-persist/lib/storage/session" + +const persistConfig = { + key: "root", + storage, + whitelist: ["auth"], + // blacklist: ['department'], +} + +const rootReducer = combineReducers({ + auth: authReducer, +}) + +const persistedReducer = persistReducer(persistConfig, rootReducer) + +const store = configureStore({ + reducer: persistedReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], + }, + }), +}) + +export const persistor = persistStore(store) + +export default store +export type RootState = ReturnType +export type AppDispatch = typeof store.dispatch +export type AppStore = typeof store + +export const useAppDispatch = useDispatch.withTypes() +export const useAppSelector = useSelector.withTypes() diff --git a/src/types/antd/index.ts b/src/types/antd/index.ts new file mode 100644 index 0000000..a90422c --- /dev/null +++ b/src/types/antd/index.ts @@ -0,0 +1,14 @@ +import type { GetProps } from "antd" +import type Icon from "@ant-design/icons" + +export type AntIconComponentProps = GetProps + +export interface AntTreeSelectOption { + value: T + label: string + children: AntTreeSelectOption[] + disabled?: boolean + disableCheckbox?: boolean + selectable?: boolean + checkable?: boolean +} diff --git a/src/types/config/index.ts b/src/types/config/index.ts new file mode 100644 index 0000000..443140d --- /dev/null +++ b/src/types/config/index.ts @@ -0,0 +1,14 @@ +/** + * WeCom config + */ +export type WecomConfig = { + /** + * Corporation ID + */ + corpId: string + + /** + * Application ID + */ + agentId: string +} diff --git a/src/types/constant/index.ts b/src/types/constant/index.ts new file mode 100644 index 0000000..839087b --- /dev/null +++ b/src/types/constant/index.ts @@ -0,0 +1,6 @@ +/** + * Status + */ +export type Status = "ACTIVE" | "INACTIVE" + +export type UserStatus = Status | "LOCKED" diff --git a/src/types/entity/index.ts b/src/types/entity/index.ts new file mode 100644 index 0000000..5abfaf9 --- /dev/null +++ b/src/types/entity/index.ts @@ -0,0 +1,73 @@ +import type { Status, UserStatus } from "@/types/constant" +import type { CountryCode as RegionAbbreviation } from "libphonenumber-js" +import type { Dayjs } from "dayjs" + +/** + * User information + */ +export interface User { + id: number + username: string + password: string + fullName: string + email: string + regionAbbreviation: RegionAbbreviation + phoneNumber: string + avatarUrl: string + status: UserStatus + departmentId: number + positionId: number + createdAt: string + updatedAt: string +} + +/** + * Menu Item + */ +export interface MenuItem { + id: number + name: string + parentId: number | null + code: string + sort: number + isExternalLink: boolean + isVisible: boolean + status: Status + authorityCode: string | null + icon: string | null + createdAt: string + updatedAt: string +} + +export interface Department { + id: number + name: string + parentId: number | null + sort: number + status: Status + createdAt: string + updatedAt: string +} + +export interface Position { + id: number + name: string + code: string | null + description: string | null + sort: number + status: Status + createdAt: string + updatedAt: string +} + +export interface Role { + id: number | string + name: string + code: string + sort: number + defaultValue: boolean + description: string | null + status: Status + createdAt: Dayjs | string + updatedAt: Dayjs | string +} diff --git a/src/types/form/index.ts b/src/types/form/index.ts new file mode 100644 index 0000000..29db71c --- /dev/null +++ b/src/types/form/index.ts @@ -0,0 +1,31 @@ +import type { User } from "@/types/entity" +import type { CountryCode as RegionAbbreviation } from "libphonenumber-js" +import type { Status } from "@/types/constant" +import type { Dayjs } from "dayjs" + +export interface UserFormValues extends Omit< + User, + "id" | "password" | "regionAbbreviation" | "departmentId" | "positionId" | "createdAt" | "updatedAt" +> { + id: number | string | null + password: string | null + regionAbbreviation: RegionAbbreviation | null + departmentId: number | null + positionId: number | null +} + +export interface QueryRoleForm { + qName: string | null + qCode: string | null + qStatus: Status | null +} + +export interface QueryUserForm { + qDepartmentId: number | null + qUsername: string | null + qRegionAbbreviation: RegionAbbreviation | null + qPhoneNumber: string | null + qStatus: Status | null + qCreatedAtStart: Dayjs | null + qCreatedAtEnd: Dayjs | null +} diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types/page/index.ts b/src/types/page/index.ts new file mode 100644 index 0000000..9f97449 --- /dev/null +++ b/src/types/page/index.ts @@ -0,0 +1,14 @@ +export interface Sortable { + empty: boolean + sorted: boolean + unsorted: boolean +} + +export interface Pageable { + pageNumber: number + pageSize: number + sort: Sortable + offset: number + paged: boolean + unpaged: boolean +} diff --git a/src/types/route/index.ts b/src/types/route/index.ts new file mode 100644 index 0000000..ae7b549 --- /dev/null +++ b/src/types/route/index.ts @@ -0,0 +1,6 @@ +/** + * React Router Metadata + */ +export interface RouteHandle { + label: string +} diff --git a/src/types/tree/index.ts b/src/types/tree/index.ts new file mode 100644 index 0000000..9495b87 --- /dev/null +++ b/src/types/tree/index.ts @@ -0,0 +1,37 @@ +/** + * Represents a single node within a tree structure. + * + * Each node holds a data item of type T and an array of its children. + * + * @template T the type of the data item stored in the node + */ +export interface TreeNode { + /** + * The actual data item contained within this node. + */ + item: T + /** + * A list of child nodes belonging to this node. + * + * This array will be empty if the node is a leaf node. + */ + children: TreeNode[] +} + +/** + * Defines a tree structure, which is simply a top-level tree node. + * + * It represents the root of the hierarchical data structure. + * + * @template T the type of the data items within the tree + */ +export type Tree = TreeNode + +/** + * Defines a forest, which is an array of zero or more disjoint trees. + * + * Each element in the array is the root of an independent tree. + * + * @template T the type of the data items within the trees + */ +export type Forest = TreeNode[] diff --git a/src/types/web/request/index.ts b/src/types/web/request/index.ts new file mode 100644 index 0000000..93e12be --- /dev/null +++ b/src/types/web/request/index.ts @@ -0,0 +1,54 @@ +import type { CountryCode as RegionAbbreviation } from "libphonenumber-js" +import type { Status, UserStatus } from "@/types/constant" +import type { User } from "@/types/entity" + +export interface PageRequest { + pageNum?: number + pageSize?: number +} + +export interface UsernamePasswordLoginRequest { + username: string + password: string + captcha?: string + uuid?: string +} + +export interface QueryUserRequest extends PageRequest { + departmentId: number | null + username: string | null + regionAbbreviation: RegionAbbreviation | null + phoneNumber: string | null + status: Status | null + createdAtStart: string | null + createdAtEnd: string | null +} + +export interface QueryPositionRequest extends PageRequest { +} + +export interface AddUserRequest extends Omit{ + roleIds: number[] | null +} + +export interface EditUserRequest { + id: number | string + username: string | null + fullName: string | null + email: string | null + regionAbbreviation: string | null + phoneNumber: string | null + avatarUrl: string | null + status: UserStatus | null + departmentId: number | null + positionId: number | null + roleIds: number[] | null +} + +export interface QueryRoleRequest extends PageRequest { + name: string | null + code: string | null + status: Status | null +} + + diff --git a/src/types/web/response/index.ts b/src/types/web/response/index.ts new file mode 100644 index 0000000..bd20934 --- /dev/null +++ b/src/types/web/response/index.ts @@ -0,0 +1,39 @@ +import type { Role, User } from "@/types/entity" +import type { Pageable, Sortable } from "@/types/page" + +export interface PageResponse { + content: T[] + last: boolean + totalPages: number + totalElements: number + size: number + sort: Sortable + first: boolean + numberOfElements: number + empty: boolean, + pageable: Pageable +} + +export interface UserAuthResponse { + user: User + accessToken: string +} + +export interface UserDetailResponse extends User { + departmentName: string + positionName: string +} + +export interface CaptchaResponse { + uuid: string + captcha: string +} + +export interface GeneralErrorResponse { + message: string + timestamp: string +} + +export interface RoleResponse extends PageResponse { +} + diff --git a/src/utils/department-utils/index.ts b/src/utils/department-utils/index.ts new file mode 100644 index 0000000..76481f3 --- /dev/null +++ b/src/utils/department-utils/index.ts @@ -0,0 +1,28 @@ +import { type TreeDataNode } from "antd" +import type { TreeNode } from "@/types/tree" +import type { Department } from "@/types/entity" + +export function transformDepartmentData(departments: TreeNode[]): TreeDataNode[] { + if (!departments || departments.length === 0) { + return [] + } + + return departments + .sort((a, b) => a.item.sort - b.item.sort) + .map((node) => { + const { item, children } = node + const hasChildren = children && children.length > 0 + + const treeItem: TreeDataNode = { + key: item.id, + title: item.name, + } + + if (hasChildren) { + // Append children + return { ...treeItem, children: transformDepartmentData(children) } + } + + return treeItem + }) +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..39caf36 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,2 @@ +export * as PhoneNumberUtils from "./phone-number-utils" +export * as DepartmentUtils from "./department-utils" diff --git a/src/utils/phone-number-utils/index.ts b/src/utils/phone-number-utils/index.ts new file mode 100644 index 0000000..0196a5b --- /dev/null +++ b/src/utils/phone-number-utils/index.ts @@ -0,0 +1,28 @@ +import { type CountryCode as RegionAbbreviation, getCountryCallingCode, parsePhoneNumberWithError, PhoneNumber } from "libphonenumber-js" + +/** + * Format user's phone number as user's country/region. + * + * @param regionAbbreviation user's region abbreviation + * @param phoneNumber user's phone number + * @return formatted phone number + */ +export function formatInternationalPhoneNumber(regionAbbreviation: string, phoneNumber: string): string { + try { + const _phoneNumber = parsePhoneNumberWithError(phoneNumber, regionAbbreviation as RegionAbbreviation) + + if (!_phoneNumber.isValid()) { + console.warn(`Phone number ${_phoneNumber.formatInternational()} is not valid`) + } + return _phoneNumber.formatInternational() + } catch (error) { + console.error("Phone number parsing failed:", error) + const _regionAbbreviation: RegionAbbreviation = regionAbbreviation as RegionAbbreviation + const callingCode = getCountryCallingCode(_regionAbbreviation) + return `+${callingCode} ${phoneNumber}` + } +} + +export function getDefaultCountryCode(): RegionAbbreviation { + return import.meta.env.VITE_DEFAULT_REGION_CODE +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..b133581 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,27 @@ +/// +/// + +import type { CountryCode as RegionAbbreviation } from "libphonenumber-js" + +interface ImportMetaEnv { + /** + * Server Base URL + */ + readonly VITE_API_BASE_URL: string + + /** + * Microsoft Entra ID Client ID + */ + readonly VITE_MSAL_CLIENT_ID: string + + /** + * Microsoft Entra ID Tenant ID + */ + readonly VITE_MSAL_TENANT_ID: string + + readonly VITE_DEFAULT_REGION_ABBREVIATION: RegionAbbreviation +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..9b30999 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fec8c8e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..70d82d6 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..a5708a3 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from "node:url" +import { defineConfig } from "vite" +import react from "@vitejs/plugin-react" +import tailwindcss from "@tailwindcss/vite" +import svgr from "vite-plugin-svgr" + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss(), svgr()], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, + server: { + allowedHosts: true, + } +})