From fcb43c0cbde3ef15bedc0fccc381dd372b47f203 Mon Sep 17 00:00:00 2001 From: zhengw <247276359@qq.com> Date: Mon, 5 Jan 2026 17:06:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E9=A1=B9=E7=9B=AE,=20antd6,=20react19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 2 + .gitignore | 26 + .vscode/settings.json | 53 + README.md | 78 + biome.jsonc | 57 + index.html | 114 + package.json | 51 + pnpm-lock.yaml | 2124 +++++++++++++++++ pnpm-workspace.yaml | 2 + public/vite.svg | 1 + src/App.tsx | 72 + src/assets/loginBg.jpg | Bin 0 -> 39520 bytes src/assets/react.svg | 1 + src/components/Footer/MonitorUpdate.tsx | 73 + src/components/Footer/index.module.css | 13 + src/components/Footer/index.tsx | 34 + src/components/FormPlugin/index.module.css | 39 + src/components/FormPlugin/index.tsx | 114 + src/components/GapBox.tsx | 28 + src/components/Header/HeaderUserInfo.tsx | 23 + src/components/ModalPlugin.tsx | 52 + .../PageContainer/BreadcrumbPlugin.tsx | 77 + .../PageContainer/PageContainerPlugin.tsx | 74 + src/components/PaginationPlugin.tsx | 64 + src/components/SearchButton.tsx | 89 + src/components/SiderMenu/NavMenu.tsx | 113 + .../SiderMenu/NavigateMenuDrawer.tsx | 29 + .../TabNavPlugin/TabNavSaveCheckBoxPlugin.tsx | 28 + src/components/TabNavPlugin/index.module.css | 58 + src/components/TabNavPlugin/index.tsx | 263 ++ src/components/TableColumnsFilterPlugin.tsx | 87 + src/components/TableColumnsFilterPlugin2.tsx | 332 +++ src/components/TablePlugin.tsx | 53 + src/configs/config.ts | 128 + src/configs/menuConfig.tsx | 50 + src/configs/routes.ts | 46 + src/index.css | 10 + src/interfaces/common.ts | 25 + src/interfaces/finance.ts | 56 + src/interfaces/staff.ts | 86 + src/interfaces/user.ts | 40 + src/layouts/AppLayout.tsx | 129 + src/layouts/EmptyLayout.tsx | 11 + src/layouts/ErrorBoundary.tsx | 81 + src/layouts/base.ts | 13 + src/main.tsx | 9 + src/pages/Error/index.tsx | 26 + src/pages/Index/index.tsx | 34 + src/pages/Login/index.tsx | 86 + src/pages/Staff/dep/index.tsx | 17 + src/pages/Staff/group/index.tsx | 17 + .../User/List/components/UserEditModal.tsx | 26 + src/pages/User/List/components/state.ts | 89 + src/pages/User/List/index.tsx | 167 ++ src/router/Link.tsx | 8 + src/router/Outlet.tsx | 48 + src/router/Router.tsx | 32 + src/router/router-data.ts | 9 + src/router/routerUtils.ts | 72 + src/router/types.ts | 12 + src/services/UserServices.ts | 3 + src/store/AuthStore.ts | 18 + src/store/CompanyStore.ts | 14 + src/store/ConfigStore.ts | 25 + src/store/RefreshStore.ts | 11 + src/store/UserConfigStore.ts | 22 + src/store/UserStore.ts | 12 + src/store/indexDBStore.ts | 11 + src/store/type.ts | 39 + src/utils/EventBus.ts | 150 ++ src/utils/UniqueKey.ts | 4 + src/utils/common.ts | 366 +++ src/utils/commonUtils.ts | 184 ++ src/utils/copyToClipboard.ts | 25 + src/utils/http.ts | 69 + src/utils/type.ts | 25 + src/utils/update.js | 51 + src/utils/useRequest.ts | 154 ++ src/utils/useRequest2.ts | 79 + src/vite-env.d.ts | 23 + tsconfig.app.json | 33 + tsconfig.json | 7 + tsconfig.node.json | 26 + vite.config.ts | 37 + 84 files changed, 6939 insertions(+) create mode 100644 .env create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100644 biome.jsonc create mode 100644 index.html create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 public/vite.svg create mode 100644 src/App.tsx create mode 100644 src/assets/loginBg.jpg create mode 100644 src/assets/react.svg create mode 100644 src/components/Footer/MonitorUpdate.tsx create mode 100644 src/components/Footer/index.module.css create mode 100644 src/components/Footer/index.tsx create mode 100644 src/components/FormPlugin/index.module.css create mode 100644 src/components/FormPlugin/index.tsx create mode 100644 src/components/GapBox.tsx create mode 100644 src/components/Header/HeaderUserInfo.tsx create mode 100644 src/components/ModalPlugin.tsx create mode 100644 src/components/PageContainer/BreadcrumbPlugin.tsx create mode 100644 src/components/PageContainer/PageContainerPlugin.tsx create mode 100644 src/components/PaginationPlugin.tsx create mode 100644 src/components/SearchButton.tsx create mode 100644 src/components/SiderMenu/NavMenu.tsx create mode 100644 src/components/SiderMenu/NavigateMenuDrawer.tsx create mode 100644 src/components/TabNavPlugin/TabNavSaveCheckBoxPlugin.tsx create mode 100644 src/components/TabNavPlugin/index.module.css create mode 100644 src/components/TabNavPlugin/index.tsx create mode 100644 src/components/TableColumnsFilterPlugin.tsx create mode 100644 src/components/TableColumnsFilterPlugin2.tsx create mode 100644 src/components/TablePlugin.tsx create mode 100644 src/configs/config.ts create mode 100644 src/configs/menuConfig.tsx create mode 100644 src/configs/routes.ts create mode 100644 src/index.css create mode 100644 src/interfaces/common.ts create mode 100644 src/interfaces/finance.ts create mode 100644 src/interfaces/staff.ts create mode 100644 src/interfaces/user.ts create mode 100644 src/layouts/AppLayout.tsx create mode 100644 src/layouts/EmptyLayout.tsx create mode 100644 src/layouts/ErrorBoundary.tsx create mode 100644 src/layouts/base.ts create mode 100644 src/main.tsx create mode 100644 src/pages/Error/index.tsx create mode 100644 src/pages/Index/index.tsx create mode 100644 src/pages/Login/index.tsx create mode 100644 src/pages/Staff/dep/index.tsx create mode 100644 src/pages/Staff/group/index.tsx create mode 100644 src/pages/User/List/components/UserEditModal.tsx create mode 100644 src/pages/User/List/components/state.ts create mode 100644 src/pages/User/List/index.tsx create mode 100644 src/router/Link.tsx create mode 100644 src/router/Outlet.tsx create mode 100644 src/router/Router.tsx create mode 100644 src/router/router-data.ts create mode 100644 src/router/routerUtils.ts create mode 100644 src/router/types.ts create mode 100644 src/services/UserServices.ts create mode 100644 src/store/AuthStore.ts create mode 100644 src/store/CompanyStore.ts create mode 100644 src/store/ConfigStore.ts create mode 100644 src/store/RefreshStore.ts create mode 100644 src/store/UserConfigStore.ts create mode 100644 src/store/UserStore.ts create mode 100644 src/store/indexDBStore.ts create mode 100644 src/store/type.ts create mode 100644 src/utils/EventBus.ts create mode 100644 src/utils/UniqueKey.ts create mode 100644 src/utils/common.ts create mode 100644 src/utils/commonUtils.ts create mode 100644 src/utils/copyToClipboard.ts create mode 100644 src/utils/http.ts create mode 100644 src/utils/type.ts create mode 100644 src/utils/update.js create mode 100644 src/utils/useRequest.ts create mode 100644 src/utils/useRequest2.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..1e44210 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +VITE_APP_WS_DEV=ws://192.168.1.224:8282 +VITE_APP_WS_PRO=wss://ws.ebaozan.com:8181 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f71003b --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +/public/ver.txt +/.cfg.ts +stats.html diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..03dd2db --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,53 @@ +{ + "window.title": "免费ERP后台系统${separator}${rootName}${separator}${profileName}", + "editor.formatOnSave": true, // 确保保存文件时自动格式化 + "files.eol": "\r\n", + "files.insertFinalNewline": true, // 保存时自动添加换行符 + "files.trimTrailingWhitespace": true, // 保存时自动删除行尾空格 + "editor.rulers": [120], + "editor.codeActionsOnSave": { + "source.organizeImports.biome": "explicit", + "source.fixAll.biome": "explicit", + "source.removeUnusedImports": "explicit" + // 移除未使用的代码 + // "source.removeUnused": "explicit", + }, + "auto-close-tag.enableAutoCloseTag": true, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.codeActionsOnSave": { + "source.organizeImports": "never" + } + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.codeActionsOnSave": { + "source.organizeImports": "never" + } + }, + "[css]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[jsonc]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + // 配置@的路径提示 + "path-autocomplete.pathMappings": { + "@": "${folder}/src" + }, + // "editor.codeActionsOnSave": { + // "source.organizeImports": "explicit" + // }, + "search.exclude": { + "**/node_modules": true, + "**/dist": true, + "**/README.md": true, + "**/stats.html": true, + "**/pnpm-lock.yaml": true, + "**/.cfg.ts": true + }, + "cSpell.words": ["freeerp", "NUMS", "Popconfirm", "qrcode", "Sider", "valtio"] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..5485b62 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# React + TypeScript + Vite + Arco Design + +# 项目运行 About 组件报错, 运行一次下面命令生成.cfg.ts 文件, 后面就可以直接用 vite 命令 + +`$ npm run dev` + +# 为了权限判断, 不要使用路径参数, 请使用查询参数 + +# 路由库在 router 文件夹 + +# 错误边界库 ErrorBoundary.tsx + +# 自己搭建的没有详细文档哦 + +- [React](https://react.dev/) +- [Vite](https://cn.vitejs.dev/) +- [TypeScript](https://www.typescriptlang.org/zh/) +- [Ant Design](https://ant-design.antgroup.com/components/overview-cn/) UI 库 +- [zustand](https://github.com/pmndrs/zustand) 状态管理库 +- [dnd-kit](https://github.com/clauderic/dnd-kit) 拖拽插件 + +# vscode 安装插件 + +- 语法校验和格式化插件 + `Biome` + +# 安装 pnpm + +`$ npm install -g pnpm` + +# 安装 + +`$ pnpm install 或 pnpm i` + +# 启动 + +`$ vite` + +http://localhost:4000/ + +# 打包 + +`$ vite build` + +# 用 biomejs 替换 eslint 和 prettier, vscode 需要安装 Biome 插件 + +[biome 文档](https://biomejs.dev/guides/getting-started/) + +# 文件目录(简单) + +``` +. +├── README.md +├── ice.config.mts # The project config +├── package.json +├── public +│   ├── favicon.ico +├── src +| ├── assets +| ├── components # 组件 +| ├── index.html # 入口页面 +| ├── global.css # 全局样式 +| ├── interfaces # 定义类型 +| ├── layout # 布局 +| ├── pages # 页面 +| ├── services # 后台api +| ├── store # store文件夹 +| ├── routes # 路由文件夹(路由和左侧导航菜单) +| └── typings.d.ts +└── tsconfig.json +``` + +# 请求封装 + +- useRequest(url: string, options) 参数传地址 +- useRequest2(request: any, options) 参数传请求 + +# 多语言实现 i18next diff --git a/biome.jsonc b/biome.jsonc new file mode 100644 index 0000000..e7a0af2 --- /dev/null +++ b/biome.jsonc @@ -0,0 +1,57 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 120, + "attributePosition": "auto" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noExplicitAny": "off", + "noDoubleEquals": "off" + }, + "style": { + "noNonNullAssertion": "off" + }, + "a11y": { + "noStaticElementInteractions": "off", + "useKeyWithClickEvents": "off" + }, + "correctness": { + "useExhaustiveDependencies": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "semicolons": "always", + "arrowParentheses": "always", + "jsxQuoteStyle": "single", + "bracketSpacing": true, + "lineEnding": "crlf", + "trailingCommas": "all" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..4843ab5 --- /dev/null +++ b/index.html @@ -0,0 +1,114 @@ + + + + + + + + + + + +
+ +
+
+
+
+
+
+ 正在加载系统资源,请耐心等待 +
+
+
+ + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..8128dab --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "freeerp-admin", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "node src/utils/update.js && vite", + "debug": "vite --debug", + "build": "node src/utils/update.js && vite build --mode development", + "build:pro": "node src/utils/update.js && vite build --mode production", + "// check": "运行format, lint等, 并应用安全建议(不会修改代码)", + "check": "npx @biomejs/biome check --write ./src", + "// lint": "校验文件", + "lint": "npx @biomejs/biome lint --write ./src", + "// format": "格式化文件", + "format": "npx @biomejs/biome format --write ./src", + "// write": "运行format, lint等, 并应用建议修改代码!!!!!!!!!!", + "write": "npx @biomejs/biome check --write-unsafe ./src", + "preview": "vite preview" + }, + "dependencies": { + "@ant-design/icons": "~5.6.1", + "antd": "^6.1.2", + "big.js": "^7.0.1", + "dayjs": "^1.11.19", + "qs": "^6.14.0", + "react": "^19.2.3", + "react-dom": "^19.2.3", + "valtio": "^2.2.0", + "zustand": "^5.0.9" + }, + "devDependencies": { + "@biomejs/biome": "2.3.10", + "@types/big.js": "^6.2.2", + "@types/node": "^25.0.3", + "@types/qs": "^6.14.0", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react-swc": "^4.2.2", + "globals": "^16.5.0", + "rollup-plugin-visualizer": "^6.0.5", + "typescript": "~5.9.3", + "vite": "npm:rolldown-vite@7.3.0" + }, + "overrides": { + "vite": "npm:rolldown-vite@7.3.0" + }, + "volta": { + "node": "22.18.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..5498f55 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2124 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@ant-design/icons': + specifier: ~5.6.1 + version: 5.6.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + antd: + specifier: ^6.1.2 + version: 6.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + big.js: + specifier: ^7.0.1 + version: 7.0.1 + dayjs: + specifier: ^1.11.19 + version: 1.11.19 + qs: + specifier: ^6.14.0 + version: 6.14.0 + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + valtio: + specifier: ^2.2.0 + version: 2.2.0(@types/react@19.2.7)(react@19.2.3) + zustand: + specifier: ^5.0.9 + version: 5.0.9(@types/react@19.2.7)(react@19.2.3) + devDependencies: + '@biomejs/biome': + specifier: 2.3.10 + version: 2.3.10 + '@types/big.js': + specifier: ^6.2.2 + version: 6.2.2 + '@types/node': + specifier: ^25.0.3 + version: 25.0.3 + '@types/qs': + specifier: ^6.14.0 + version: 6.14.0 + '@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-swc': + specifier: ^4.2.2 + version: 4.2.2(rolldown-vite@7.3.0(@types/node@25.0.3)) + globals: + specifier: ^16.5.0 + version: 16.5.0 + rollup-plugin-visualizer: + specifier: ^6.0.5 + version: 6.0.5(rolldown@1.0.0-beta.53) + typescript: + specifier: ~5.9.3 + version: 5.9.3 + vite: + specifier: npm:rolldown-vite@7.3.0 + version: rolldown-vite@7.3.0(@types/node@25.0.3) + +packages: + + '@ant-design/colors@7.2.1': + resolution: {integrity: sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==} + + '@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@2.0.6': + resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} + engines: {node: '>=8.x'} + + '@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@5.6.1': + resolution: {integrity: sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg==} + engines: {node: '>=8'} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@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 + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@biomejs/biome@2.3.10': + resolution: {integrity: sha512-/uWSUd1MHX2fjqNLHNL6zLYWBbrJeG412/8H7ESuK8ewoRoMPUgHDebqKrPTx/5n6f17Xzqc9hdg3MEqA5hXnQ==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@2.3.10': + resolution: {integrity: sha512-M6xUjtCVnNGFfK7HMNKa593nb7fwNm43fq1Mt71kpLpb+4mE7odO8W/oWVDyBVO4ackhresy1ZYO7OJcVo/B7w==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@2.3.10': + resolution: {integrity: sha512-Vae7+V6t/Avr8tVbFNjnFSTKZogZHFYl7MMH62P/J1kZtr0tyRQ9Fe0onjqjS2Ek9lmNLmZc/VR5uSekh+p1fg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@2.3.10': + resolution: {integrity: sha512-B9DszIHkuKtOH2IFeeVkQmSMVUjss9KtHaNXquYYWCjH8IstNgXgx5B0aSBQNr6mn4RcKKRQZXn9Zu1rM3O0/A==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@2.3.10': + resolution: {integrity: sha512-hhPw2V3/EpHKsileVOFynuWiKRgFEV48cLe0eA+G2wO4SzlwEhLEB9LhlSrVeu2mtSn205W283LkX7Fh48CaxA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@2.3.10': + resolution: {integrity: sha512-QTfHZQh62SDFdYc2nfmZFuTm5yYb4eO1zwfB+90YxUumRCR171tS1GoTX5OD0wrv4UsziMPmrePMtkTnNyYG3g==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@2.3.10': + resolution: {integrity: sha512-wwAkWD1MR95u+J4LkWP74/vGz+tRrIQvr8kfMMJY8KOQ8+HMVleREOcPYsQX82S7uueco60L58Wc6M1I9WA9Dw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@2.3.10': + resolution: {integrity: sha512-o7lYc9n+CfRbHvkjPhm8s9FgbKdYZu5HCcGVMItLjz93EhgJ8AM44W+QckDqLA9MKDNFrR8nPbO4b73VC5kGGQ==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.3.10': + resolution: {integrity: sha512-pHEFgq7dUEsKnqG9mx9bXihxGI49X+ar+UBrEIj3Wqj3UCZp1rNgV+OoyjFgcXsjCWpuEAF4VJdkZr3TrWdCbQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@emotion/hash@0.8.0': + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + + '@emotion/unitless@0.7.5': + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + + '@napi-rs/wasm-runtime@1.1.0': + resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} + + '@oxc-project/runtime@0.101.0': + resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@oxc-project/types@0.101.0': + resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==} + + '@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.6.0': + resolution: {integrity: sha512-A7vrN8kExtw4sW06mrsgCb1rowhvBFFvQU6Bk/NL0Fj6Wet/5GF0QnGCxBu/sG3JI9FEhsJWES0D44BW2d0hzg==} + 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.9.0': + resolution: {integrity: sha512-OLisdk8AWVCG9goBU1dWzuH5QlBQk8jktmQ6p0/IyBFwdKGwyIZOSjnBYo8hooHiTdl0lU+wGf/OfMtVBw02KQ==} + 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.3.0': + resolution: {integrity: sha512-5J/bJ01mbDnoA6P/FW8SxUvKn+OgUSTZJPzCNnTBntG50tzoP7DydGhqxp7ggZXZls7me3mc2EQDXakU3iTVFg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@rc-component/select@1.3.6': + resolution: {integrity: sha512-CzbJ9TwmWcF5asvTMZ9BMiTE9CkkrigeOGRPpzCNmeZP7KBwwmYrmOIiKh9tMG7d6DyGAEAQ75LBxzPx+pGTHA==} + 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.2': + resolution: {integrity: sha512-25x+D2k9SAkaK/MNMNmv2Nlv8FH1D9RtmjoMoLEw1Cid+sMV4pAAT5k49ku59UeXaOA1qwLUVrBUMq4A6gUSsQ==} + 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.2': + resolution: {integrity: sha512-RPQASdThk6oKCaV0wUA4s5nh8Scs+0nSywHASc+XsHrmBUZ284LyvVYpd6Dq+JZSN+IyhY0b/TSfgjPf+Qzicg==} + 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' + + '@rolldown/binding-android-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-yIsKqMz0CtRnVa6x3Pa+mzTihr4Ty+Z6HfPbZ7RVbk1Uxnco4+CUn7Qbm/5SBol1JD/7nvY8rphAgyAi7Lj6Vg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.53': + resolution: {integrity: sha512-GTXe+mxsCGUnJOFMhfGWmefP7Q9TpYUseHvhAhr21nCTgdS8jPsvirb0tJwM3lN0/u/cg7bpFNa16fQrjKrCjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + resolution: {integrity: sha512-9Tmp7bBvKqyDkMcL4e089pH3RsjD3SUungjmqWtyhNOxoQMh0fSmINTyYV8KXtE+JkxYMPWvnEt+/mfpVCkk8w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + resolution: {integrity: sha512-a1y5fiB0iovuzdbjUxa7+Zcvgv+mTmlGGC4XydVIsyl48eoxgaYkA3l9079hyTyhECsPq+mbr0gVQsFU11OJAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + resolution: {integrity: sha512-bpIGX+ov9PhJYV+wHNXl9rzq4F0QvILiURn0y0oepbQx+7stmQsKA0DhPGwmhfvF856wq+gbM8L92SAa/CBcLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + resolution: {integrity: sha512-bGe5EBB8FVjHBR1mOLOPEFg1Lp3//7geqWkU5NIhxe+yH0W8FVrQ6WRYOap4SUTKdklD/dC4qPLREkMMQ855FA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + resolution: {integrity: sha512-qL+63WKVQs1CMvFedlPt0U9PiEKJOAL/bsHMKUDS6Vp2Q+YAv/QLPu8rcvkfIMvQ0FPU2WL0aX4eWwF6e/GAnA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + resolution: {integrity: sha512-VGl9JIGjoJh3H8Mb+7xnVqODajBmrdOOb9lxWXdcmxyI+zjB2sux69br0hZJDTyLJfvBoYm439zPACYbCjGRmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + resolution: {integrity: sha512-B4iIserJXuSnNzA5xBLFUIjTfhNy7d9sq4FUMQY3GhQWGVhS2RWWzzDnkSU6MUt7/aHUrep0CdQfXUJI9D3W7A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + resolution: {integrity: sha512-BUjAEgpABEJXilGq/BPh7jeU3WAJ5o15c1ZEgHaDWSz3LB881LQZnbNJHmUiM4d1JQWMYYyR1Y490IBHi2FPJg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + resolution: {integrity: sha512-s27uU7tpCWSjHBnxyVXHt3rMrQdJq5MHNv3BzsewCIroIw3DJFjMH1dzCPPMUFxnh1r52Nf9IJ/eWp6LDoyGcw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + resolution: {integrity: sha512-cjWL/USPJ1g0en2htb4ssMjIycc36RvdQAx1WlXnS6DpULswiUTVXPDesTifSKYSyvx24E0YqQkEm0K/M2Z/AA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.47': + resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} + + '@rolldown/pluginutils@1.0.0-beta.53': + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + + '@swc/core-darwin-arm64@1.15.3': + resolution: {integrity: sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.15.3': + resolution: {integrity: sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.15.3': + resolution: {integrity: sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.15.3': + resolution: {integrity: sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.15.3': + resolution: {integrity: sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.15.3': + resolution: {integrity: sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.15.3': + resolution: {integrity: sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.15.3': + resolution: {integrity: sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.15.3': + resolution: {integrity: sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.15.3': + resolution: {integrity: sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.15.3': + resolution: {integrity: sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.25': + resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/big.js@6.2.2': + resolution: {integrity: sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==} + + '@types/node@25.0.3': + resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@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==} + + '@vitejs/plugin-react-swc@4.2.2': + resolution: {integrity: sha512-x+rE6tsxq/gxrEJN3Nv3dIV60lFflPj94c90b+NNo6n1QV1QQUTLoL0MpaOVasUZ0zqVBn7ead1B5ecx1JAGfA==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4 || ^5 || ^6 || ^7 + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + antd@6.1.2: + resolution: {integrity: sha512-pqYaZECL/7TBiNxxz+LieLiPCem6DaEzudqN44EZ3SvJjixLP7K41n6clo0zxe/2HiOUe9KxTMxGN+icOkL6Tw==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + + big.js@7.0.1: + resolution: {integrity: sha512-iFgV784tD8kq4ccF1xtNMZnXeZzVuXWWM+ERFzKQjv+A5G9HC8CY3DuV45vgzFFcW+u2tIvmF95+AzWgs6BjCg==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + compute-scroll-into-view@3.1.1: + resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + 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'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + 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==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + 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'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-mobile@5.0.0: + resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + json2mq@0.2.0: + resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} + + 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'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + 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} + + proxy-compare@3.0.1: + resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + rc-util@5.44.4: + resolution: {integrity: sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + peerDependencies: + react: ^19.2.3 + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + rolldown-vite@7.3.0: + resolution: {integrity: sha512-5hI5NCJwKBGtzWtdKB3c2fOEpI77Iaa0z4mSzZPU1cJ/OqrGbFafm90edVCd7T9Snz+Sh09TMAv4EQqyVLzuEg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + esbuild: ^0.27.0 + jiti: '>=1.21.0' + less: ^4.0.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 + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + rolldown@1.0.0-beta.53: + resolution: {integrity: sha512-Qd9c2p0XKZdgT5AYd+KgAMggJ8ZmCs3JnS9PTMWkyUfteKlfmKtxJbWTHkVakxwXs1Ub7jrRYVeFeF7N0sQxyw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup-plugin-visualizer@6.0.5: + resolution: {integrity: sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: 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==} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + string-convert@0.2.1: + resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + 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@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + valtio@2.2.0: + resolution: {integrity: sha512-l/zzQahUIm+dfUUP9fIecNVEWJLea9shMC1Bb1aK+v4XNOEzoq796Qax+yzMemmqpltuxfH7kPJy62FVGJDEtw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + react: '>=18.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + zustand@5.0.9: + resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + '@ant-design/colors@7.2.1': + dependencies: + '@ant-design/fast-color': 2.0.6 + + '@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.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/runtime': 7.28.4 + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@ant-design/cssinjs@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.8.0 + '@emotion/unitless': 0.7.5 + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + csstype: 3.2.3 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + stylis: 4.3.6 + + '@ant-design/fast-color@2.0.6': + dependencies: + '@babel/runtime': 7.28.4 + + '@ant-design/fast-color@3.0.0': {} + + '@ant-design/icons-svg@4.4.2': {} + + '@ant-design/icons@5.6.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@ant-design/colors': 7.2.1 + '@ant-design/icons-svg': 4.4.2 + '@babel/runtime': 7.28.4 + classnames: 2.5.1 + rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@ant-design/icons@6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@ant-design/colors': 8.0.0 + '@ant-design/icons-svg': 4.4.2 + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@ant-design/react-slick@2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + clsx: 2.1.1 + json2mq: 0.2.0 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + throttle-debounce: 5.0.2 + + '@babel/runtime@7.28.4': {} + + '@biomejs/biome@2.3.10': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.3.10 + '@biomejs/cli-darwin-x64': 2.3.10 + '@biomejs/cli-linux-arm64': 2.3.10 + '@biomejs/cli-linux-arm64-musl': 2.3.10 + '@biomejs/cli-linux-x64': 2.3.10 + '@biomejs/cli-linux-x64-musl': 2.3.10 + '@biomejs/cli-win32-arm64': 2.3.10 + '@biomejs/cli-win32-x64': 2.3.10 + + '@biomejs/cli-darwin-arm64@2.3.10': + optional: true + + '@biomejs/cli-darwin-x64@2.3.10': + optional: true + + '@biomejs/cli-linux-arm64-musl@2.3.10': + optional: true + + '@biomejs/cli-linux-arm64@2.3.10': + optional: true + + '@biomejs/cli-linux-x64-musl@2.3.10': + optional: true + + '@biomejs/cli-linux-x64@2.3.10': + optional: true + + '@biomejs/cli-win32-arm64@2.3.10': + optional: true + + '@biomejs/cli-win32-x64@2.3.10': + optional: true + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/hash@0.8.0': {} + + '@emotion/unitless@0.7.5': {} + + '@napi-rs/wasm-runtime@1.1.0': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@oxc-project/runtime@0.101.0': {} + + '@oxc-project/types@0.101.0': {} + + '@rc-component/async-validator@5.0.4': + dependencies: + '@babel/runtime': 7.28.4 + + '@rc-component/cascader@1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/select': 1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/checkbox@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/collapse@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/color-picker@3.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@ant-design/fast-color': 3.0.0 + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/context@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/dialog@1.5.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/portal': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/drawer@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/portal': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/dropdown@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/form@1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/async-validator': 5.0.4 + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/image@1.5.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/portal': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/input-number@1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/mini-decimal': 1.1.0 + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/input@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/mentions@1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/textarea': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/menu@1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/mini-decimal@1.1.0': + dependencies: + '@babel/runtime': 7.28.4 + + '@rc-component/motion@1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/mutate-observer@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/notification@1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/overflow@1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/pagination@1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/picker@1.9.0(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + dayjs: 1.11.19 + + '@rc-component/portal@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/progress@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/qrcode@1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/rate@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/resize-observer@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/segmented@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/select@1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/slider@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/steps@1.2.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/switch@1.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/table@1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/context': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/tabs@1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/dropdown': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/textarea@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/tooltip@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/tour@2.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/portal': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/tree-select@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/select': 1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/tree@1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/trigger@3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/portal': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/upload@1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rc-component/util@1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + is-mobile: 5.0.0 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-is: 18.3.1 + + '@rc-component/virtual-list@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.4 + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + + '@rolldown/binding-android-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.53': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.53': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.53': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.53': + dependencies: + '@napi-rs/wasm-runtime': 1.1.0 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.53': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.53': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.47': {} + + '@rolldown/pluginutils@1.0.0-beta.53': {} + + '@swc/core-darwin-arm64@1.15.3': + optional: true + + '@swc/core-darwin-x64@1.15.3': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.15.3': + optional: true + + '@swc/core-linux-arm64-gnu@1.15.3': + optional: true + + '@swc/core-linux-arm64-musl@1.15.3': + optional: true + + '@swc/core-linux-x64-gnu@1.15.3': + optional: true + + '@swc/core-linux-x64-musl@1.15.3': + optional: true + + '@swc/core-win32-arm64-msvc@1.15.3': + optional: true + + '@swc/core-win32-ia32-msvc@1.15.3': + optional: true + + '@swc/core-win32-x64-msvc@1.15.3': + optional: true + + '@swc/core@1.15.3': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.25 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.3 + '@swc/core-darwin-x64': 1.15.3 + '@swc/core-linux-arm-gnueabihf': 1.15.3 + '@swc/core-linux-arm64-gnu': 1.15.3 + '@swc/core-linux-arm64-musl': 1.15.3 + '@swc/core-linux-x64-gnu': 1.15.3 + '@swc/core-linux-x64-musl': 1.15.3 + '@swc/core-win32-arm64-msvc': 1.15.3 + '@swc/core-win32-ia32-msvc': 1.15.3 + '@swc/core-win32-x64-msvc': 1.15.3 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.25': + dependencies: + '@swc/counter': 0.1.3 + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/big.js@6.2.2': {} + + '@types/node@25.0.3': + dependencies: + undici-types: 7.16.0 + + '@types/qs@6.14.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 + + '@vitejs/plugin-react-swc@4.2.2(rolldown-vite@7.3.0(@types/node@25.0.3))': + dependencies: + '@rolldown/pluginutils': 1.0.0-beta.47 + '@swc/core': 1.15.3 + vite: rolldown-vite@7.3.0(@types/node@25.0.3) + transitivePeerDependencies: + - '@swc/helpers' + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + antd@6.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@ant-design/colors': 8.0.0 + '@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/cssinjs-utils': 2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/fast-color': 3.0.0 + '@ant-design/icons': 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/react-slick': 2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/runtime': 7.28.4 + '@rc-component/cascader': 1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/checkbox': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/collapse': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/color-picker': 3.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/dialog': 1.5.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/drawer': 1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/dropdown': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/form': 1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/image': 1.5.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/input-number': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/mentions': 1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/notification': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/pagination': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/picker': 1.9.0(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/progress': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/qrcode': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/rate': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/segmented': 1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/select': 1.3.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/slider': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/steps': 1.2.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/switch': 1.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/table': 1.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tabs': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/textarea': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tooltip': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tour': 2.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/tree-select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.7.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/upload': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + dayjs: 1.11.19 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + scroll-into-view-if-needed: 3.1.0 + throttle-debounce: 5.0.2 + transitivePeerDependencies: + - date-fns + - luxon + - moment + + big.js@7.0.1: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + classnames@2.5.1: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + compute-scroll-into-view@3.1.1: {} + + csstype@3.2.3: {} + + dayjs@1.11.19: {} + + define-lazy-prop@2.0.0: {} + + detect-libc@2.1.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + emoji-regex@8.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + escalade@3.2.0: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + 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: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + is-docker@2.2.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-mobile@5.0.0: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + json2mq@0.2.0: + dependencies: + string-convert: 0.2.1 + + 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 + + math-intrinsics@1.1.0: {} + + nanoid@3.3.11: {} + + object-inspect@1.13.4: {} + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.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 + + proxy-compare@3.0.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + rc-util@5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-is: 18.3.1 + + react-dom@19.2.3(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.27.0 + + react-is@18.3.1: {} + + react@19.2.3: {} + + require-directory@2.1.1: {} + + rolldown-vite@7.3.0(@types/node@25.0.3): + dependencies: + '@oxc-project/runtime': 0.101.0 + fdir: 6.5.0(picomatch@4.0.3) + lightningcss: 1.30.2 + picomatch: 4.0.3 + postcss: 8.5.6 + rolldown: 1.0.0-beta.53 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.0.3 + fsevents: 2.3.3 + + rolldown@1.0.0-beta.53: + dependencies: + '@oxc-project/types': 0.101.0 + '@rolldown/pluginutils': 1.0.0-beta.53 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.53 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.53 + '@rolldown/binding-darwin-x64': 1.0.0-beta.53 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.53 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.53 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.53 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.53 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.53 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.53 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.53 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.53 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.53 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.53 + + rollup-plugin-visualizer@6.0.5(rolldown@1.0.0-beta.53): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rolldown: 1.0.0-beta.53 + + scheduler@0.27.0: {} + + scroll-into-view-if-needed@3.1.0: + dependencies: + compute-scroll-into-view: 3.1.1 + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + string-convert@0.2.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + stylis@4.3.6: {} + + 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: + optional: true + + typescript@5.9.3: {} + + undici-types@7.16.0: {} + + valtio@2.2.0(@types/react@19.2.7)(react@19.2.3): + dependencies: + proxy-compare: 3.0.1 + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + y18n@5.0.8: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + zustand@5.0.9(@types/react@19.2.7)(react@19.2.3): + optionalDependencies: + '@types/react': 19.2.7 + react: 19.2.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..4216cb8 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +onlyBuiltDependencies: + - '@swc/core' diff --git a/public/vite.svg b/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..5adaa09 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,72 @@ +import { App as AntdApp, ConfigProvider, notification } from 'antd'; +import type { ArgsProps } from 'antd/es/notification'; +import zhCN from 'antd/locale/zh_CN'; +import { useEffect } from 'react'; +import { headerHeight } from './configs/config'; +import { routes } from './configs/routes'; +import Router from './router/Router'; +import { getDevice } from './utils/common'; +import { notificationEventBus } from './utils/EventBus'; + +function App() { + const [api, contextHolder] = notification.useNotification({ + stack: false, + }); + + useEffect(() => { + window.dfConfig = { + isPhone: getDevice() == 'phone', + tableStickyOffsetHeader: headerHeight, + language: 'zh-cn', + vhUnit: CSS.supports('height', '100dvh') ? 'dvh' : 'vh', + }; + }); + + useEffect(() => { + notificationEventBus.onOpen((data) => { + api.open(data as ArgsProps); + }); + notificationEventBus.onClose((key: string) => { + api.destroy(key); + }); + }, [api]); + + return ( + + {contextHolder} + + + + + ); +} + +export default App; diff --git a/src/assets/loginBg.jpg b/src/assets/loginBg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..39e5925124830b45fbd0fbbd9eee325585cfe519 GIT binary patch literal 39520 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 KoDuMQ?B4+HAflH5 literal 0 HcmV?d00001 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/components/Footer/MonitorUpdate.tsx b/src/components/Footer/MonitorUpdate.tsx new file mode 100644 index 0000000..5577351 --- /dev/null +++ b/src/components/Footer/MonitorUpdate.tsx @@ -0,0 +1,73 @@ +import { Button } from 'antd'; +import { type FC, useEffect, useRef } from 'react'; +import { Colors } from '@/configs/config'; +import { notificationEventBus } from '@/utils/EventBus'; +import { GapBox } from '../GapBox'; + +/** 监听网站版本更新 */ +const MonitorUpdate: FC = () => { + const timerRef = useRef(null); + const version = useRef(''); + + useEffect(() => { + timerRef.current = setInterval(() => { + if (import.meta.env.DEV) { + return; + } + fetch('/ver.txt') + .then((res) => res.text()) + .then(async (res) => { + if (version.current == '') { + version.current = res; + } + if (res != version.current) { + clearInterval(timerRef.current); + notificationEventBus.emit({ + key: 'MonitorUpdate', + title: '有新版本', + description: ( +
+
发现系统版本更新,请刷新页面
+
+ 刷新前,请先保存页面数据!!! +
+ + + + +
+ ), + duration: 0, + }); + } + }); + }, 60000); + + return () => { + clearInterval(timerRef.current); + }; + }, []); + + return null; +}; +export default MonitorUpdate; diff --git a/src/components/Footer/index.module.css b/src/components/Footer/index.module.css new file mode 100644 index 0000000..98e48ec --- /dev/null +++ b/src/components/Footer/index.module.css @@ -0,0 +1,13 @@ +.footer { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 8px 0; + font-size: 12px; +} + +.footer a { + text-decoration: none; + color: #1677ff; +} diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx new file mode 100644 index 0000000..b47364d --- /dev/null +++ b/src/components/Footer/index.tsx @@ -0,0 +1,34 @@ +import type { CSSProperties, FC } from 'react'; +import { DefaultERPName } from '@/configs/config'; +import styles from './index.module.css'; +import MonitorUpdate from './MonitorUpdate'; + +type IProps = { + style?: CSSProperties; +}; + +const filings: any = { + 'd.com': '闽ICP备14007219号-9', +}; + +const Footer: FC = (props) => { + const currentYear = new Date().getFullYear(); + + return ( +
+
+ + +
+
+ © {`${currentYear} ${DefaultERPName}`}  + + {filings[location.hostname] || '闽ICP备14007219号-15'} + +
+ +
+ ); +}; + +export default Footer; diff --git a/src/components/FormPlugin/index.module.css b/src/components/FormPlugin/index.module.css new file mode 100644 index 0000000..bfef852 --- /dev/null +++ b/src/components/FormPlugin/index.module.css @@ -0,0 +1,39 @@ +.item { + margin-bottom: var(--item-margin-bottom, 12px); +} + +.itemLabel { + flex-shrink: 0; + white-space: nowrap; + display: flex; + justify-content: flex-end; + align-items: center; + min-height: 32px; + width: var(--labelWidth, 84px); +} + +.itemLabel.required::before { + color: #ff4d4f; + width: 12px; + font-family: SimSun, sans-serif; + content: "*"; + display: inline-block; + flex-shrink: 0; +} + +.itemLabel.colon::after { + content: ":"; + display: inline-block; + flex-shrink: 0; +} +.itemControl { + display: flex; + min-height: 32px; + align-items: flex-start; + flex-direction: column; + justify-content: center; +} + +.itemControl > div { + width: 100%; +} diff --git a/src/components/FormPlugin/index.tsx b/src/components/FormPlugin/index.tsx new file mode 100644 index 0000000..3487f9c --- /dev/null +++ b/src/components/FormPlugin/index.tsx @@ -0,0 +1,114 @@ +import { Col, Row } from 'antd'; +import type React from 'react'; +import type { FC, PropsWithChildren } from 'react'; +import { Colors } from '@/configs/config'; +import { isNumber } from '@/utils/common.ts'; +import styles from './index.module.css'; + +type ISearchFormPluginProps = { + style?: React.CSSProperties & { + '--labelWidth'?: string; + '--item-margin-bottom'?: string; + }; + children?: React.ReactNode; + labelWidth?: number | string; + itemMarginBottom?: number | string; + gutter?: number; +}; + +/** 响应式栅格 FormItemPlugin默认值 xs = 24, sm = 24, md = 12, lg = 8, xl = 6, xxl = 6*/ +export type ICol = { + /** 窗口宽度 < 576px */ + xs?: number; + /** 窗口宽度 ≥ 576px */ + sm?: number; + /** 窗口宽度 ≥ 768px */ + md?: number; + /** 窗口宽度 ≥ 992px */ + lg?: number; + /** 窗口宽度 ≥ 1200px */ + xl?: number; + /** 窗口宽度 ≥ 1600px */ + xxl?: number; +}; + +/** 单纯表单样式简化版插件 */ +export const FormPlugin: FC> = (props) => { + const { style, children, labelWidth, gutter = 0, itemMarginBottom } = props; + + return ( + + {children} + + ); +}; + +type SearchFormPluginItemProps = { + col?: ICol; + /** 统一设置 col */ + allCol?: number; + style?: React.CSSProperties; + /** 是否显示冒号, 默认为 true */ + colon?: boolean; + label?: React.ReactNode; + labelStyle?: React.CSSProperties; + controlStyle?: React.CSSProperties; + labelWidth?: number | string; + /** 是否必填显示星号 */ + required?: boolean; + errorMsg?: React.ReactNode; + // name?: string; +}; + +export const FormItemPlugin: FC> = (props) => { + const { + col = {}, + style, + colon = true, + label, + labelStyle, + labelWidth, + children, + required, + allCol, + controlStyle, + } = props; + const { xs = 24, sm = 24, md = 12, lg = 8, xl = 6, xxl = 6 } = col; + + return ( + + {label ? ( + + ) : null} +
+ {children} +
+ {props.errorMsg} +
+
+ + ); +}; diff --git a/src/components/GapBox.tsx b/src/components/GapBox.tsx new file mode 100644 index 0000000..625c88d --- /dev/null +++ b/src/components/GapBox.tsx @@ -0,0 +1,28 @@ +import type React from 'react'; +import type { PropsWithChildren } from 'react'; + +type IProps = { + style?: React.CSSProperties; + gap?: number; // 间距 + onClick?: React.MouseEventHandler; + title?: string; +}; + +export const GapBox: React.FC> = ({ children, onClick, style, title, gap }) => { + return ( +
+ {children} +
+ ); +}; diff --git a/src/components/Header/HeaderUserInfo.tsx b/src/components/Header/HeaderUserInfo.tsx new file mode 100644 index 0000000..c2ab48f --- /dev/null +++ b/src/components/Header/HeaderUserInfo.tsx @@ -0,0 +1,23 @@ +import { Button, Popconfirm } from 'antd'; +import { useUserStore } from '@/store/UserStore'; +import { GapBox } from '../GapBox'; + +export const HeaderUserInfo: React.FC = () => { + const userInfo = useUserStore().user; + + return ( + +
{userInfo.login_name}
+ { + location.hash = '#/login'; + }} + > + + +
+ ); +}; diff --git a/src/components/ModalPlugin.tsx b/src/components/ModalPlugin.tsx new file mode 100644 index 0000000..74c1b30 --- /dev/null +++ b/src/components/ModalPlugin.tsx @@ -0,0 +1,52 @@ +import { App, Modal } from 'antd'; +import type { ModalProps } from 'antd/es/modal/interface'; +import type React from 'react'; + +type IProps = ModalProps & { + /** 关闭是否需要确认弹框 boolean */ + confirm?: boolean; + /** 关闭确认弹框内容 React.ReactNode */ + confirmContent?: React.ReactNode; +}; + +/** Modal对话框简单封装, 支持确认退出 + * + * @注意 destroyOnHidden 默认为true与antd文档相反 + * @注意 centered 默认为true与antd文档相反 + * @注意 maskClosable 默认为true与antd文档相反 + * @param confirm 关闭是否需要确认弹框 boolean + * @param confirmContent 关闭确认弹框内容 React.ReactNode + */ +const ModalPlugin: React.FC = (props) => { + const { modal } = App.useApp(); + return ( + { + if (props.confirm) { + modal.confirm({ + transitionName: 'ant-fade', + title: '系统提示', + content: <>{props.confirmContent || '确认关闭?'}, + width: 300, + centered: true, + onOk: async () => { + if (props.onCancel) { + await props.onCancel(event); + } + }, + }); + } else { + props.onCancel?.(event); + } + }} + > + {props.children} + + ); +}; +export default ModalPlugin; diff --git a/src/components/PageContainer/BreadcrumbPlugin.tsx b/src/components/PageContainer/BreadcrumbPlugin.tsx new file mode 100644 index 0000000..992e5b8 --- /dev/null +++ b/src/components/PageContainer/BreadcrumbPlugin.tsx @@ -0,0 +1,77 @@ +import { Breadcrumb } from 'antd'; +import type React from 'react'; +import { GapBox } from '../GapBox'; + +type IProps = { + /** 面包屑内容 */ + items?: string[]; + /** 容器样式 */ + contentStyle?: React.CSSProperties; + /** 面包屑样式 */ + breadcrumbStyle?: React.CSSProperties; +}; + +const BreadcrumbPlugin: React.FC = (props) => { + // const [src, setSrc] = useState(''); + // const user_id = localStorage.getItem('user_id'); + // const company_id = localStorage.getItem('company_id'); + // const storageKey = `likeMenus_c${company_id}_u${user_id}`; + // const [likeMenus, setLikeMenus] = useState(toArray(jsonParse(localStorage.getItem(storageKey)))); + // useEffect(() => { + // aa: for (const el of asideMenuConfig) { + // for (const ell of toArray(el.children)) { + // if (ell.path == lo.pathname) { + // // ! 打开文档跳转 + // setSrc(ell.docUrl); + // break aa; + // } + // } + // } + // }, []); + + // const save = (type: 'add' | 'remove') => { + // if (type == 'add') { + // if (!likeMenus.includes(lo.pathname)) { + // likeMenus.push(lo.pathname); + // } + // } else { + // likeMenus.splice(likeMenus.indexOf(lo.pathname), 1); + // } + // localStorage.setItem(storageKey, JSON.stringify(likeMenus)); + // setLikeMenus([...likeMenus]); + // }; + + return Array.isArray(props.items) ? ( + + ({ title: item }))} + style={{ minHeight: 22, ...props.breadcrumbStyle }} + /> + {/* {!!src && ( + + + } + /> + )} + + ); +}; + +export default PageContainerPlugin; diff --git a/src/components/PaginationPlugin.tsx b/src/components/PaginationPlugin.tsx new file mode 100644 index 0000000..353cc06 --- /dev/null +++ b/src/components/PaginationPlugin.tsx @@ -0,0 +1,64 @@ +import { Pagination } from 'antd'; +import type React from 'react'; + +interface IProps { + current: number | undefined; + pageSize: number | undefined; + total: number | undefined; + onChange: (page: number) => void; + style?: React.CSSProperties; + size?: 'small' | 'default'; + hideOnSinglePage?: boolean; +} + +export const HeaderPagination: React.FC = (props) => { + return ( + { + props.onChange(page); + }} + hideOnSinglePage={props.hideOnSinglePage} + simple + showSizeChanger={false} + size={props.size ?? 'small'} + showTotal={(total) => `共 ${total} 条`} + /> + ); +}; + +interface IProps2 { + current: number | undefined; + pageSize: number | undefined; + total: number | undefined; + onChange: (page: number, pageSize: number) => void; + // onShowSizeChange: (pageSize: number) => void; + size?: 'small' | 'default'; + showSizeChanger?: boolean; + style?: React.CSSProperties; +} + +export const FooterPagination: React.FC = (props) => { + return ( + { + props.onChange(pageSize != props.pageSize ? 1 : page, pageSize); + }} + // onShowSizeChange={(_current, size) => { + // props.onShowSizeChange(size); + // }} + // size={!isPhone ? 'small' : 'default'} + showTotal={(total) => `共 ${total} 条`} + /> + ); +}; diff --git a/src/components/SearchButton.tsx b/src/components/SearchButton.tsx new file mode 100644 index 0000000..cc5a9bb --- /dev/null +++ b/src/components/SearchButton.tsx @@ -0,0 +1,89 @@ +import { DownOutlined, UpOutlined } from '@ant-design/icons'; +import { Button, Input } from 'antd'; +import type React from 'react'; +import { useEffect, useState } from 'react'; + +type IProps = { + style?: React.CSSProperties; + onClick?: () => void; + loading?: boolean; + onlyIcon?: boolean; + type?: 'link' | 'text' | 'primary' | 'default' | 'dashed'; +}; + +export const SearchButton: React.FC = (props) => { + const title = '搜索' as string; + return ( + + ); +}; + +export const ResetButton: React.FC = (props) => { + const title = '重置' as string; + return ( + + ); +}; + +export const MoreSearchButton: React.FC = (props) => { + const title = (props.show ? '收起' : '展开') as string; + return ( + + ); +}; + +interface ISearchInput { + placeholder?: string; + value?: string; + onEnd?: (newValue?: string, oldValue?: string) => void; + onPressEnter?: (newValue?: string, oldValue?: string) => void; +} + +export const SearchInputPlugin: React.FC = (props) => { + const { placeholder, value, onPressEnter, onEnd } = props; + const [val, setVal] = useState(); + + useEffect(() => { + setVal(value); + }, [value]); + + return ( + { + setVal(v.target.value); + }} + // onClear={() => { + // onEnd?.('', value); + // }} + onBlur={() => { + onEnd?.(val, value); + }} + onPressEnter={() => { + onEnd?.(val, value); + onPressEnter?.(val, value); + }} + /> + ); +}; diff --git a/src/components/SiderMenu/NavMenu.tsx b/src/components/SiderMenu/NavMenu.tsx new file mode 100644 index 0000000..5c66a74 --- /dev/null +++ b/src/components/SiderMenu/NavMenu.tsx @@ -0,0 +1,113 @@ +import { Menu, type MenuProps } from 'antd'; +import type React from 'react'; +import { useEffect, useState } from 'react'; +import { asideMenuConfig } from '@/configs/menuConfig'; +import { getHash, navigate } from '@/router/routerUtils'; +import { useAuthStore } from '@/store/AuthStore'; +import { useCompanyStore } from '@/store/CompanyStore'; +import { isArray, toArray } from '@/utils/common'; + +interface IProps { + onCallback?: () => void; +} + +const NavMenu: React.FC = (props) => { + const [openKeys, setOpenKeys] = useState([]); + const auth = useAuthStore().auth; + const company = useCompanyStore().company; + // 新窗口打开的链接 + const [newWindowUrl] = useState<{ [key: string]: { target: string } }>({}); + const [hash, setHash] = useState(getHash()); + type MenuItem = Required['items'][number]; + /** 导航菜单 数据处理 */ + const [menuOptions, setMenuOptions] = useState([]); + + useEffect(() => { + const arr: MenuItem[] = []; + asideMenuConfig.forEach((item) => { + const itemName = item.name; + const obj: any = { + key: item.path || itemName, + icon: item.icon, + label: itemName, + title: itemName, + }; + if (isArray(item.children)) { + obj.children = []; + item.children?.forEach((el: any) => { + // ! 添加权限判断 + if (!el.hideInMenu && (!el.auth || (auth && el.auth.split(',').some((key: string) => auth?.[key.trim()])))) { + if (!el.auth && (company.staff_type == '3' || company.staff_type == '4')) { + // + } else { + const elName = el.name; + if (el.target && el.path) { + newWindowUrl[el.path] = { target: el.target }; + } + obj.children.push({ key: el.path, icon: el.icon, label: elName, title: elName }); + } + } + }); + } + if (obj.children.length) { + arr.push(obj); + } + }); + // console.log(arr); + setMenuOptions(arr); + + const hashChange = () => { + const hashStr = getHash() || '/home/index'; + let name = ''; + let title = ''; + asideMenuConfig.forEach((item) => { + const itemName = item.name as string; + if (item.path == hashStr) { + name = itemName; + title = itemName; + } else { + toArray(item.children).forEach((el) => { + if (el.path == hashStr) { + name = itemName; + title = el.name as string; + } + }); + } + }); + setOpenKeys([name]); + document.title = title; + setHash(hashStr); + }; + + hashChange(); + + window.addEventListener('hashchange', hashChange); + + return () => { + window.removeEventListener('hashchange', hashChange); + }; + }, []); + + return ( + { + if (newWindowUrl[info.key]) { + window.open(`#${info.key}`, newWindowUrl[info.key].target); + } else { + navigate(info.key); + } + props.onCallback?.(); + }} + onOpenChange={(openKeys) => { + setOpenKeys(openKeys); + }} + // style={{ width: '100%' }} + selectedKeys={[hash]} + openKeys={openKeys} + // key={`${openKeys[0]}_${lo.pathname}`} + mode='inline' + items={menuOptions} + /> + ); +}; +export default NavMenu; diff --git a/src/components/SiderMenu/NavigateMenuDrawer.tsx b/src/components/SiderMenu/NavigateMenuDrawer.tsx new file mode 100644 index 0000000..7d6c8cf --- /dev/null +++ b/src/components/SiderMenu/NavigateMenuDrawer.tsx @@ -0,0 +1,29 @@ +import { MenuUnfoldOutlined } from '@ant-design/icons'; +import { Button, Drawer } from 'antd'; +import type React from 'react'; +import { useState } from 'react'; +import { getDevice } from '@/utils/common'; +import NavMenu from './NavMenu'; + +export const NavigateMenuDrawer: React.FC = () => { + const [open, setOpen] = useState(false); + + if (getDevice() === 'phone') { + return ( + <> + +// +//
表格列配置
+// +// +// +// } +// onClose={() => { +// setOpen(false); +// }}> +// +// el.columnName)} strategy={verticalListSortingStrategy}> +// +// +// +//
+// +// ); +// }; diff --git a/src/components/TablePlugin.tsx b/src/components/TablePlugin.tsx new file mode 100644 index 0000000..97bf2c9 --- /dev/null +++ b/src/components/TablePlugin.tsx @@ -0,0 +1,53 @@ +import { ConfigProvider, Table } from 'antd'; +import type { TableProps } from 'antd/lib/table'; +import type React from 'react'; +import { isObject } from '@/utils/common'; + +export const formatTableSort = (sort: any) => { + if (isObject(sort) && sort.order) { + return `${sort.field} ${sort.order.replace('end', '')}`; + } + return undefined; +}; + +/** + * 排序顺序格式化 + * @param dataIndex 列数据索引 + * @param order 排序顺序 + * @returns 'ascend' | 'descend' | undefined + */ +export const formatTableSortOrder = (dataIndex: string, order?: string): 'ascend' | 'descend' | undefined => { + if (order) { + const [name, sort] = order.split(' '); + if (name == dataIndex) { + return sort == 'asc' ? 'ascend' : 'descend'; + } + } + return undefined; +}; + +type IProps = TableProps; +/** Table简单封装 + * + * @props size="small" + * @props tableLayout="fixed" + * @props showSorterTooltip={false} + * @props pagination={false} + * @props bordered={true} + * + */ +export const TablePlugin: React.FC = (props) => { + return ( + '暂无数据'}> + + + ); +}; diff --git a/src/configs/config.ts b/src/configs/config.ts new file mode 100644 index 0000000..a26b2f5 --- /dev/null +++ b/src/configs/config.ts @@ -0,0 +1,128 @@ +import type React from 'react'; + +/** 默认错误图片 */ +// export const BreakImgUrl = pathAddApiString('/static/images/break_img.svg'); +// export const DefaultAvatar = pathAddApiString('/static/img/avatar.svg'); + +/** 头部高度 */ +export const headerHeight = 40; + +export const OSSBaseUrl = 'https://cdn.fzcfkj.com/'; + +/** 头部导航高度 */ +export const headerTabNavHeight = 32; + +export const DefaultERPName = (() => { + return '易宝赞普惠版后台系统'; +})(); + +export const Colors = { + primary: 'rgb(22, 93, 255)', + success: 'rgb(0, 180, 42)', + successBg: 'rgb(175, 240, 181)', + black: 'rgb(0, 0, 0)', + warning: 'rgb(255, 125, 0)', + error: 'rgb(245, 63, 63)', + danger: 'rgb(245, 63, 63)', +} as const; + +export const styleConfig = { + borderRadius: 2, +} as const; + +export const FlexCenter: React.CSSProperties = { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +}; + +export const FlexCenterInLine: React.CSSProperties = { + display: 'inline-flex', + justifyContent: 'center', + alignItems: 'center', +}; + +/** 撤回码标记 */ +export const RecallCodeMarking = '-'; + +/** 菜单房间 */ +export const RoomName = [ + { label: '主卧', value: '主卧' }, + { label: '次卧', value: '次卧' }, + { label: '老人房', value: '老人房' }, + { label: '儿童房', value: '儿童房' }, + { label: '阳台', value: '阳台' }, + { label: '客厅', value: '客厅' }, + { label: '厨房', value: '厨房' }, + { label: '卫生间', value: '卫生间' }, +]; + +export const OrderState = { + /** 未审核 */ + ERP_ORDER_STATE_NOT: 110, + /** 部分审核 */ + ERP_ORDER_STATE_PART: 120, + /** 全部审核 */ + ERP_ORDER_STATE_ALL: 130, + /** 已关闭 */ + ERP_ORDER_STATE_CLOSE: 140, + /** 部分销售 */ + ERP_ORDER_STATE_PART_SALE: 150, + /** 完成销售 */ + ERP_ORDER_STATE_ALL_SALE: 160, +} as const; + +export const OrderStateColors = { + /** 未审核 */ + 110: 'red', + /** 部分审核 */ + 120: 'orange', + /** 全部审核 */ + 130: 'green', + /** 已关闭 */ + 140: 'gray', + /** 部分销售 */ + 150: 'blue', + /** 完成销售 */ + 160: 'arcoblue', +} as const; + +export const BonusType = { 1: '计件', 2: '计时' }; + +/** 生产订单状态 */ +export const ProduceState = { + /** 未审核 */ + PRODUCE_ORDER_STATE_NOT: 110, + /** 部分审核 */ + PRODUCE_ORDER_STATE_PART: 120, + /** 全部审核 */ + PRODUCE_ORDER_STATE_ALL: 130, + /** 已关闭 */ + PRODUCE_ORDER_STATE_CLOSE: 140, + /** 加工中 */ + PRODUCE_ORDER_STATE_WORKING: 150, + /** 已完工 */ + PRODUCE_ORDER_STATE_WORKED: 160, +} as const; + +export const ProduceStateObj: Record = { + /** 未审核 */ + 110: { label: '未审核', color: 'red' }, + /** 部分审核 */ + 120: { label: '部分审核', color: 'orange' }, + /** 全部审核 */ + 130: { label: '全部审核', color: 'green' }, + /** 已关闭 */ + 140: { label: '已关闭', color: 'gray' }, + /** 加工中 */ + 150: { label: '加工中', color: 'blue' }, + /** 已完工 */ + 160: { label: '已完工', color: 'arcoblue' }, +} as const; + +/** 工序状态 */ +export const ProcessState: Record = { + 0: { label: '未开始', color: '#0fc6c2' }, + 1: { label: '进行中', color: '#7bc616' }, + 2: { label: '已完成', color: '#86909c' }, +}; diff --git a/src/configs/menuConfig.tsx b/src/configs/menuConfig.tsx new file mode 100644 index 0000000..1a66861 --- /dev/null +++ b/src/configs/menuConfig.tsx @@ -0,0 +1,50 @@ +import { DashboardOutlined, UserOutlined } from '@ant-design/icons'; +import type React from 'react'; + +/* cspell:disable */ +const iconStyle: React.CSSProperties = { fontSize: 18 }; + +interface MenuDataItem { + name: string; + icon?: React.ReactNode; + path?: string; + hideInMenu?: boolean; + auth?: string; + children?: MenuDataItem[]; + docUrl?: string; +} + +//const docUrl = 'https://docs.qq.com/aio/DS2NCRFFseG9Ma3Ja?p='; + +const userMenu: MenuDataItem = { + name: '用户管理', + icon: , + children: [ + { name: '用户管理', path: '/user/list', auth: '' }, + // { name: '岗位角色', path: '/user/group', auth: 'SF_ERP_GROUP_VIEW' }, + ], +}; +const staffMenu: MenuDataItem = { + name: '后台用户', + icon: , + children: [ + { name: '组织架构', path: '/staff/dep', auth: 'SF_ERP_DEPART_VIEW' }, + { name: '岗位角色', path: '/staff/group', auth: 'SF_ERP_GROUP_VIEW' }, + { name: '员工管理', path: '/staff/list', auth: 'SF_ERP_STAFF_VIEW' }, + { name: '我的权限', path: '/staff/my', auth: 'SF_MY_RIGHT_VIEW' }, + // { name: '日志管理', path: '/system/record', auth: 'SF_ERP_LOG_VIEW' }, + ], +}; + +const asideMenuConfig: MenuDataItem[] = [ + { + name: '系统看板', + // path: '/', + icon: , + children: [{ name: '系统主页', path: '/home/index', auth: '' }], + }, + userMenu, + staffMenu, +]; + +export { asideMenuConfig }; diff --git a/src/configs/routes.ts b/src/configs/routes.ts new file mode 100644 index 0000000..39f0d89 --- /dev/null +++ b/src/configs/routes.ts @@ -0,0 +1,46 @@ +import { lazy } from 'react'; +import AppLayout from '@/layouts/AppLayout'; +import EmptyLayout from '@/layouts/EmptyLayout'; +import ErrorPage from '@/pages/Error'; +import Index from '@/pages/Index'; +import Dep from '@/pages/Staff/dep'; +import Group from '@/pages/Staff/group'; +import UserList from '@/pages/User/List'; +import type { IRouteItem } from '@/router/types'; + +export const routes: IRouteItem[] = [ + { + path: '/home', + Layout: AppLayout, + children: [ + { path: '/index', Component: Index }, + // { path: '/index', Component: lazy(() => import('@/pages/Index')) }, + // { path: '/home', Component: Index, }, + ], + }, + { + path: '/user', + Layout: AppLayout, + children: [ + { path: '/list', Component: UserList }, + // { path: '/group', Component: lazy(() => import('@/pages/Staff/group')) }, + ], + }, + { + path: '/staff', + Layout: AppLayout, + children: [ + { path: '/dep', Component: Dep }, + { path: '/group', Component: Group }, + ], + }, + { + path: '/login', + Layout: EmptyLayout, + children: [ + { path: '/index', Component: lazy(() => import('@/pages/Login')) }, + // + ], + }, + { path: '*', Layout: ErrorPage, children: [] }, +]; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..758ed6f --- /dev/null +++ b/src/index.css @@ -0,0 +1,10 @@ +body { + margin: 0; + min-height: 100vh; +} + +@supports (height: 100dvh) { + body { + min-height: 100vh; + } +} diff --git a/src/interfaces/common.ts b/src/interfaces/common.ts new file mode 100644 index 0000000..7587377 --- /dev/null +++ b/src/interfaces/common.ts @@ -0,0 +1,25 @@ +import type { ForwardedRef } from 'react'; + +/** params的基础类型 */ +export type IParamsBase = { + curr_page: number; + page_count: number; + order?: string; +}; + +/** ajax返回的基础类型 */ +export type IAjaxDataBase = { + count: number | undefined; + err_msg?: string; + err_code?: number; + [key: string]: any; +}; + +export type IRef = { + ref: ForwardedRef; +}; + +export type IOption = { + value: string | number; + label: string; +}; diff --git a/src/interfaces/finance.ts b/src/interfaces/finance.ts new file mode 100644 index 0000000..03f3654 --- /dev/null +++ b/src/interfaces/finance.ts @@ -0,0 +1,56 @@ +/** 供应商 type */ +export type ISupplierType = { + supplier_id?: number; + name?: string; + phone?: string; + tax_no?: string; + invoice_title?: string; + bank_name?: string; + bank_no?: string; + finance_phone?: string; + address?: string; + tax_rate?: number | string; + create_date?: string; + comments?: string; +}; + +/** 经销商 type */ +export type ISaleInfo = { + sms_code?: string; + sale_id?: number; + name?: string; + phone?: string; + level?: number | string; + level_name?: string; + default_discount?: number | string; + last_discount?: number; + tax_no?: string; + invoice_title?: string; + bank_name?: string; + bank_no?: string; + finance_phone?: string; + address?: string; + tax_rate?: number; + pay_ratio?: number; + signed_date?: string; + create_date?: string; + comments?: string; + is_staff?: any; + login_name?: string; // 业务员信息 + bind_login_name?: string; // 绑定账号信息 + bind_user_phone?: string; // 绑定账号信息 + bind_user_id?: any; // 绑定账号信息 + staff_user_id?: any; + staff_name?: string; + nick_name?: string; +}; + +/** 折扣 type */ +export type IDiscountInfo = { + discount_id?: number; + name?: string; + code?: string; + discount_value?: number; + comments?: string; + create_date?: string; +}; diff --git a/src/interfaces/staff.ts b/src/interfaces/staff.ts new file mode 100644 index 0000000..a399bd8 --- /dev/null +++ b/src/interfaces/staff.ts @@ -0,0 +1,86 @@ +/** 部门 */ +export type IDepartment = { + comments?: string; + company_id?: number; + create_date?: string; + department_id: number; + name: string; + state?: number; + dept_type?: number; +}; + +export type IGroup = { + comments?: string; + company_id?: number; + create_date?: string; + group_id: number; + name: string; + state?: number; + rights?: any; +}; + +export type IRightsItem3 = { + comments: null | string; + function_ch_name: string; + function_en_name: string; + function_id: number; + function_sort: number; + function_type: number; + menu_id: number; + checked?: boolean; +}; + +export type IRightsItem2 = { + comments: null | string; + menu_ch_name: string; + menu_en_name: string; + menu_icon: null | string; + menu_id: number; + menu_sort: number; + menu_type: number; + menu_url: string; + parent_menu_id: number; + state: number; + children: IRightsItem3[]; +}; + +export type IRightsItem1 = { + comments: null | string; + menu_ch_name: string; + menu_en_name: string; + menu_icon: null | string; + menu_id: number; + menu_sort: number; + menu_type: number; + menu_url: string; + parent_menu_id: number; + state: number; + children: IRightsItem2[]; +}; + +export type IRights = IRightsItem1[]; + +export type IStaff = { + group_type: any; + comments: null | string; + create_date: string; + dep_name: string; + department_id: number; + group_id: string; + staff_id: number; + group_name: string; + last_login_time: null | string; + login_name: string; + logo: null | string; + nick_name: null | string; + staff_type: number; + state: number; + user_id: number; + user_phone: string; + user_sex: number; + visit_times: number; + staff_state: number; + wx_open_id?: string; + wx_nick_name?: string; + wx_head_img?: string; +}; diff --git a/src/interfaces/user.ts b/src/interfaces/user.ts new file mode 100644 index 0000000..87a1e6e --- /dev/null +++ b/src/interfaces/user.ts @@ -0,0 +1,40 @@ +export interface UserInfo { + login_name?: string; + logo?: string; + last_login_time?: string; + nick_name?: string; + state?: number; + user_id?: number; + user_sex?: number; + user_phone?: string; + visit_times?: string; + create_date?: string; + logoKey?: number; + wx_head_img?: string; + wx_nick_name?: string; + wx_open_id?: string; + self_account?: number; +} + +export interface CompanyInfo { + company_address?: string; + company_desc?: string; + company_domain?: string; + company_id?: number; + company_logo?: string; + company_name?: string; + company_state?: string; + create_date?: string; + eff_date?: string; + exp_date?: string; + erp_name?: string; + last_login_name?: string; + user_id?: string; + domain?: string; + desc?: string; + company_list?: any[]; + sale_id?: any; + staff_type?: any; + erp_version?: number; + session_id?: string; +} diff --git a/src/layouts/AppLayout.tsx b/src/layouts/AppLayout.tsx new file mode 100644 index 0000000..ff96c70 --- /dev/null +++ b/src/layouts/AppLayout.tsx @@ -0,0 +1,129 @@ +import { Layout, Spin } from 'antd'; +import { Content, Header } from 'antd/es/layout/layout'; +import Sider from 'antd/es/layout/Sider'; +import { useEffect, useState } from 'react'; +import Footer from '@/components/Footer'; +import { GapBox } from '@/components/GapBox'; +import { HeaderUserInfo } from '@/components/Header/HeaderUserInfo'; +import { NavigateMenuDrawer } from '@/components/SiderMenu/NavigateMenuDrawer'; +import NavMenu from '@/components/SiderMenu/NavMenu'; +import TabNavPlugin from '@/components/TabNavPlugin'; +import { DefaultERPName, headerHeight } from '@/configs/config'; +import Outlet from '@/router/Outlet'; +import { useAuthStore } from '@/store/AuthStore'; +import { useUserStore } from '@/store/UserStore'; +import { getDevice, toObject } from '@/utils/common'; +import { loginState } from './base'; +import ErrorBoundary from './ErrorBoundary'; + +const AppLayout = () => { + const [loading, setLoading] = useState(true); + const isPhone = getDevice() == 'phone'; + const userStore = useUserStore(); + const authStore = useAuthStore(); + + useEffect(() => { + setLoading(true); + loginState().then((res) => { + // console.log(res); + userStore.updateUser(toObject(res.user_info)); + authStore.updateAuth(toObject(res.auth_info) as any); + localStorage.setItem('admin_user_id', res?.user_info?.user_id); + setLoading(false); + }); + }, []); + + return ( + <> + {!loading ? ( + +
+ + {isPhone ? ( + + ) : ( +
{DefaultERPName}
+ )} + {Date.now()} +
+
+ +
+
+ + {isPhone ? null : ( + { + // setCollapsed(collapsed); + // }} + style={{ + background: '#fff', + overflow: 'auto', + // height: `calc(100vh - ${headerHeight}px)`, + position: 'sticky', + // zIndex: 1000, + left: 0, + // top: headerHeight, + }} + width={200} + // width={window?.dfConfig?.language == 'zh-cn' ? 100 : 240} + // collapsed={collapsed} + // collapsedWidth={60} + > + + {/* */} + + )} + + + {/* */} +
+ + + +
+
+ + + + ) : ( + 加载数据...} + > +   + + )} + + ); +}; +export default AppLayout; diff --git a/src/layouts/EmptyLayout.tsx b/src/layouts/EmptyLayout.tsx new file mode 100644 index 0000000..6983f33 --- /dev/null +++ b/src/layouts/EmptyLayout.tsx @@ -0,0 +1,11 @@ +import Outlet from '@/router/Outlet'; +import ErrorBoundary from './ErrorBoundary'; + +const EmptyLayout = () => { + return ( + + + + ); +}; +export default EmptyLayout; diff --git a/src/layouts/ErrorBoundary.tsx b/src/layouts/ErrorBoundary.tsx new file mode 100644 index 0000000..d2daf65 --- /dev/null +++ b/src/layouts/ErrorBoundary.tsx @@ -0,0 +1,81 @@ +import { Button, Result } from 'antd'; +import React from 'react'; + +type IProps = { + fallback?: (error: any, info?: any) => React.ReactNode; + children?: React.ReactNode; +}; + +/** 错误边界组件 */ +class ErrorBoundary extends React.Component { + state: { hasError: boolean; errorMsg?: React.ReactNode }; + + constructor(props: IProps) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(_error: any) { + // console.log("error", error); + // 更新状态,以便下一次渲染将显示后备 UI。 + return { hasError: true }; + } + + componentDidCatch(error: any, info: any) { + // console.log(error, info); + this.setState({ errorMsg: `${error}${info.componentStack}` }); + } + + render() { + if (this.state.hasError) { + // 你可以渲染任何自定义后备 UI + return ( + this.props?.fallback?.(this.state.errorMsg) || ( + +
页面发生异常,错误内容已上报!
+
开发人员紧急修复中,敬请耐心等待!
+ + } + subTitle={ +
+                {this.state.errorMsg}
+              
+ } + style={{ + display: 'flex', + alignItems: 'center', + flexDirection: 'column', + minHeight: 'calc(100vh - 180px)', + }} + extra={[ + , + ]} + /> + ) + ); + } + + return this.props?.children; + } +} + +export default ErrorBoundary; diff --git a/src/layouts/base.ts b/src/layouts/base.ts new file mode 100644 index 0000000..6638eed --- /dev/null +++ b/src/layouts/base.ts @@ -0,0 +1,13 @@ +import { requestLite } from '@/utils/useRequest'; + +export const loginState = async () => { + return new Promise((resolve, reject) => { + requestLite('/Users/loginState').then((res) => { + if (res?.err_code == 0) { + resolve(res); + } else { + reject(null); + } + }); + }); +}; diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..f329669 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,9 @@ +import { createRoot } from 'react-dom/client'; +import './index.css'; +import App from './App.tsx'; + +createRoot(document.getElementById('root')!).render( + // + , + // , +); diff --git a/src/pages/Error/index.tsx b/src/pages/Error/index.tsx new file mode 100644 index 0000000..fd3ea8d --- /dev/null +++ b/src/pages/Error/index.tsx @@ -0,0 +1,26 @@ +import { Button, Result } from 'antd'; + +const ErrorPage = () => { + document.title = '404 - 抱歉,您访问的页面不存在'; + return ( +
+ { + location.href = '/'; + }} + > + {'返回首页'} + + } + /> +
+ ); +}; + +export default ErrorPage; diff --git a/src/pages/Index/index.tsx b/src/pages/Index/index.tsx new file mode 100644 index 0000000..e0d2c80 --- /dev/null +++ b/src/pages/Index/index.tsx @@ -0,0 +1,34 @@ +const Index = () => { + return ( +
+ 开发中... + {/* Index */} + {/* + + + login */} + {/* {undefined.map()} */} +
+ ); +}; + +export default Index; diff --git a/src/pages/Login/index.tsx b/src/pages/Login/index.tsx new file mode 100644 index 0000000..24a1a07 --- /dev/null +++ b/src/pages/Login/index.tsx @@ -0,0 +1,86 @@ +import { Button, Input } from 'antd'; +import { stringify } from 'qs'; +import { useState } from 'react'; +import loginBg from '@/assets/loginBg.jpg'; +import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin'; +import { DefaultERPName } from '@/configs/config'; +import { notificationEventBus } from '@/utils/EventBus'; +import { useRequest } from '@/utils/useRequest'; + +const Login = () => { + const [userInfo, setUserInfo] = useState({ login_name: 'zhengw', password: '123456', login_type: 1 }); + const { request, loading } = useRequest('Users/login', { + onSuccessCodeZero() { + notificationEventBus.emit({ description: '登录成功' }); + location.href = '#/'; + }, + }); + + document.title = '登录'; + + const login = () => { + request(stringify(userInfo)); + }; + + return ( +
+
+
{DefaultERPName}后台登录
+ + + { + userInfo.login_name = e.target.value; + setUserInfo({ ...userInfo }); + }} + onPressEnter={login} + /> + + + { + userInfo.password = e.target.value; + setUserInfo({ ...userInfo }); + }} + onPressEnter={login} + /> + + + + + +
+
+ ); +}; + +export default Login; diff --git a/src/pages/Staff/dep/index.tsx b/src/pages/Staff/dep/index.tsx new file mode 100644 index 0000000..20418c2 --- /dev/null +++ b/src/pages/Staff/dep/index.tsx @@ -0,0 +1,17 @@ +import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin'; + +const DepContent = () => { + return ( +
+
Dep
+
+ ); +}; + +const Dep = () => ( + + + +); + +export default Dep; diff --git a/src/pages/Staff/group/index.tsx b/src/pages/Staff/group/index.tsx new file mode 100644 index 0000000..bc86d32 --- /dev/null +++ b/src/pages/Staff/group/index.tsx @@ -0,0 +1,17 @@ +import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin'; + +const GroupContent = () => { + return ( +
+
Group
+
+ ); +}; + +const Group = () => ( + + + +); + +export default Group; diff --git a/src/pages/User/List/components/UserEditModal.tsx b/src/pages/User/List/components/UserEditModal.tsx new file mode 100644 index 0000000..1069174 --- /dev/null +++ b/src/pages/User/List/components/UserEditModal.tsx @@ -0,0 +1,26 @@ +import type React from 'react'; +import { useImperativeHandle, useState } from 'react'; +import ModalPlugin from '@/components/ModalPlugin'; +import type { IRef } from '@/utils/type'; + +interface IProps extends IRef {} + +export type IUserEditModalType = { + show: () => void; +}; + +export const UserEditModal: React.FC = (props) => { + console.log(props.ref); + const [open, setOpen] = useState(false); + + useImperativeHandle(props.ref, () => ({ + show: () => { + setOpen(true); + }, + })); + return ( + setOpen(false)}> + 11111 + + ); +}; diff --git a/src/pages/User/List/components/state.ts b/src/pages/User/List/components/state.ts new file mode 100644 index 0000000..413fd64 --- /dev/null +++ b/src/pages/User/List/components/state.ts @@ -0,0 +1,89 @@ +import { proxy } from 'valtio'; +import { deepClone } from 'valtio/utils'; +import type { IOption, IParamsBase } from '@/interfaces/common'; +import { UserServices } from '@/services/UserServices'; +import { toArray, toNumber, toObject } from '@/utils/common'; +import { requestLite } from '@/utils/useRequest2'; + +const defaultParams = { curr_page: 1, page_count: 20 }; + +type IParams = IParamsBase & { + order_no?: string; + custom_order_no?: string; + custom_name?: string; + custom_phone?: string; + end_user_address?: string; + end_user_phone?: string; + end_user_name?: string; + payed_state?: string; + document_dateL?: string; + document_dateU?: string; + create_dateL?: string; + create_dateU?: string; + process_state?: any[]; + order_step?: any[]; + category_id?: any; +}; + +export const userListStateProxy = proxy<{ + params: IParams; + loading: boolean; + ajaxData: any[]; + orderStepsOptions: IOption[]; + count: number; + amount: { + tot_discount_money?: string; + tot_payed_amount?: string; + tot_tax_last_money?: string; + tot_un_payed_amount?: string; + }; + showMoreSearch: boolean; + reset: () => void; + getData: () => void; + clear: () => void; + page: (current?: number, pageSize?: number) => void; + // !分页回调函数 + pageCallback?: () => void; +}>({ + params: deepClone(defaultParams), + loading: false, + showMoreSearch: false, + ajaxData: [], + orderStepsOptions: [], + amount: {}, + count: 0, + reset() { + this.params = deepClone(defaultParams); + this.getData(); + }, + page(current, pageSize) { + if (!this.loading) { + this.params.curr_page = current || 1; + this.params.page_count = pageSize || this.params.page_count; + this.getData(); + this.pageCallback?.(); + } + }, + async getData() { + this.loading = true; + const temp: any = deepClone(this.params); + if (temp.process_state?.length) { + temp.process_state = temp.process_state.join(','); + } + if (temp.order_step?.length) { + temp.order_step = temp.order_step.join(','); + } + const res: any = await requestLite(UserServices.list, temp); + this.loading = false; + this.ajaxData = toArray(res?.data); + if (this.ajaxData.length == 0 && this.params.curr_page > 1) { + this.page(this.params.curr_page - 1); + } + this.count = toNumber(res?.count); + this.amount = toObject(res?.amount); + }, + clear() { + this.ajaxData = []; + this.pageCallback = undefined; + }, +}); diff --git a/src/pages/User/List/index.tsx b/src/pages/User/List/index.tsx new file mode 100644 index 0000000..f00ab1c --- /dev/null +++ b/src/pages/User/List/index.tsx @@ -0,0 +1,167 @@ +import { Button } from 'antd'; +import { useRef } from 'react'; +import { useSnapshot } from 'valtio'; +import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin'; +import { GapBox } from '@/components/GapBox'; +import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin'; +import { FooterPagination, HeaderPagination } from '@/components/PaginationPlugin'; +import { MoreSearchButton, ResetButton, SearchButton, SearchInputPlugin } from '@/components/SearchButton'; +import type { ColumnsTypeUltra2 } from '@/components/TableColumnsFilterPlugin2'; +import { formatTableSort, TablePlugin } from '@/components/TablePlugin'; +import { tableFixedByPhone } from '@/utils/common'; +import { userListStateProxy } from './components/state'; +import { type IUserEditModalType, UserEditModal } from './components/UserEditModal'; + +const SearchBox = () => { + const snap = useSnapshot(userListStateProxy); + + return ( + <> + + + { + userListStateProxy.page(1); + }} + onEnd={(v) => { + userListStateProxy.params.order_no = v; + }} + /> + + + { + userListStateProxy.page(1); + }} + onEnd={(v) => { + userListStateProxy.params.custom_order_no = v; + }} + /> + + + { + userListStateProxy.page(1); + }} + onEnd={(v) => { + userListStateProxy.params.custom_name = v; + }} + /> + + + + + { + userListStateProxy.page(1); + }} + /> + { + userListStateProxy.reset(); + }} + /> + { + userListStateProxy.showMoreSearch = !userListStateProxy.showMoreSearch; + }} + /> + + + + + + { + userListStateProxy.page(1); + }} + onEnd={(v) => { + userListStateProxy.params.custom_phone = v; + }} + /> + + + + ); +}; + +const Content = () => { + const snap = useSnapshot(userListStateProxy); + const tableColumns: ColumnsTypeUltra2 = [ + { + columnName: '操作', + title: '操作', + fixed: tableFixedByPhone('left'), + width: 52, + render: () => { + return {/* */}; + }, + }, + { columnName: '创建时间', width: 150, title: '创建时间', dataIndex: 'create_date', sorter: true }, + { columnName: '备注', title: '备注', dataIndex: 'comments', width: 180 }, + { columnName: '' }, + ]; + + const UserEditModalRef = useRef(null); + + return ( + <> + + + + + { + userListStateProxy.page(page); + }} + /> + + { + userListStateProxy.params.order = formatTableSort(sort); + userListStateProxy.page(1); + }} + dataSource={snap.ajaxData} + rowKey={'user_id'} + columns={tableColumns} + /> + { + userListStateProxy.page(page, pageSize); + }} + /> + + + + ); +}; + +const UserList = () => ( + + + + +); + +export default UserList; diff --git a/src/router/Link.tsx b/src/router/Link.tsx new file mode 100644 index 0000000..59865c4 --- /dev/null +++ b/src/router/Link.tsx @@ -0,0 +1,8 @@ +import type React from "react"; +import { urlFormat } from "./routerUtils"; + +const Link: React.FC<{ href: string; children: React.ReactNode }> = (props) => { + return {props.children}; +}; + +export default Link; diff --git a/src/router/Outlet.tsx b/src/router/Outlet.tsx new file mode 100644 index 0000000..000a089 --- /dev/null +++ b/src/router/Outlet.tsx @@ -0,0 +1,48 @@ +import { Spin } from 'antd'; +import React, { Suspense, useEffect, useRef, useState } from 'react'; +import { routeMatchingHash } from './routerUtils'; + +const Outlet = () => { + const [key, setKey] = useState(1); + const OutLetRef = useRef(null); + + useEffect(() => { + const handle = async () => { + const res: any = routeMatchingHash(); + if (OutLetRef.current != res?.Component) { + OutLetRef.current = res?.Component; + setKey(Date.now()); + } + }; + handle(); + + window.addEventListener('hashchange', handle); + + return () => { + window.removeEventListener('hashchange', handle); + }; + }, []); + + return ( + + {OutLetRef.current ? ( + OutLetRef.current?.$$typeof == Symbol.for('react.lazy') ? ( + + } + > + + + ) : ( + + ) + ) : null} + + ); +}; + +export default Outlet; diff --git a/src/router/Router.tsx b/src/router/Router.tsx new file mode 100644 index 0000000..a4f3ecc --- /dev/null +++ b/src/router/Router.tsx @@ -0,0 +1,32 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { routerData } from './router-data.js'; +import { routeMatchingHash, routerFormat } from './routerUtils.js'; +import type { IRouteItem } from './types.js'; + +const Router: React.FC<{ routes: IRouteItem[] }> = (props) => { + const { routes } = props; + const [key, setKey] = useState(1); + const LayoutRef = useRef(null); + routerData.routers = routerFormat(routes); + + useEffect(() => { + const handle = () => { + const res: any = routeMatchingHash(); + if (LayoutRef.current != res?.Layout) { + LayoutRef.current = res?.Layout; + setKey(Date.now()); + } + }; + handle(); + + window.addEventListener('hashchange', handle); + + return () => { + window.removeEventListener('hashchange', handle); + }; + }, []); + + return {LayoutRef.current ? : null}; +}; + +export default Router; diff --git a/src/router/router-data.ts b/src/router/router-data.ts new file mode 100644 index 0000000..4ff5e14 --- /dev/null +++ b/src/router/router-data.ts @@ -0,0 +1,9 @@ +interface IRouterData { + mode: 'hash' | 'history'; + routers: Map; +} + +export const routerData: IRouterData = { + mode: 'hash', + routers: new Map(), +}; diff --git a/src/router/routerUtils.ts b/src/router/routerUtils.ts new file mode 100644 index 0000000..f7055e0 --- /dev/null +++ b/src/router/routerUtils.ts @@ -0,0 +1,72 @@ +import { routerData } from './router-data'; + +/** 路由导航 */ +export const navigate = (path: string) => { + window.location.hash = urlFormat(path); +}; + +export const urlFormat = (path: string) => { + const url = `${path || ''}`.trim(); + if (url.startsWith('http') || url.startsWith('blob')) { + return url; + } + return `#${url}`; +}; + +/** 获取查询参数 */ +export const getURLSearchParams = () => { + const { hash } = location; + const params = hash.includes('?') ? hash.slice(hash.indexOf('?')) : ''; + return new URLSearchParams(params); +}; + +export const getHash = () => { + let hash = location.hash; + if (hash.startsWith('#')) { + hash = hash.slice(1); + } + if (hash.includes('?')) { + hash = hash.slice(0, hash.indexOf('?')); + } + hash = hash.endsWith('/') ? hash.slice(0, hash.length - 1) : hash; + return hash; +}; + +export const routerFormat = (routes: any[]) => { + const router = new Map(); + routes.forEach((el) => { + router.set(`${el.path}`, { ...el }); + if (Array.isArray(el.children)) { + el.children.forEach((ell: any, i: number) => { + if (i == 0) { + router.set(`${el.path}`, { ...el, ...ell }); + } + router.set(`${el.path}${ell.path}`, { ...el, ...ell }); + }); + } + }); + return router; +}; + +export const routeMatchingHash = () => { + const hash = getHash(); + let obj: any = {}; + // console.log(hash); + if (routerData.routers.has(hash)) { + obj = routerData.routers.get(hash); + } else { + if (hash) { + if (routerData.routers.has('*')) { + obj = routerData.routers.get('*'); + } + // + // console.warn('请配置 * 错误路由'); + } else { + // 返回第一个路由 + obj = routerData.routers.values().next().value; + } + } + + // document.title = obj.title || ''; + return obj; +}; diff --git a/src/router/types.ts b/src/router/types.ts new file mode 100644 index 0000000..15a3728 --- /dev/null +++ b/src/router/types.ts @@ -0,0 +1,12 @@ +export type IRouteItemChild = { + path: string; + Component: any; + title?: string; +}; + +export type IRouteItem = { + path: string; + Layout: any; + title?: string; + children: IRouteItemChild[]; +}; diff --git a/src/services/UserServices.ts b/src/services/UserServices.ts new file mode 100644 index 0000000..8e5c2dc --- /dev/null +++ b/src/services/UserServices.ts @@ -0,0 +1,3 @@ +export const UserServices = { + list: '/UserServices/list', +} as const; diff --git a/src/store/AuthStore.ts b/src/store/AuthStore.ts new file mode 100644 index 0000000..49d78f1 --- /dev/null +++ b/src/store/AuthStore.ts @@ -0,0 +1,18 @@ +import { create, type StoreApi, type UseBoundStore } from 'zustand'; + +export type IAuth = { [key: string]: boolean }; +export type IAuthByPathname = { [key: string]: string }; + +type IUser = { + auth: IAuth; + authByPathname: IAuthByPathname; + updateAuth: (data: IAuth) => void; + initAuthByPathname: (data: IAuthByPathname) => void; +}; + +export const useAuthStore: UseBoundStore> = create((set) => ({ + auth: {}, + updateAuth: (data) => set(() => ({ auth: data })), + authByPathname: {}, + initAuthByPathname: (data: IAuthByPathname) => set(() => ({ authByPathname: data })), +})); diff --git a/src/store/CompanyStore.ts b/src/store/CompanyStore.ts new file mode 100644 index 0000000..c2e0abb --- /dev/null +++ b/src/store/CompanyStore.ts @@ -0,0 +1,14 @@ +import { create, type StoreApi, type UseBoundStore } from "zustand"; +import type { CompanyInfo } from "./type"; + +type IBear = { + company: CompanyInfo; + updateCompany: (data: CompanyInfo) => void; +}; + +export const useCompanyStore: UseBoundStore> = create( + (set) => ({ + company: {}, + updateCompany: (data) => set(() => ({ company: data })), + }), +); diff --git a/src/store/ConfigStore.ts b/src/store/ConfigStore.ts new file mode 100644 index 0000000..4e8f546 --- /dev/null +++ b/src/store/ConfigStore.ts @@ -0,0 +1,25 @@ +import { create, type StoreApi, type UseBoundStore } from 'zustand'; + +interface IConfigType { + // config_id: number; + config_value: string; + // rel_config_id: number; + // create_date: string; + // config_type: string; + // config_name: string; + // config_desc: string; + // form_type: string; + // setting: string; + // config_state: number; +} + +type IConfig = { + config: { [key: string]: IConfigType }; + updateConfig: (data: { [key: string]: IConfigType }) => void; +}; + +/** 参数化配置store */ +export const useConfigStore: UseBoundStore> = create((set) => ({ + config: {}, + updateConfig: (data) => set(() => ({ config: data })), +})); diff --git a/src/store/RefreshStore.ts b/src/store/RefreshStore.ts new file mode 100644 index 0000000..e5d1df5 --- /dev/null +++ b/src/store/RefreshStore.ts @@ -0,0 +1,11 @@ +import { create, type StoreApi, type UseBoundStore } from 'zustand'; + +type IUser = { + refresh: number; + updateRefresh: (data: number) => void; +}; + +export const useRefreshStore: UseBoundStore> = create((set) => ({ + refresh: 1, + updateRefresh: (data) => set(() => ({ refresh: data })), +})); diff --git a/src/store/UserConfigStore.ts b/src/store/UserConfigStore.ts new file mode 100644 index 0000000..7694ee5 --- /dev/null +++ b/src/store/UserConfigStore.ts @@ -0,0 +1,22 @@ +// import { create, type StoreApi, type UseBoundStore } from 'zustand'; +// import type { UsersConfig } from '@/services/UserServicesAndConfig'; + +// type IUsersConfig = { +// [key in keyof typeof UsersConfig]?: { +// config_id?: number; +// config_name: string; +// config_value: string; +// update_date: string | null; +// }; +// }; + +// type IUser = { +// config: IUsersConfig; +// updateConfig: (data: IUsersConfig) => void; +// }; + +// /** 用户配置store */ +// export const useUsersConfigStore: UseBoundStore> = create((set) => ({ +// config: {}, +// updateConfig: (data) => set(() => ({ config: data })), +// })); diff --git a/src/store/UserStore.ts b/src/store/UserStore.ts new file mode 100644 index 0000000..90cc037 --- /dev/null +++ b/src/store/UserStore.ts @@ -0,0 +1,12 @@ +import { create, type StoreApi, type UseBoundStore } from "zustand"; +import type { UserInfo } from "./type"; + +type IUser = { + user: UserInfo; + updateUser: (data: UserInfo) => void; +}; + +export const useUserStore: UseBoundStore> = create((set) => ({ + user: {}, + updateUser: (data) => set(() => ({ user: data })), +})); diff --git a/src/store/indexDBStore.ts b/src/store/indexDBStore.ts new file mode 100644 index 0000000..71ef91f --- /dev/null +++ b/src/store/indexDBStore.ts @@ -0,0 +1,11 @@ +import { create, type StoreApi, type UseBoundStore } from 'zustand'; + +type IIndexDB = { + db: any; + init: (data: any) => void; +}; + +export const useIndexDBStore: UseBoundStore> = create((set) => ({ + db: {}, + init: (data) => set(() => ({ db: data })), +})); diff --git a/src/store/type.ts b/src/store/type.ts new file mode 100644 index 0000000..d52e02f --- /dev/null +++ b/src/store/type.ts @@ -0,0 +1,39 @@ +export type UserInfo = { + login_name?: string; + logo?: string; + last_login_time?: string; + nick_name?: string; + state?: number; + user_id?: number; + user_sex?: number; + user_phone?: string; + visit_times?: string; + create_date?: string; + logoKey?: number; + wx_head_img?: string; + wx_nick_name?: string; + wx_open_id?: string; + self_account?: number; +}; + +export type CompanyInfo = { + company_address?: string; + company_desc?: string; + company_domain?: string; + company_id?: number; + company_logo?: string; + company_name?: string; + company_state?: string; + create_date?: string; + eff_date?: string; + exp_date?: string; + erp_name?: string; + last_login_name?: string; + user_id?: string; + domain?: string; + desc?: string; + company_list?: any[]; + sale_id?: any; + staff_type?: any; + erp_version?: number; +}; diff --git a/src/utils/EventBus.ts b/src/utils/EventBus.ts new file mode 100644 index 0000000..bc58faf --- /dev/null +++ b/src/utils/EventBus.ts @@ -0,0 +1,150 @@ +import type { ReactNode } from 'react'; + +// class EventBus { +// eventMap: { [key: string]: (() => void)[] } = {}; +// constructor() { +// // 存储事件映射:key=事件名,value=回调函数数组 +// this.eventMap = Object.create(null); +// } + +// /** +// * 订阅事件 +// * @param {string} eventName - 事件名称 +// * @param {Function} callback - 事件触发时的回调函数 +// */ +// on(eventName: string, callback: () => void) { +// if (typeof callback !== 'function') { +// throw new Error('回调函数必须是函数类型'); +// } +// // 若事件不存在,初始化一个空数组 +// if (!this.eventMap[eventName]) { +// this.eventMap[eventName] = []; +// } +// // 将回调加入事件对应的数组(支持多个订阅者) +// this.eventMap[eventName].push(callback); +// } + +// /** +// * 发布事件(触发订阅者回调) +// * @param {string} eventName - 事件名称 +// * @param {...any} args - 传递给回调的参数(支持多个) +// */ +// emit(eventName: string, ...args: any) { +// // 若事件无订阅者,直接返回 +// if (!this.eventMap[eventName]) return; +// // 遍历所有订阅者,执行回调(传递参数) +// // 用slice()创建副本,避免执行回调时修改数组(如取消订阅)导致遍历异常 +// this.eventMap[eventName].slice().forEach((callback: () => void) => { +// callback.apply(this, args); +// }); +// } + +// /** +// * 取消订阅 +// * @param {string} eventName - 事件名称 +// * @param {Function} [callback] - 要取消的回调(不传则取消该事件所有订阅) +// */ +// off(eventName: string, callback: () => void) { +// const callbacks = this.eventMap[eventName]; +// if (!callbacks) return; + +// // 情况1:不传callback,取消该事件所有订阅 +// if (!callback) { +// delete this.eventMap[eventName]; +// return; +// } + +// // 情况2:传callback,只取消指定回调(避免影响其他订阅者) +// const index = callbacks.indexOf(callback); +// if (index !== -1) { +// callbacks.splice(index, 1); +// // 若事件无剩余订阅者,删除该事件(优化内存) +// if (callbacks.length === 0) { +// delete this.eventMap[eventName]; +// } +// } +// } + +// /** +// * 订阅一次事件(触发后自动取消订阅) +// * @param {string} eventName - 事件名称 +// * @param {Function} callback - 回调函数 +// */ +// once(eventName: string, callback: () => void) { +// // 包装回调:执行后自动取消订阅 +// const wrapCallback = (...args: any) => { +// callback.apply(this, args); +// this.off(eventName, wrapCallback); +// }; +// this.on(eventName, wrapCallback); +// } +// } + +/** 单例 */ +// function singleton(className: object) { +// let ins: any = null; +// const proxy = new Proxy(className, { +// construct(target, args) { +// if (!ins) { +// ins = Reflect.construct(target, args); +// } +// return ins; +// }, +// }); +// proxy.prototype.constructor = proxy; +// return proxy; +// } + +// const Bus = singleton(EventBus); + +// export const eventBus = new Bus(); + +type INotificationConfig = { + /** 标题 默认: 系统通知 */ + title?: ReactNode; + /** 内容 */ + description?: ReactNode; + /** 当前通知唯一标志 */ + key?: string; + /** 通知类型, 默认: success */ + type?: 'success' | 'info' | 'error' | 'warning'; + duration?: number; +}; + +const notificationEvent: any = {}; + +/** + * 通知事件 + */ +export const notificationEventBus = { + /** + * 监听打开通知事件 + * @param callback 回调函数 + */ + onOpen(callback: (data: INotificationConfig) => void) { + notificationEvent.notification = callback; + }, + /** + * 发送通知数据 + * @param {INotificationConfig} data INotificationConfig + */ + emit(data: INotificationConfig) { + data.type = data.type || 'success'; + data.title = data.title || '系统通知'; + notificationEvent.notification?.(data); + }, + /** + * 发送关闭通知 + * @param key 通知唯一标志 + */ + emitClose(key: string) { + notificationEvent.notificationClose?.(key); + }, + /** + * 监听关闭通知事件 + * @param callback 回调函数 + */ + onClose(callback: (key: string) => void) { + notificationEvent.notificationClose = callback; + }, +}; diff --git a/src/utils/UniqueKey.ts b/src/utils/UniqueKey.ts new file mode 100644 index 0000000..b881bb8 --- /dev/null +++ b/src/utils/UniqueKey.ts @@ -0,0 +1,4 @@ +let count = 1; +/** 生成唯一key */ +// export const uKey = () => `${Date.now().toString(36)}-${Math.random().toString(36).substring(2)}`; +export const uKey = () => count++; diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 0000000..d6d5238 --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1,366 @@ +import Big from 'big.js'; +import dayjs from 'dayjs'; +import { DefaultERPName } from '@/configs/config'; + +/** 获取设备屏幕大小 */ +export const getDevice = (): 'phone' | 'tablet' | 'desktop' => { + const width = window.innerWidth; + const isPhone = typeof navigator !== 'undefined' && navigator && navigator.userAgent.match(/phone/gi); + + if (width < 768 || isPhone) { + return 'phone'; + } else if (width < 1280 && width > 768) { + return 'tablet'; + } else { + return 'desktop'; + } +}; + +/** + * 判断字符串包含字符串 + * @param str 待判断的字符串 + * @param search 查询字符串 + * @returns Boolean + */ +export const includesString = (str: string, search: string): boolean => { + return `${str}`.toLocaleUpperCase().includes(search.toLocaleUpperCase()); +}; + +/** 路径前面添加 api */ +export const pathAddApiString = (path: string): string => { + /** 生产环境不加 api */ + // if (import.meta.env.PROD) { + // return path; + // } + if (typeof path == 'string') { + if (`${path}`.startsWith('http') || `${path}`.startsWith('blob:http')) { + return path; + } + if (`${path}`.startsWith('/')) { + return `/api${path}`; + } + return `/api/${path}`; + } + return path; +}; + +/** 只保留数字 */ +export const preserveNumbers = (val: any): string => { + return `${val}`.replace(/[^0-9]/gi, ''); +}; + +/** 判断数据是不是数组类型 */ +export const isArray = (data: any): boolean => { + return data && Array.isArray(data); +}; + +export const toArray = (data: any): any[] => { + return isArray(data) ? data : []; +}; + +/** 判断数据是不是对象类型 */ +export const isObject = (data: any): boolean => { + return data && `${Object.prototype.toString.call(data)}`.includes('Object'); +}; + +export const toObject = (data: any): object => { + return isObject(data) ? data : {}; +}; + +/** object clean */ +export const objectClear = (data: any): any => { + if (isObject(data)) { + for (const key of Object.keys(data)) { + data[key] = undefined; + } + } + return data; +}; + +/** 获取时间毫秒 */ +export const getNowTime = (): number => Date.now(); + +/** 日期格式化 YYYY-MM-DD */ +export const dateFormat = (date: Date): string => { + return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date + .getDate() + .toString() + .padStart(2, '0')}`; +}; + +/** 获取当前日期 格式化 YYYY-MM-DD */ +export const getNowDate = (): string => { + return dateFormat(new Date()); +}; + +/** 判断是json数据 */ +export const isJson = (str: any): boolean => { + if (str && typeof str == 'string') { + try { + const obj = JSON.parse(str); + return obj && typeof obj == 'object'; + } catch (_e) { + // + } + } + return false; +}; + +/** + * 解码json数据 + * @param data 数据 + * @returns array | object | null + */ +export const jsonParse = (data: any): any[] | object | null => { + if (data) { + if (typeof data == 'string') { + try { + const obj = JSON.parse(data); + if (['Array', 'Object'].includes(Object.prototype.toString.call(obj).slice(8, -1))) { + return obj; + } + } catch (_e) { + // + } + } else if (['Array', 'Object'].includes(Object.prototype.toString.call(data).slice(8, -1))) { + return data; + } + } + return null; +}; + +/** 判断是数字 */ +export const isNumber = (value: any): boolean => { + // biome-ignore lint/suspicious/noGlobalIsNan: + // biome-ignore lint/suspicious/noGlobalIsFinite: + return !isNaN(Number.parseFloat(value)) && isFinite(value); +}; + +/** 转成数字 */ +export const toNumber = (str: any): number => { + return isNumber(str) ? Number(str) : 0; +}; + +/** 转成字符串并去除前后空格 */ +export const toStringAndTrim = (value: any, trim = true): string => { + const str = typeof value == 'string' ? value : ''; + return trim ? str.trim() : str; +}; + +/** 替换中文标点 ?【】:() */ +export const chinesePunctuationReplace = (str: string) => { + // ?【】:() + + if (str && typeof str == 'string') { + return str + .replace(/?/g, '?') + .replace(/【/g, '[') + .replace(/】/g, ']') + .replace(/:/g, ':') + .replace(/(/g, '(') + .replace(/)/g, ')') + .replace(/“/g, '"') + .replace(/”/g, '"') + .replace(/‘/g, '"') + .replace(/’/g, '"'); + } + return str; +}; + +/** 打开二维码窗口 */ +export const openPrintWindow = (msg: string, desc?: string) => { + window.open( + `/#/print/qrcode?msg=${encodeURIComponent(msg)}${desc ? `&desc=${encodeURIComponent(desc)}` : ''}`, + '_blank', + 'height=600,width=800', + ); +}; + +export const formatErpConfigList = (data: any[]) => { + const obj: any = {}; + toArray(data).forEach((item) => { + obj[item.config_type_en] = { + config_value: item.config_value, + }; + }); + return obj; +}; + +/** 转换文件大小 */ +export const formatFileSize = (fileSize: any): string => { + const file_size = toNumber(fileSize); + if (file_size == 0) { + return '0B'; + } + const unitArr = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + let index = 0; + index = Math.floor(Math.log(file_size) / Math.log(1024)); + const size = file_size / 1024 ** index; + return size.toFixed(0) + unitArr[index]; +}; + +/** 文本脱敏 */ +export function desensitizedCommon(str: string, begin = 1, end = 1) { + if (!str && begin + end >= str.length) { + return ''; + } + const leftStr = str.substring(0, begin); + const rightStr = str.substring(str.length - end, str.length); + let strCon = ''; + for (let i = 0; i < str.length - end - begin; i++) { + strCon += '*'; + } + return leftStr + strCon + rightStr; +} + +export const isImageFile = (path: string) => { + return /\.(jpe?g|png|gif|svg|webp|bmp)$/i.test(path); +}; + +export const getBoundingClientRect = ( + dom: any, +): { + bottom: number; + height: number; + left: number; + right: number; + top: number; + width: number; +} => { + return ( + dom?.getBoundingClientRect() || { + bottom: 0, + height: 0, + left: 0, + right: 0, + top: 0, + width: 0, + } + ); +}; + +/** + * 商品数量转换成显示单位数量 + * @param goods 商品 + * @param {string} key 商品数量的key + * @returns {Object} {nums: number, unit: string} + */ +export const goodsStockFormatShowUnit = (goods: any, key: string): { nums: any; unit: string } => { + const g: any = toObject(goods); + const unit = g.depot_show_unit_name || ''; + const value = g[key]; + // if (goods.depot_show_unit && goods.base_unit != goods.depot_show_unit) { + // value = new Big(toNumber(value) / toNumber(goods.unit_ratio)).toFixed(3); + // unit = goods.depot_show_unit_name; + // } + + return { + nums: value, + unit, + }; +}; + +type IGoodsRatioFormatNum = { + base_unit: any; + two_unit: any; + ratio: any; + unit: any; + num: any; +}; +/** 商品根据比例换算数量 */ +export const goodsRatioFormatNum = (goods: IGoodsRatioFormatNum): number => { + let num = toNumber(goods.num); + const ratio = toNumber(goods.ratio); + if (goods.base_unit == goods.unit) { + num = Big(num).times(ratio).toNumber(); + } else { + if (ratio != 0) { + num = Big(num).div(ratio).toNumber(); + } else { + console.warn('goodsRatioFormatNum被除数为0'); + } + } + return num; +}; + +/** + * 数组对象排序 数字类型 + * @param data + * @returns data + */ +export const arraySortTypeNumber = (arr: any, order?: string) => { + const data = toArray(arr); + if (order) { + const [key, sort] = order.split(' '); + data.sort((a: any, b: any) => { + if (sort === 'asc') { + return toNumber(a[key]) - toNumber(b[key]); + } else { + return toNumber(b[key]) - toNumber(a[key]); + } + }); + } + return data; +}; + +/** 导出文本 */ +export const exportText = (text: string, filename: string) => { + const blob = new Blob([`${text}`], { type: 'text/plain;charset=utf-8' }); + const objectURL = URL.createObjectURL(blob); + downloadFile(objectURL, filename); + URL.revokeObjectURL(objectURL); +}; + +/** 下载文件 */ +export const downloadFile = (objectURL: string, filename: string) => { + const aTag = document.createElement('a'); + aTag.href = objectURL; + aTag.download = filename; + aTag.click(); +}; + +/** 表格锁列小屏幕不锁列 */ +export const tableFixedByPhone = (fixed: 'left' | 'right') => { + if (window.dfConfig.isPhone) { + return undefined; + } + return fixed; +}; + +/** ajax参数转json字符串 */ +export const paramsToJson = (params: any): object => { + const obj: any = {}; + Object.keys(toObject(params)).forEach((key) => { + if (isArray(params[key]) || isObject(params[key])) { + obj[key] = JSON.stringify(params[key]); + } else { + obj[key] = params[key]; + } + }); + return obj; +}; + +export async function dingRequest(msg: string) { + const loginName = localStorage.getItem('login_name'); + const userPhone = localStorage.getItem('user_phone'); + const userIP = localStorage.getItem('userIP'); + const href = window.location.href; + const userAgent = navigator.userAgent; + + let baseMsg = `${DefaultERPName}发生错误\n报错地址:${href}\n登录用户:${loginName}\n手机号码:${userPhone}\nIP地址:${userIP}\n`; + baseMsg += `浏览器信息:${userAgent}\n触发时间:${dayjs().format('YYYY-MM-DD HH:mm:ss')}`; + + // !开发环境 + if (import.meta.env.DEV || location.hostname == 'free.erp') { + return; + } + // 发送钉钉消息 + return await fetch('https://chenfeng.tech:7779/Weixin-User-ding', { + method: 'POST', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + body: `token=3945cee5317f212d824da3fef16e321bb23ae5c3cf6b5f81d37f90568be89b1e&msg=${baseMsg}\n${msg}`, + }); +} diff --git a/src/utils/commonUtils.ts b/src/utils/commonUtils.ts new file mode 100644 index 0000000..f8428fd --- /dev/null +++ b/src/utils/commonUtils.ts @@ -0,0 +1,184 @@ +import Big from 'big.js'; +import { isArray, isObject, toNumber, toObject, toStringAndTrim } from './common.ts'; + +/** 搜索参数格式化(字符串去除前后空格) */ +export const paramsFormat = ( + params: any, + config?: { + /** 是否将数组转json */ + arrayToJson?: boolean; + /** 是否将对象转json */ + objectToJson?: boolean; + /** 是否将数组和对象转json */ + toJson?: boolean; + }, +): object => { + const obj: any = {}; + Object.keys(toObject(params)).forEach((key) => { + if (typeof params[key] === 'string') { + obj[key] = toStringAndTrim(params[key]); + } else { + if (config?.toJson && (isArray(params[key]) || isObject(params[key]))) { + obj[key] = JSON.stringify(params[key]); + } else { + if (config?.arrayToJson && isArray(params[key])) { + obj[key] = JSON.stringify(params[key]); + } else if (config?.objectToJson && isObject(params[key])) { + obj[key] = JSON.stringify(params[key]); + } else { + obj[key] = params[key]; + } + } + } + }); + return obj; +}; + +/** + * sleep + * @param callback 回调函数 + * @param ms 毫秒, 默认300ms + * @returns + */ +export const sleep = (callback?: () => void, ms = 300): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + callback?.(); + resolve(true); + }, ms); + }); +}; + +/** + * 空数据是返回前一页 + * @param dataLength + * @param curr_page 当前页 + * @param page 分页函数 + */ +export const navigateBackIfEmpty = (dataLength: number, curr_page: number, page: (curr: number) => void) => { + dataLength === 0 && curr_page > 1 && page(curr_page - 1); +}; + +/** 检测支持语言 */ +export const checkSupportLanguage = (lang?: string | null) => (lang && ['zh-cn', 'en'].includes(lang) ? lang : 'zh-cn'); + +// export const notificationFun = (option: { +// title?: React.ReactNode; +// type?: 'info' | 'success' | 'warning' | 'error' | 'normal'; +// content?: React.ReactNode; +// }) => { +// const { title = t('系统提示'), type = 'success' } = option; +// Notification[type]({ +// title: title, +// content: option.content || '', +// }); +// }; + +// export const modalFun = (option: { +// title?: React.ReactNode; +// type?: 'info' | 'success' | 'warning' | 'error' | 'confirm'; +// content?: React.ReactNode; +// onOk: (e?: MouseEvent) => Promise; +// okText?: string; +// okButtonProps?: ButtonProps; +// }) => { +// const { title = t('系统提示'), type = 'confirm', onOk } = option; +// Modal[type]({ +// title: title, +// content: option.content || '', +// okButtonProps: { +// autoFocus: true, +// ...option.okButtonProps, +// }, +// onOk: onOk, +// okText: option.okText, +// }); +// }; + +/** 笛卡尔积 */ +export const cartesianProduct = (...arrays: any[]) => { + let result: any[] = []; + // 处理边界情况:如果没有传入数组,返回空数组 + if (arrays.length === 0) return result; + + // 初始结果为第一个数组的每个元素组成的单元素数组 + result = arrays[0].map((item: any) => [item]); + + // 遍历剩余的数组,与当前结果合并计算笛卡尔积 + for (let i = 1; i < arrays.length; i++) { + const currentArray = arrays[i]; + const temp: any[] = []; + // 对于结果中的每个已有组合 + for (const existingCombination of result) { + // 与当前数组的每个元素组合 + for (const item of currentArray) { + temp.push([...existingCombination, item]); + } + } + + // 更新结果为新的组合 + result = temp; + } + + return result; +}; + +export const blobToFile = (blob: BlobPart[], fileName: string, options?: FilePropertyBag) => { + return new File( + blob, + fileName, + options ?? { + lastModified: Date.now(), + }, + ); +}; + +/** Map数据转对象 */ +export const MapToObject = (data: Map) => Object.fromEntries(data); + +/** Map数据转对象json */ +export const MapToJson = (data: Map) => JSON.stringify(MapToObject(data)); + +/** 深拷贝 Map 对象(支持基本类型和引用类型只支持(一层)) */ +export const deepCopyMap = (data: Map) => { + const newMap = new Map(); + for (const [key, value] of data) { + if (Array.isArray(value)) { + // 处理数组 + newMap.set(key, [...value]); // 数组深拷贝(一层) + } else if (isObject(value)) { + // 处理对象(非 null 且为对象类型) + newMap.set(key, { ...value }); // 对象深拷贝(一层) + } else { + // 基本类型直接赋值 + newMap.set(key, value); + } + } + return newMap; +}; + +/** Set数据转数组 */ +export const SetToArray = (data: Set) => [...data]; + +/** Set数据转数组json */ +export const SetToJson = (data: Set) => JSON.stringify(SetToArray(data)); + +/** 价格保留位数 */ +export const priceRetentionDigits = (value?: number) => { + return toNumber(Big(toNumber(value)).toFixed(window.dfERPConfig.PRICE_HOLD_POINT)); +}; + +/** 价格保留位数字符串类型 */ +export const priceRetentionDigitsString = (value?: number) => { + return Big(toNumber(value)).toFixed(window.dfERPConfig.PRICE_HOLD_POINT); +}; + +/** 数量保留位数 */ +export const numRetentionDigits = (value?: number) => { + return toNumber(Big(toNumber(value)).toFixed(window.dfERPConfig.NUMS_HOLD_POINT)); +}; + +/** 数量保留位数字符串类型 */ +export const numRetentionDigitsString = (value?: number) => { + return Big(toNumber(value)).toFixed(window.dfERPConfig.NUMS_HOLD_POINT); +}; diff --git a/src/utils/copyToClipboard.ts b/src/utils/copyToClipboard.ts new file mode 100644 index 0000000..89d8d53 --- /dev/null +++ b/src/utils/copyToClipboard.ts @@ -0,0 +1,25 @@ +export const copyToClipboard = (textToCopy: string) => { + // navigator clipboard 需要https等安全上下文 + if (navigator.clipboard && window.isSecureContext) { + // navigator clipboard 向剪贴板写文本 + return navigator.clipboard.writeText(textToCopy); + } else { + // 创建text area + const textArea = document.createElement('textarea'); + textArea.value = textToCopy; + // 使text area不在viewport,同时设置不可见 + textArea.style.position = 'absolute'; + textArea.style.opacity = '0'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + return new Promise((resolve, reject) => { + // 执行复制命令并移除文本框 + document.execCommand('copy') ? resolve() : reject(); + textArea.remove(); + }); + } +}; diff --git a/src/utils/http.ts b/src/utils/http.ts new file mode 100644 index 0000000..b7f58ee --- /dev/null +++ b/src/utils/http.ts @@ -0,0 +1,69 @@ +import { pathAddApiString } from './common'; +import type { IAjaxDataBase } from './type'; + +// 辅助方法:统一处理响应内容(支持 json/text/blob 等格式) +// async function getResponseContent(response: any) { +// try { +// // 优先尝试解析为 JSON(大部分接口的错误响应格式) +// return await response.json(); +// } catch (_e) { +// try { +// // 若不是 JSON,解析为文本 +// return await response.text(); +// } catch (_e2) { +// // 若为二进制数据(如图片错误),返回类型提示 +// return `[二进制数据,类型: ${response.headers.get('Content-Type')}]`; +// } +// } +// } + +const ajax = async (method: string, url: string, data: any, config?: any) => { + try { + const res: IAjaxDataBase = await fetch(pathAddApiString(url), { + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + }, + method: method, + body: data, + credentials: 'include', + mode: 'cors', + ...config, + }).then((res) => res.json()); + + return res; + } catch (error: any) { + const err = { + message: error.message, + status: error.status || '无', // 仅 HTTP 状态错误有 + url: error.url || url, + responseBody: error.responseBody || '无', // 仅 HTTP 状态错误有 + stack: error.stack, // 错误堆栈(定位代码位置) + cause: error.cause, // 网络错误的底层原因(Chrome 96+ 支持) + type: error.name, // 错误类型(如 TypeError/AbortError) + }; + + // console.error('【fetch 详细错误】', error); + // 可根据错误类型做针对性处理 + if (error.name === 'AbortError') { + console.log('请求被手动取消'); + } else if (error.message.includes('CORS')) { + console.log('跨域错误,请检查服务端跨域配置'); + } + + throw err; // 可选:向上层抛出,让调用方处理 + } +}; + +export const post = (url: string, data?: any, config?: any) => { + return ajax('POST', url, data, config); +}; + +export const get = (url: string, data: any, config?: any) => { + return ajax('GET', url, data, config); +}; + +export const request = { + post, + get, +}; diff --git a/src/utils/type.ts b/src/utils/type.ts new file mode 100644 index 0000000..7587377 --- /dev/null +++ b/src/utils/type.ts @@ -0,0 +1,25 @@ +import type { ForwardedRef } from 'react'; + +/** params的基础类型 */ +export type IParamsBase = { + curr_page: number; + page_count: number; + order?: string; +}; + +/** ajax返回的基础类型 */ +export type IAjaxDataBase = { + count: number | undefined; + err_msg?: string; + err_code?: number; + [key: string]: any; +}; + +export type IRef = { + ref: ForwardedRef; +}; + +export type IOption = { + value: string | number; + label: string; +}; diff --git a/src/utils/update.js b/src/utils/update.js new file mode 100644 index 0000000..16bbc7d --- /dev/null +++ b/src/utils/update.js @@ -0,0 +1,51 @@ +import * as fs from "node:fs"; + +// 获取版本号 +const currDate = new Date(); +const year = currDate.getFullYear(); +const month = currDate.getMonth() + 1; +const strMonth = month >= 1 && month <= 9 ? `0${month}` : `${month}`; +const date = currDate.getDate(); +const strDate = date >= 0 && date <= 9 ? `0${date}` : `${date}`; +const hourMinutes = `${currDate.getHours()}${currDate.getMinutes()}`; +const version = `V${year}${strMonth}${strDate}-${hourMinutes}`; +const logDir = process.argv.slice(2)[0] ?? ""; +//span: { xl: 2, xxl: 2 }, +// 读取组件版本 +fs.readFile("package.json", "utf8", (_err, dataStr) => { + const data = JSON.parse(dataStr); + let comStr = "[\n"; + Object.keys(data.dependencies).forEach((item, index) => { + comStr += ` {\n key: ${ + index + 1 + },\n label: '${item}',\n value: '${ + data.dependencies[item] + }',\n },\n`; + }); + comStr += " ]"; + + const cfg = `// 基础配置文件,记录版本号,编译时间等 +export const EnvConfig = { + version: '${version}', + compile: '${currDate.toLocaleString()}', + helpName: '易宝赞系统操作手册', + helpAddr: 'https://docs.qq.com/doc/DQXZTV3lvcXpqdkt3', + docName: '易宝赞系统更新说明 2025-04-27', + docAddr: 'https://docs.qq.com/aio/DS2NCRFFseG9Ma3Ja?p=60db8i0gVHuMAuNx56deBp', + comItems: ${comStr}, +}`; + + fs.writeFile(`./${logDir}/.cfg.ts`, cfg, (err) => { + if (err) console.log("日志写入失败", err); + else console.log("日志写入成功"); + }); + + fs.writeFile( + `./${logDir}/public/ver.txt`, + `${Math.round(Date.now() / 1000).toString(16)}`, + (err) => { + if (err) console.log("版本写入失败", err); + else console.log("版本写入成功"); + } + ); +}); diff --git a/src/utils/useRequest.ts b/src/utils/useRequest.ts new file mode 100644 index 0000000..e4e6c24 --- /dev/null +++ b/src/utils/useRequest.ts @@ -0,0 +1,154 @@ +import { useState } from 'react'; +// import { dingRequest } from '@/services/common'; +import { dingRequest, toNumber } from './common'; +import { notificationEventBus } from './EventBus'; +import { post } from './http'; +import type { IAjaxDataBase } from './type'; + +type IOptions = { + // onSuccess?: (res: IAjaxDataBase, params: any, cancel: boolean) => void; + onSuccess?: (res: IAjaxDataBase, params: any) => void; + /** 错误码为 0 的时候执行 */ + onSuccessCodeZero?: (res: IAjaxDataBase, params: any) => void; + onCatch?: (error: any) => void; + // method?: 'POST' | 'GET'; + hideNotice?: boolean; +}; + +export const useRequest = (url: string, options?: IOptions) => { + // 请求返回的数据 + const [data, setData] = useState(null); + // 请求返回的错误信息 + const [error, setError] = useState(null); + // 请求的loading 状态 + const [loading, setLoading] = useState(false); + const [count, setCount] = useState(0); + + // const cancelRef = useRef(false); + // function cancelRequest() { + // cancelRef.current = true; + // } + + // loader 方法通过 fetch API 发出 http 请求 + const request = async (data?: any, config?: any) => { + // cancelRef.current = false; + setLoading(true); + try { + const res = await post(url, data, config); + + if (res?.err_code != 0) { + if (res.err_code == 110000) { + location.href = '#/login'; + } else { + if (options?.hideNotice != true) { + notificationEventBus.emit({ + title: `${'错误码'}:${res.err_code}`, + description: res.err_msg, + type: 'error', + }); + } + } + } + if (res?.err_code === 0) { + options?.onSuccessCodeZero?.(res, data); + } + options?.onSuccess?.(res, data); + setData(res); + setCount(toNumber(res?.count)); + setLoading(false); + return res; + } catch (error: any) { + setError(error); + setLoading(false); + // const traces = toArray(error?.response?.data?.traces).map((el) => { + // return { + // file: el?.file, + // line: el?.line, + // message: el?.message, + // }; + // }); + console.log(error); + notificationEventBus.emit({ title: `${'服务错误'}`, description: `${error?.message}`, type: 'error' }); + options?.onCatch?.(error); + + // const params = JSON.parse(JSON.stringify(data)); + // console.log(error?.response?.data?.traces); + const msg = `接口地址:${url}\n响应信息:${error?.message}\n错误信息:${JSON.stringify( + error?.response?.data || '', + ).replace(/"/g, '')}\n请求参数:${JSON.stringify(data || '').replace(/"/g, '')}`; + // console.log(msg); + dingRequest(msg || '错误'); + } + }; + // 将 loader, data, error, loading 作为自定义 hook 的返回值 cancelRequest + return { request, data, loading, error, count }; +}; + +type IConfig = { + hideNotice?: boolean; +}; + +/** + * 轻量级请求 + * @param url 请求地址 + * @param data 请求参数 + * @param config 请求配置项 + 提示组件 {} + * @returns Promise + * */ +export const requestLite = async (url: string, data?: any, config?: IConfig) => { + const { hideNotice = false, ...option } = config || {}; + try { + const res = await post(url, data, option); + if (res?.err_code != 0) { + if (res?.err_code == 110000) { + location.href = '#/login'; + } else { + if (!hideNotice) { + notificationEventBus.emit({ title: `${'错误码'}:${res.err_code}`, description: res.err_msg, type: 'error' }); + } + } + } + return res; + } catch (error: any) { + console.log(error); + if (!hideNotice) { + notificationEventBus.emit({ title: `${'服务错误'}`, description: `${error?.message}`, type: 'error' }); + } + const msg = `接口地址:${url}\n响应信息:${error?.message}\n错误信息:${JSON.stringify( + error?.response?.data || '', + ).replace(/"/g, '')}\n请求参数:${JSON.stringify(data || '').replace(/"/g, '')}`; + dingRequest(msg || '错误'); + } +}; + +/** + * 请求获取文件 + * @param url 文件地址 + * @param options 参数 + * @param options.oss 判断是不是 oss文件, 默认 true + * @returns Promise + */ +// export const requestFile = async ( +// url: string, +// options: { oss?: boolean } = { oss: true }, +// ) => { +// const u = url.startsWith("/") ? url.substring(1) : url; +// return new Promise((resolve, reject) => { +// try { +// fetch(options.oss ? `${OSSBaseUrl}${u}` : url, { mode: "cors" }) +// .then((response) => { +// if (!response.ok) { +// throw new Error(`HTTP 错误!状态:${response.status}`); +// } +// return response.blob(); +// }) +// .then((res) => { +// // const fileName = url.split('/').pop() || ''; +// // resolve(blobToFile([res], fileName)); +// resolve(res); +// }); +// } catch (error) { +// reject(error); +// } +// }); +// }; diff --git a/src/utils/useRequest2.ts b/src/utils/useRequest2.ts new file mode 100644 index 0000000..7601dae --- /dev/null +++ b/src/utils/useRequest2.ts @@ -0,0 +1,79 @@ +// import { OSSBaseUrl } from '@/config/config'; +import type { NotificationInstance } from 'antd/es/notification/interface'; +import { dingRequest } from './common'; +import { post } from './http'; + +type IConfig = { + notification?: NotificationInstance; +}; + +/** + * 轻量级请求 + * @param url 请求地址 + * @param data 请求参数 + * @param config 请求配置项 + 提示组件 {} + * @returns Promise + * */ +export const requestLite = async (url: string, data?: any, config?: IConfig) => { + const { notification, ...option } = config || {}; + try { + const res = await post(url, data, option); + if (res?.err_code != 0) { + if (res?.err_code == 110000) { + location.href = '#/login'; + } else { + if (notification) { + notification.error({ + title: `${'错误码'}:${res.err_code}`, + description: res.err_msg, + }); + } + } + } + return res; + } catch (error: any) { + console.log(error); + if (notification) { + notification.error({ + title: `${'服务错误'}`, + description: `${error?.message}, ${error?.response?.data?.message || ''}`, + }); + } + const msg = `接口地址:${url}\n响应信息:${error?.message}\n错误信息:${JSON.stringify( + error?.response?.data || '', + ).replace(/"/g, '')}\n请求参数:${JSON.stringify(data || '').replace(/"/g, '')}`; + dingRequest(msg || '错误'); + } +}; + +/** + * 请求获取文件 + * @param url 文件地址 + * @param options 参数 + * @param options.oss 判断是不是 oss文件, 默认 true + * @returns Promise + */ +// export const requestFile = async ( +// url: string, +// options: { oss?: boolean } = { oss: true }, +// ) => { +// const u = url.startsWith("/") ? url.substring(1) : url; +// return new Promise((resolve, reject) => { +// try { +// fetch(options.oss ? `${OSSBaseUrl}${u}` : url, { mode: "cors" }) +// .then((response) => { +// if (!response.ok) { +// throw new Error(`HTTP 错误!状态:${response.status}`); +// } +// return response.blob(); +// }) +// .then((res) => { +// // const fileName = url.split('/').pop() || ''; +// // resolve(blobToFile([res], fileName)); +// resolve(res); +// }); +// } catch (error) { +// reject(error); +// } +// }); +// }; diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..eeeb99f --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,23 @@ +/// + +declare interface Window { + dfConfig: { + isPhone: boolean; + /** 表格设置粘性头部 */ + tableStickyOffsetHeader: number; + /** 语言 */ + language: "zh-cn" | "en"; + /** 视口高度 */ + vhUnit: "vh" | "dvh"; + }; + showProcessGraphId?: number; + debug: { + add: (data: { [key: string]: any }) => void; + }; + dfERPConfig: { + /** 价格小数点保留位数 */ + PRICE_HOLD_POINT: number; + /** 数量小数点保留位数 */ + NUMS_HOLD_POINT: number; + }; +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..c3e704f --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8a67f62 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..6b3413b --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,37 @@ +import path from 'node:path'; +import react from '@vitejs/plugin-react-swc'; +// import { visualizer } from 'rollup-plugin-visualizer'; +import { defineConfig } from 'vite'; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react(), // 打包后生成体积分析报告(dist/stats.html) + // visualizer({ + // // open: true, // 自动打开报告页面 + // filename: 'stats.html', + // }), + ], + base: './', + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, + server: { + port: 4050, + host: '0.0.0.0', + proxy: { + '/api': { + target: 'http://192.168.1.138:93', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, ''), // 不可以省略rewrite + }, + '/static': { + target: 'http://192.168.1.138:83', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, ''), // 不可以省略rewrite + }, + }, + }, +});