From 5f108c732b4ce8afc8500b9f60abc73fca16a83e Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Mon, 16 Oct 2023 18:51:37 +0800 Subject: [PATCH 01/17] feat: license service Signed-off-by: jingyang <3161362058@qq.com> --- service/license/.env.template | 27 + service/license/.eslintrc.json | 3 + service/license/.gitignore | 35 + service/license/.prettierignore | 18 + service/license/.prettierrc.js | 20 + service/license/README.md | 40 + service/license/next-i18next.config.js | 11 + service/license/next.config.js | 13 + service/license/package.json | 54 + service/license/pnpm-lock.yaml | 5594 +++++++++++++++++ service/license/public/favicon.ico | Bin 0 -> 15086 bytes service/license/public/images/background.svg | 178 + service/license/public/images/empty.svg | 5 + .../license/public/images/sealos-title.png | Bin 0 -> 54072 bytes service/license/public/images/sealos.svg | 1 + service/license/public/locales/en/common.json | 94 + service/license/public/locales/zh/common.json | 88 + service/license/public/logo.svg | 1 + service/license/src/api/license.ts | 35 + service/license/src/api/system.ts | 10 + service/license/src/api/user.ts | 19 + .../src/components/LangSelect/index.tsx | 34 + .../src/components/icons/CancelIcon.tsx | 14 + .../src/components/icons/CloseIcon.tsx | 8 + .../license/src/components/icons/CopyLink.tsx | 7 + .../src/components/icons/DeleteIcon.tsx | 8 + .../components/icons/DownloadIcon copy 2.tsx | 14 + .../components/icons/DownloadIcon copy 3.tsx | 14 + .../components/icons/DownloadIcon copy 4.tsx | 14 + .../src/components/icons/DownloadIcon.tsx | 14 + .../src/components/icons/EmptyIcon.tsx | 29 + .../src/components/icons/ExchangeIcon.tsx | 21 + .../src/components/icons/GithubIcon.tsx | 19 + .../src/components/icons/GoogleIcon.tsx | 30 + .../license/src/components/icons/GroupAdd.tsx | 20 + .../license/src/components/icons/HomePage.tsx | 11 + .../license/src/components/icons/HtmlIcon.tsx | 7 + .../src/components/icons/LicenseIcon.tsx | 11 + .../license/src/components/icons/LockIcon.tsx | 8 + .../license/src/components/icons/MdIcon.tsx | 7 + .../src/components/icons/PersonIcon.tsx | 8 + .../src/components/icons/RightArrow.tsx | 16 + .../src/components/icons/SafetyIcon.tsx | 9 + .../license/src/components/icons/Share.tsx | 8 + .../src/components/icons/TokenIcon.tsx | 18 + .../src/components/icons/WarningIcon.tsx | 15 + .../src/components/icons/WechatIcon.tsx | 22 + service/license/src/components/icons/index.ts | 23 + .../components/signin/auth/useAuthList.tsx | 99 + .../components/signin/auth/useCustomError.tsx | 61 + .../components/signin/auth/useLanguage.tsx | 27 + .../components/signin/auth/usePassword.tsx | 236 + .../components/signin/auth/useProtocol.tsx | 70 + .../src/components/signin/auth/useSms.tsx | 201 + .../license/src/components/signin/index.tsx | 189 + service/license/src/hooks/useBonusBox.tsx | 65 + service/license/src/hooks/useCopyData.ts | 32 + service/license/src/hooks/useCustomToast.ts | 13 + service/license/src/hooks/useScreen.ts | 12 + service/license/src/pages/404.tsx | 13 + service/license/src/pages/_app.tsx | 32 + service/license/src/pages/_document.tsx | 13 + .../src/pages/api/auth/oauth/github/index.ts | 53 + .../src/pages/api/auth/oauth/google/index.ts | 63 + .../src/pages/api/auth/oauth/wechat/index.ts | 50 + .../src/pages/api/auth/password/exist.ts | 41 + .../src/pages/api/auth/password/index.ts | 40 + .../license/src/pages/api/auth/phone/sms.ts | 85 + .../src/pages/api/auth/phone/verify.ts | 38 + .../pages/api/license/createLicenseRecord.ts | 31 + .../src/pages/api/license/getLicenseRecord.ts | 29 + service/license/src/pages/api/license/pay.ts | 84 + .../license/src/pages/api/license/result.ts | 32 + .../license/src/pages/api/platform/getEnv.ts | 49 + service/license/src/pages/index.tsx | 23 + .../license/components/CurrencySymbol.tsx | 22 + .../pages/license/components/OuterLink.tsx | 35 + .../pages/license/components/Pagination.tsx | 118 + .../src/pages/license/components/Recharge.tsx | 248 + .../src/pages/license/components/Record.tsx | 104 + .../license/components/WechatPayment.tsx | 60 + service/license/src/pages/license/index.tsx | 61 + service/license/src/pages/signin.tsx | 18 + service/license/src/services/backend/auth.ts | 54 + .../src/services/backend/db/license.ts | 72 + .../src/services/backend/db/mongodb.ts | 24 + .../license/src/services/backend/db/user.ts | 128 + .../src/services/backend/db/verifyCode.ts | 61 + service/license/src/services/backend/oauth.ts | 193 + .../license/src/services/backend/response.ts | 30 + service/license/src/services/enable.ts | 32 + service/license/src/services/request.ts | 136 + service/license/src/stores/session.ts | 58 + service/license/src/styles/globals.css | 69 + service/license/src/styles/theme.ts | 52 + service/license/src/types/api.ts | 8 + service/license/src/types/index.ts | 12 + service/license/src/types/license.ts | 63 + service/license/src/types/login.ts | 5 + service/license/src/types/payment.ts | 58 + service/license/src/types/session.ts | 32 + service/license/src/types/system.ts | 29 + service/license/src/types/user.ts | 93 + service/license/src/types/valuation.ts | 18 + service/license/src/utils/cookieUtils.ts | 13 + service/license/src/utils/crypto.ts | 15 + service/license/src/utils/downloadFIle.ts | 14 + service/license/src/utils/format.ts | 54 + service/license/src/utils/tools.ts | 66 + service/license/tsconfig.json | 22 + 110 files changed, 10413 insertions(+) create mode 100644 service/license/.env.template create mode 100644 service/license/.eslintrc.json create mode 100644 service/license/.gitignore create mode 100644 service/license/.prettierignore create mode 100644 service/license/.prettierrc.js create mode 100644 service/license/README.md create mode 100644 service/license/next-i18next.config.js create mode 100644 service/license/next.config.js create mode 100644 service/license/package.json create mode 100644 service/license/pnpm-lock.yaml create mode 100644 service/license/public/favicon.ico create mode 100644 service/license/public/images/background.svg create mode 100644 service/license/public/images/empty.svg create mode 100644 service/license/public/images/sealos-title.png create mode 100644 service/license/public/images/sealos.svg create mode 100644 service/license/public/locales/en/common.json create mode 100644 service/license/public/locales/zh/common.json create mode 100644 service/license/public/logo.svg create mode 100644 service/license/src/api/license.ts create mode 100644 service/license/src/api/system.ts create mode 100644 service/license/src/api/user.ts create mode 100644 service/license/src/components/LangSelect/index.tsx create mode 100644 service/license/src/components/icons/CancelIcon.tsx create mode 100644 service/license/src/components/icons/CloseIcon.tsx create mode 100644 service/license/src/components/icons/CopyLink.tsx create mode 100644 service/license/src/components/icons/DeleteIcon.tsx create mode 100644 service/license/src/components/icons/DownloadIcon copy 2.tsx create mode 100644 service/license/src/components/icons/DownloadIcon copy 3.tsx create mode 100644 service/license/src/components/icons/DownloadIcon copy 4.tsx create mode 100644 service/license/src/components/icons/DownloadIcon.tsx create mode 100644 service/license/src/components/icons/EmptyIcon.tsx create mode 100644 service/license/src/components/icons/ExchangeIcon.tsx create mode 100644 service/license/src/components/icons/GithubIcon.tsx create mode 100644 service/license/src/components/icons/GoogleIcon.tsx create mode 100644 service/license/src/components/icons/GroupAdd.tsx create mode 100644 service/license/src/components/icons/HomePage.tsx create mode 100644 service/license/src/components/icons/HtmlIcon.tsx create mode 100644 service/license/src/components/icons/LicenseIcon.tsx create mode 100644 service/license/src/components/icons/LockIcon.tsx create mode 100644 service/license/src/components/icons/MdIcon.tsx create mode 100644 service/license/src/components/icons/PersonIcon.tsx create mode 100644 service/license/src/components/icons/RightArrow.tsx create mode 100644 service/license/src/components/icons/SafetyIcon.tsx create mode 100644 service/license/src/components/icons/Share.tsx create mode 100644 service/license/src/components/icons/TokenIcon.tsx create mode 100644 service/license/src/components/icons/WarningIcon.tsx create mode 100644 service/license/src/components/icons/WechatIcon.tsx create mode 100644 service/license/src/components/icons/index.ts create mode 100644 service/license/src/components/signin/auth/useAuthList.tsx create mode 100644 service/license/src/components/signin/auth/useCustomError.tsx create mode 100644 service/license/src/components/signin/auth/useLanguage.tsx create mode 100644 service/license/src/components/signin/auth/usePassword.tsx create mode 100644 service/license/src/components/signin/auth/useProtocol.tsx create mode 100644 service/license/src/components/signin/auth/useSms.tsx create mode 100644 service/license/src/components/signin/index.tsx create mode 100644 service/license/src/hooks/useBonusBox.tsx create mode 100644 service/license/src/hooks/useCopyData.ts create mode 100644 service/license/src/hooks/useCustomToast.ts create mode 100644 service/license/src/hooks/useScreen.ts create mode 100644 service/license/src/pages/404.tsx create mode 100644 service/license/src/pages/_app.tsx create mode 100644 service/license/src/pages/_document.tsx create mode 100644 service/license/src/pages/api/auth/oauth/github/index.ts create mode 100644 service/license/src/pages/api/auth/oauth/google/index.ts create mode 100644 service/license/src/pages/api/auth/oauth/wechat/index.ts create mode 100644 service/license/src/pages/api/auth/password/exist.ts create mode 100644 service/license/src/pages/api/auth/password/index.ts create mode 100644 service/license/src/pages/api/auth/phone/sms.ts create mode 100644 service/license/src/pages/api/auth/phone/verify.ts create mode 100644 service/license/src/pages/api/license/createLicenseRecord.ts create mode 100644 service/license/src/pages/api/license/getLicenseRecord.ts create mode 100644 service/license/src/pages/api/license/pay.ts create mode 100644 service/license/src/pages/api/license/result.ts create mode 100644 service/license/src/pages/api/platform/getEnv.ts create mode 100644 service/license/src/pages/index.tsx create mode 100644 service/license/src/pages/license/components/CurrencySymbol.tsx create mode 100644 service/license/src/pages/license/components/OuterLink.tsx create mode 100644 service/license/src/pages/license/components/Pagination.tsx create mode 100644 service/license/src/pages/license/components/Recharge.tsx create mode 100644 service/license/src/pages/license/components/Record.tsx create mode 100644 service/license/src/pages/license/components/WechatPayment.tsx create mode 100644 service/license/src/pages/license/index.tsx create mode 100644 service/license/src/pages/signin.tsx create mode 100644 service/license/src/services/backend/auth.ts create mode 100644 service/license/src/services/backend/db/license.ts create mode 100644 service/license/src/services/backend/db/mongodb.ts create mode 100644 service/license/src/services/backend/db/user.ts create mode 100644 service/license/src/services/backend/db/verifyCode.ts create mode 100644 service/license/src/services/backend/oauth.ts create mode 100644 service/license/src/services/backend/response.ts create mode 100644 service/license/src/services/enable.ts create mode 100644 service/license/src/services/request.ts create mode 100644 service/license/src/stores/session.ts create mode 100644 service/license/src/styles/globals.css create mode 100644 service/license/src/styles/theme.ts create mode 100644 service/license/src/types/api.ts create mode 100644 service/license/src/types/index.ts create mode 100644 service/license/src/types/license.ts create mode 100644 service/license/src/types/login.ts create mode 100644 service/license/src/types/payment.ts create mode 100644 service/license/src/types/session.ts create mode 100644 service/license/src/types/system.ts create mode 100644 service/license/src/types/user.ts create mode 100644 service/license/src/types/valuation.ts create mode 100644 service/license/src/utils/cookieUtils.ts create mode 100644 service/license/src/utils/crypto.ts create mode 100644 service/license/src/utils/downloadFIle.ts create mode 100644 service/license/src/utils/format.ts create mode 100644 service/license/src/utils/tools.ts create mode 100644 service/license/tsconfig.json diff --git a/service/license/.env.template b/service/license/.env.template new file mode 100644 index 00000000000..53db89856ce --- /dev/null +++ b/service/license/.env.template @@ -0,0 +1,27 @@ +PUBLIC_URL=. +NEXT_PUBLIC_SERVICE=/service/ +SEALOS_CLOUD_DOMAIN="cloud.sealos.io" + +# GITHUB_CLIENT_ID= +# GITHUB_CLIENT_SECRET= +# WECHAT_CLIENT_ID= +# WECHAT_CLIENT_SECRET= +# KUBECONFIG= +# MONGODB_URI= +# JWT_SECRET= +# ALI_ACCESS_KEY_ID= +# ALI_ACCESS_KEY_SECRET= +# ALI_TEMPLATE_CODE= +# ALI_SIGN_NAME= +# PRIVATE_PROTOCOL= +# SERVICE_PROTOCOL= +# CALLBACK_URL= +# PASSWORD_SALT= +# WECHAT_ENABLED= +# GITHUB_ENABLED= +# PASSWORD_ENABLED= +# SMS_ENABLED= + +# costcenter +STRIPE_ENABLED= +STRIPE_PUB= \ No newline at end of file diff --git a/service/license/.eslintrc.json b/service/license/.eslintrc.json new file mode 100644 index 00000000000..bffb357a712 --- /dev/null +++ b/service/license/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/service/license/.gitignore b/service/license/.gitignore new file mode 100644 index 00000000000..8f322f0d8f4 --- /dev/null +++ b/service/license/.gitignore @@ -0,0 +1,35 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/service/license/.prettierignore b/service/license/.prettierignore new file mode 100644 index 00000000000..ae2744a993c --- /dev/null +++ b/service/license/.prettierignore @@ -0,0 +1,18 @@ +*swp +*rpmnew +*swo +.idea +oss-config +ossutil64 +main.exe +dist +.vscode +scripts/release/Note.md +.ossutil_checkpoint +bin +.run +tools +coverage.out +tmp +**/.DS_Store +node_modules diff --git a/service/license/.prettierrc.js b/service/license/.prettierrc.js new file mode 100644 index 00000000000..8bc336a3674 --- /dev/null +++ b/service/license/.prettierrc.js @@ -0,0 +1,20 @@ +module.exports = { + printWidth: 100, + tabWidth: 2, + useTabs: false, + semi: true, + singleQuote: true, + quoteProps: 'as-needed', + jsxSingleQuote: false, + trailingComma: 'none', + bracketSpacing: true, + jsxBracketSameLine: false, + arrowParens: 'always', + rangeStart: 0, + rangeEnd: Infinity, + requirePragma: false, + insertPragma: false, + proseWrap: 'preserve', + htmlWhitespaceSensitivity: 'css', + endOfLine: 'lf' +}; diff --git a/service/license/README.md b/service/license/README.md new file mode 100644 index 00000000000..a75ac524881 --- /dev/null +++ b/service/license/README.md @@ -0,0 +1,40 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/service/license/next-i18next.config.js b/service/license/next-i18next.config.js new file mode 100644 index 00000000000..14df1ec905a --- /dev/null +++ b/service/license/next-i18next.config.js @@ -0,0 +1,11 @@ +/** + * @type {import('next-i18next').UserConfig} + */ + +module.exports = { + i18n: { + defaultLocale: 'en', + locales: ['en', 'zh'], + localeDetection: false + } +} diff --git a/service/license/next.config.js b/service/license/next.config.js new file mode 100644 index 00000000000..d3a20495ae0 --- /dev/null +++ b/service/license/next.config.js @@ -0,0 +1,13 @@ +const { i18n } = require('./next-i18next.config') +const isProduction = process.env.NODE_ENV === 'production' + + +/** @type {import('next').NextConfig} */ +const nextConfig = { + i18n, + reactStrictMode: false, + swcMinify: isProduction, + output: 'standalone', +} + +module.exports = nextConfig diff --git a/service/license/package.json b/service/license/package.json new file mode 100644 index 00000000000..3cb73cf852d --- /dev/null +++ b/service/license/package.json @@ -0,0 +1,54 @@ +{ + "name": "license", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "@alicloud/dysmsapi20170525": "^2.0.24", + "@alicloud/openapi-client": "^0.4.6", + "@alicloud/tea-util": "^1.4.7", + "@chakra-ui/react": "^2.8.1", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", + "@tanstack/react-query": "^4.36.1", + "axios": "^1.5.1", + "clsx": "^2.0.0", + "dayjs": "^1.11.10", + "framer-motion": "^10.16.4", + "i18next": "^23.5.1", + "immer": "^10.0.3", + "js-cookie": "^3.0.5", + "jsonwebtoken": "^9.0.2", + "lodash": "^4.17.21", + "mongodb": "^6.1.0", + "next": "13.5.4", + "next-i18next": "^14.0.3", + "nprogress": "^0.2.0", + "qrcode.react": "^3.1.0", + "react": "^18", + "react-dom": "^18", + "react-hook-form": "^7.47.0", + "react-i18next": "^13.3.0", + "uuid": "^9.0.1", + "zustand": "^4.4.3" + }, + "devDependencies": { + "@types/js-cookie": "^3.0.4", + "@types/jsonwebtoken": "^9.0.3", + "@types/lodash": "^4.14.199", + "@types/node": "^20", + "@types/nprogress": "^0.2.1", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/uuid": "^9.0.5", + "eslint": "^8", + "eslint-config-next": "13.5.4", + "prettier": "^3.0.3", + "typescript": "^5" + } +} \ No newline at end of file diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml new file mode 100644 index 00000000000..c0b8a6b03b9 --- /dev/null +++ b/service/license/pnpm-lock.yaml @@ -0,0 +1,5594 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@alicloud/dysmsapi20170525': + specifier: ^2.0.24 + version: registry.npmmirror.com/@alicloud/dysmsapi20170525@2.0.24 + '@alicloud/openapi-client': + specifier: ^0.4.6 + version: registry.npmmirror.com/@alicloud/openapi-client@0.4.6 + '@alicloud/tea-util': + specifier: ^1.4.7 + version: registry.npmmirror.com/@alicloud/tea-util@1.4.7 + '@chakra-ui/react': + specifier: ^2.8.1 + version: registry.npmmirror.com/@chakra-ui/react@2.8.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.0.0)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0) + '@emotion/react': + specifier: ^11.11.1 + version: registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0) + '@emotion/styled': + specifier: ^11.11.0 + version: registry.npmmirror.com/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.0.0)(react@18.0.0) + '@tanstack/react-query': + specifier: ^4.36.1 + version: registry.npmmirror.com/@tanstack/react-query@4.36.1(react-dom@18.0.0)(react@18.0.0) + axios: + specifier: ^1.5.1 + version: registry.npmmirror.com/axios@1.5.1 + clsx: + specifier: ^2.0.0 + version: registry.npmmirror.com/clsx@2.0.0 + dayjs: + specifier: ^1.11.10 + version: registry.npmmirror.com/dayjs@1.11.10 + framer-motion: + specifier: ^10.16.4 + version: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + i18next: + specifier: ^23.5.1 + version: registry.npmmirror.com/i18next@23.5.1 + immer: + specifier: ^10.0.3 + version: registry.npmmirror.com/immer@10.0.3 + js-cookie: + specifier: ^3.0.5 + version: registry.npmmirror.com/js-cookie@3.0.5 + jsonwebtoken: + specifier: ^9.0.2 + version: registry.npmmirror.com/jsonwebtoken@9.0.2 + lodash: + specifier: ^4.17.21 + version: registry.npmmirror.com/lodash@4.17.21 + mongodb: + specifier: ^6.1.0 + version: registry.npmmirror.com/mongodb@6.1.0 + next: + specifier: 13.5.4 + version: registry.npmmirror.com/next@13.5.4(react-dom@18.0.0)(react@18.0.0) + next-i18next: + specifier: ^14.0.3 + version: registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.4)(react-i18next@13.3.0)(react@18.0.0) + nprogress: + specifier: ^0.2.0 + version: registry.npmmirror.com/nprogress@0.2.0 + qrcode.react: + specifier: ^3.1.0 + version: registry.npmmirror.com/qrcode.react@3.1.0(react@18.0.0) + react: + specifier: ^18 + version: registry.npmmirror.com/react@18.0.0 + react-dom: + specifier: ^18 + version: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + react-hook-form: + specifier: ^7.47.0 + version: registry.npmmirror.com/react-hook-form@7.47.0(react@18.0.0) + react-i18next: + specifier: ^13.3.0 + version: registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0) + uuid: + specifier: ^9.0.1 + version: registry.npmmirror.com/uuid@9.0.1 + zustand: + specifier: ^4.4.3 + version: registry.npmmirror.com/zustand@4.4.3(@types/react@18.0.0)(immer@10.0.3)(react@18.0.0) + +devDependencies: + '@types/js-cookie': + specifier: ^3.0.4 + version: registry.npmmirror.com/@types/js-cookie@3.0.4 + '@types/jsonwebtoken': + specifier: ^9.0.3 + version: registry.npmmirror.com/@types/jsonwebtoken@9.0.3 + '@types/lodash': + specifier: ^4.14.199 + version: registry.npmmirror.com/@types/lodash@4.14.199 + '@types/node': + specifier: ^20 + version: registry.npmmirror.com/@types/node@20.0.0 + '@types/nprogress': + specifier: ^0.2.1 + version: registry.npmmirror.com/@types/nprogress@0.2.1 + '@types/react': + specifier: ^18 + version: registry.npmmirror.com/@types/react@18.0.0 + '@types/react-dom': + specifier: ^18 + version: registry.npmmirror.com/@types/react-dom@18.0.0 + '@types/uuid': + specifier: ^9.0.5 + version: registry.npmmirror.com/@types/uuid@9.0.5 + eslint: + specifier: ^8 + version: registry.npmmirror.com/eslint@8.0.0 + eslint-config-next: + specifier: 13.5.4 + version: registry.npmmirror.com/eslint-config-next@13.5.4(eslint@8.0.0)(typescript@5.0.2) + prettier: + specifier: ^3.0.3 + version: registry.npmmirror.com/prettier@3.0.3 + typescript: + specifier: ^5 + version: registry.npmmirror.com/typescript@5.0.2 + +packages: + + registry.npmmirror.com/@aashutoshrathi/word-wrap@1.2.6: + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz} + name: '@aashutoshrathi/word-wrap' + version: 1.2.6 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/@alicloud/credentials@2.3.0: + resolution: {integrity: sha512-x0vf/m1BzkqYXAj2Hkd22O35josx5P4VCzq/9EvTBjA7aGLX/P6JDz7QVp+gnhLjPJyvwAbErvJRYq4gIo4IMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/credentials/-/credentials-2.3.0.tgz} + name: '@alicloud/credentials' + version: 2.3.0 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + httpx: registry.npmmirror.com/httpx@2.3.0 + ini: registry.npmmirror.com/ini@1.3.8 + kitx: registry.npmmirror.com/kitx@2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/dysmsapi20170525@2.0.24: + resolution: {integrity: sha512-RtOwh3L+NbpfnOxySViIKLlNQeT9pZJS496ZTMMz7A29CBrlComC1UDLmwmD5odWF2Okv9ZdsyP3IRiQnoEL+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/dysmsapi20170525/-/dysmsapi20170525-2.0.24.tgz} + name: '@alicloud/dysmsapi20170525' + version: 2.0.24 + dependencies: + '@alicloud/endpoint-util': registry.npmmirror.com/@alicloud/endpoint-util@0.0.1 + '@alicloud/openapi-client': registry.npmmirror.com/@alicloud/openapi-client@0.4.6 + '@alicloud/openapi-util': registry.npmmirror.com/@alicloud/openapi-util@0.3.2 + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util@1.4.7 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/endpoint-util@0.0.1: + resolution: {integrity: sha512-+pH7/KEXup84cHzIL6UJAaPqETvln4yXlD9JzlrqioyCSaWxbug5FUobsiI6fuUOpw5WwoB3fWAtGbFnJ1K3Yg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/endpoint-util/-/endpoint-util-0.0.1.tgz} + name: '@alicloud/endpoint-util' + version: 0.0.1 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + kitx: registry.npmmirror.com/kitx@2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/gateway-spi@0.0.8: + resolution: {integrity: sha512-KM7fu5asjxZPmrz9sJGHJeSU+cNQNOxW+SFmgmAIrITui5hXL2LB+KNRuzWmlwPjnuA2X3/keq9h6++S9jcV5g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/gateway-spi/-/gateway-spi-0.0.8.tgz} + name: '@alicloud/gateway-spi' + version: 0.0.8 + dependencies: + '@alicloud/credentials': registry.npmmirror.com/@alicloud/credentials@2.3.0 + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/openapi-client@0.4.6: + resolution: {integrity: sha512-cyhUQOJehLRslHy2l+lsginiyXdzfV7yF7b9EJcxzGG7zHAEX0XF3OJvfo13n7WgiqCzt9suQBatJz7b5F+14A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/openapi-client/-/openapi-client-0.4.6.tgz} + name: '@alicloud/openapi-client' + version: 0.4.6 + dependencies: + '@alicloud/credentials': registry.npmmirror.com/@alicloud/credentials@2.3.0 + '@alicloud/gateway-spi': registry.npmmirror.com/@alicloud/gateway-spi@0.0.8 + '@alicloud/openapi-util': registry.npmmirror.com/@alicloud/openapi-util@0.3.2 + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util@1.4.7 + '@alicloud/tea-xml': registry.npmmirror.com/@alicloud/tea-xml@0.0.2 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/openapi-util@0.3.2: + resolution: {integrity: sha512-EC2JvxdcOgMlBAEG0+joOh2IB1um8CPz9EdYuRfTfd1uP8Yc9D8QRUWVGjP6scnj6fWSOaHFlit9H6PrJSyFow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/openapi-util/-/openapi-util-0.3.2.tgz} + name: '@alicloud/openapi-util' + version: 0.3.2 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + '@alicloud/tea-util': registry.npmmirror.com/@alicloud/tea-util@1.4.7 + kitx: registry.npmmirror.com/kitx@2.1.0 + sm3: registry.npmmirror.com/sm3@1.0.3 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/tea-typescript@1.8.0: + resolution: {integrity: sha512-CWXWaquauJf0sW30mgJRVu9aaXyBth5uMBCUc+5vKTK1zlgf3hIqRUjJZbjlwHwQ5y9anwcu18r48nOZb7l2QQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/tea-typescript/-/tea-typescript-1.8.0.tgz} + name: '@alicloud/tea-typescript' + version: 1.8.0 + dependencies: + '@types/node': registry.npmmirror.com/@types/node@12.20.55 + httpx: registry.npmmirror.com/httpx@2.3.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/tea-util@1.4.7: + resolution: {integrity: sha512-Lrpfk9kxihHsit3oMoeIMjk783AxjOvzMhLAbZcIzazKiVg3Zk/209XDe9r1lXqxII59j3V4rhC9X14y6WGYyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/tea-util/-/tea-util-1.4.7.tgz} + name: '@alicloud/tea-util' + version: 1.4.7 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + kitx: registry.npmmirror.com/kitx@2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@alicloud/tea-xml@0.0.2: + resolution: {integrity: sha512-Xs7v5y7YSNSDDYmiDWAC0/013VWPjS3dQU4KezSLva9VGiTVPaL3S7Nk4NrTmAYCG6MKcrRj/nGEDIWL5KRoPg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@alicloud/tea-xml/-/tea-xml-0.0.2.tgz} + name: '@alicloud/tea-xml' + version: 0.0.2 + dependencies: + '@alicloud/tea-typescript': registry.npmmirror.com/@alicloud/tea-typescript@1.8.0 + '@types/xml2js': registry.npmmirror.com/@types/xml2js@0.4.12 + xml2js: registry.npmmirror.com/xml2js@0.4.23 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/@babel/code-frame@7.22.13: + resolution: {integrity: sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.22.13.tgz} + name: '@babel/code-frame' + version: 7.22.13 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': registry.npmmirror.com/@babel/highlight@7.22.20 + chalk: registry.npmmirror.com/chalk@2.4.2 + dev: false + + registry.npmmirror.com/@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz} + name: '@babel/helper-module-imports' + version: 7.22.15 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': registry.npmmirror.com/@babel/types@7.23.0 + dev: false + + registry.npmmirror.com/@babel/helper-string-parser@7.22.5: + resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz} + name: '@babel/helper-string-parser' + version: 7.22.5 + engines: {node: '>=6.9.0'} + dev: false + + registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20: + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz} + name: '@babel/helper-validator-identifier' + version: 7.22.20 + engines: {node: '>=6.9.0'} + dev: false + + registry.npmmirror.com/@babel/highlight@7.22.20: + resolution: {integrity: sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/highlight/-/highlight-7.22.20.tgz} + name: '@babel/highlight' + version: 7.22.20 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20 + chalk: registry.npmmirror.com/chalk@2.4.2 + js-tokens: registry.npmmirror.com/js-tokens@4.0.0 + dev: false + + registry.npmmirror.com/@babel/runtime@7.23.2: + resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.2.tgz} + name: '@babel/runtime' + version: 7.23.2 + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: registry.npmmirror.com/regenerator-runtime@0.14.0 + + registry.npmmirror.com/@babel/types@7.23.0: + resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/types/-/types-7.23.0.tgz} + name: '@babel/types' + version: 7.23.0 + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': registry.npmmirror.com/@babel/helper-string-parser@7.22.5 + '@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20 + to-fast-properties: registry.npmmirror.com/to-fast-properties@2.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/accordion@2.3.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0): + resolution: {integrity: sha512-FSXRm8iClFyU+gVaXisOSEw0/4Q+qZbFRiuhIAkVU6Boj0FxAMrlo9a8AV5TuF77rgaHytCdHk0Ng+cyUijrag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/accordion/-/accordion-2.3.1.tgz} + id: registry.npmmirror.com/@chakra-ui/accordion/2.3.1 + name: '@chakra-ui/accordion' + version: 2.3.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + dependencies: + '@chakra-ui/descendant': registry.npmmirror.com/@chakra-ui/descendant@3.1.0(react@18.0.0) + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/transition': registry.npmmirror.com/@chakra-ui/transition@2.1.0(framer-motion@10.16.4)(react@18.0.0) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/alert@2.2.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-GduIqqWCkvID8hxRlKw29Jp3w93r/E9S30J2F8By3ODon9Bhk1o/KVolcPiSiQvRwKNBJCd/rBTpPpLkB+s7pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/alert/-/alert-2.2.1.tgz} + id: registry.npmmirror.com/@chakra-ui/alert/2.2.1 + name: '@chakra-ui/alert' + version: 2.2.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/spinner': registry.npmmirror.com/@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/anatomy@2.2.1: + resolution: {integrity: sha512-bbmyWTGwQo+aHYDMtLIj7k7hcWvwE7GFVDViLFArrrPhfUTDdQTNqhiDp1N7eh2HLyjNhc2MKXV8s2KTQqkmTg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/anatomy/-/anatomy-2.2.1.tgz} + name: '@chakra-ui/anatomy' + version: 2.2.1 + dev: false + + registry.npmmirror.com/@chakra-ui/avatar@2.3.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-8gKSyLfygnaotbJbDMHDiJoF38OHXUYVme4gGxZ1fLnQEdPVEaIWfH+NndIjOM0z8S+YEFnT9KyGMUtvPrBk3g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/avatar/-/avatar-2.3.0.tgz} + id: registry.npmmirror.com/@chakra-ui/avatar/2.3.0 + name: '@chakra-ui/avatar' + version: 2.3.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/image': registry.npmmirror.com/@chakra-ui/image@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/breadcrumb@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-4cWCG24flYBxjruRi4RJREWTGF74L/KzI2CognAW/d/zWR0CjiScuJhf37Am3LFbCySP6WSoyBOtTIoTA4yLEA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/breadcrumb/-/breadcrumb-2.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/breadcrumb/2.2.0 + name: '@chakra-ui/breadcrumb' + version: 2.2.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/breakpoint-utils@2.0.8: + resolution: {integrity: sha512-Pq32MlEX9fwb5j5xx8s18zJMARNHlQZH2VH1RZgfgRDpp7DcEgtRW5AInfN5CfqdHLO1dGxA7I3MqEuL5JnIsA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/breakpoint-utils/-/breakpoint-utils-2.0.8.tgz} + name: '@chakra-ui/breakpoint-utils' + version: 2.0.8 + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + dev: false + + registry.npmmirror.com/@chakra-ui/button@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-95CplwlRKmmUXkdEp/21VkEWgnwcx2TOBG6NfYlsuLBDHSLlo5FKIiE2oSi4zXc4TLcopGcWPNcm/NDaSC5pvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/button/-/button-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/button/2.1.0 + name: '@chakra-ui/button' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/spinner': registry.npmmirror.com/@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/card@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-xUB/k5MURj4CtPAhdSoXZidUbm8j3hci9vnc+eZJVDqhDOShNlD6QeniQNRPRys4lWAQLCbFcrwL29C8naDi6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/card/-/card-2.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/card/2.2.0 + name: '@chakra-ui/card' + version: 2.2.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/checkbox@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-e6qL9ntVI/Ui6g0+iljUV2chX86YMsXafldpTHBNYDEoNLjGo1lqLFzq3y6zs3iuB3DHI0X7eAG3REmMVs0A0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/checkbox/-/checkbox-2.3.1.tgz} + id: registry.npmmirror.com/@chakra-ui/checkbox/2.3.1 + name: '@chakra-ui/checkbox' + version: 2.3.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/visually-hidden': registry.npmmirror.com/@chakra-ui/visually-hidden@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@zag-js/focus-visible': registry.npmmirror.com/@zag-js/focus-visible@0.16.0 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/clickable@2.1.0(react@18.0.0): + resolution: {integrity: sha512-flRA/ClPUGPYabu+/GLREZVZr9j2uyyazCAUHAdrTUEdDYCr31SVGhgh7dgKdtq23bOvAQJpIJjw/0Bs0WvbXw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/clickable/-/clickable-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/clickable/2.1.0 + name: '@chakra-ui/clickable' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/close-button@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-gnpENKOanKexswSVpVz7ojZEALl2x5qjLYNqSQGbxz+aP9sOXPfUS56ebyBrre7T7exuWGiFeRwnM0oVeGPaiw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/close-button/-/close-button-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/close-button/2.1.1 + name: '@chakra-ui/close-button' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/color-mode@2.2.0(react@18.0.0): + resolution: {integrity: sha512-niTEA8PALtMWRI9wJ4LL0CSBDo8NBfLNp4GD6/0hstcm3IlbBHTVKxN6HwSaoNYfphDQLxCjT4yG+0BJA5tFpg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/color-mode/-/color-mode-2.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/color-mode/2.2.0 + name: '@chakra-ui/color-mode' + version: 2.2.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/control-box@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-gVrRDyXFdMd8E7rulL0SKeoljkLQiPITFnsyMO8EFHNZ+AHt5wK4LIguYVEq88APqAGZGfHFWXr79RYrNiE3Mg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/control-box/-/control-box-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/control-box/2.1.0 + name: '@chakra-ui/control-box' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/counter@2.1.0(react@18.0.0): + resolution: {integrity: sha512-s6hZAEcWT5zzjNz2JIWUBzRubo9la/oof1W7EKZVVfPYHERnl5e16FmBC79Yfq8p09LQ+aqFKm/etYoJMMgghw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/counter/-/counter-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/counter/2.1.0 + name: '@chakra-ui/counter' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/number-utils': registry.npmmirror.com/@chakra-ui/number-utils@2.0.7 + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/css-reset@2.3.0(@emotion/react@11.11.1)(react@18.0.0): + resolution: {integrity: sha512-cQwwBy5O0jzvl0K7PLTLgp8ijqLPKyuEMiDXwYzl95seD3AoeuoCLyzZcJtVqaUZ573PiBdAbY/IlZcwDOItWg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/css-reset/-/css-reset-2.3.0.tgz} + id: registry.npmmirror.com/@chakra-ui/css-reset/2.3.0 + name: '@chakra-ui/css-reset' + version: 2.3.0 + peerDependencies: + '@emotion/react': '>=10.0.35' + react: '>=18' + dependencies: + '@emotion/react': registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/descendant@3.1.0(react@18.0.0): + resolution: {integrity: sha512-VxCIAir08g5w27klLyi7PVo8BxhW4tgU/lxQyujkmi4zx7hT9ZdrcQLAted/dAa+aSIZ14S1oV0Q9lGjsAdxUQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/descendant/-/descendant-3.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/descendant/3.1.0 + name: '@chakra-ui/descendant' + version: 3.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/dom-utils@2.1.0: + resolution: {integrity: sha512-ZmF2qRa1QZ0CMLU8M1zCfmw29DmPNtfjR9iTo74U5FPr3i1aoAh7fbJ4qAlZ197Xw9eAW28tvzQuoVWeL5C7fQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/dom-utils/-/dom-utils-2.1.0.tgz} + name: '@chakra-ui/dom-utils' + version: 2.1.0 + dev: false + + registry.npmmirror.com/@chakra-ui/editable@3.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-j2JLrUL9wgg4YA6jLlbU88370eCRyor7DZQD9lzpY95tSOXpTljeg3uF9eOmDnCs6fxp3zDWIfkgMm/ExhcGTg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/editable/-/editable-3.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/editable/3.1.0 + name: '@chakra-ui/editable' + version: 3.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-focus-on-pointer-down': registry.npmmirror.com/@chakra-ui/react-use-focus-on-pointer-down@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/event-utils@2.0.8: + resolution: {integrity: sha512-IGM/yGUHS+8TOQrZGpAKOJl/xGBrmRYJrmbHfUE7zrG3PpQyXvbLDP1M+RggkCFVgHlJi2wpYIf0QtQlU0XZfw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/event-utils/-/event-utils-2.0.8.tgz} + name: '@chakra-ui/event-utils' + version: 2.0.8 + dev: false + + registry.npmmirror.com/@chakra-ui/focus-lock@2.1.0(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-EmGx4PhWGjm4dpjRqM4Aa+rCWBxP+Rq8Uc/nAVnD4YVqkEhBkrPTpui2lnjsuxqNaZ24fIAZ10cF1hlpemte/w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/focus-lock/-/focus-lock-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/focus-lock/2.1.0 + name: '@chakra-ui/focus-lock' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/dom-utils': registry.npmmirror.com/@chakra-ui/dom-utils@2.1.0 + react: registry.npmmirror.com/react@18.0.0 + react-focus-lock: registry.npmmirror.com/react-focus-lock@2.9.6(@types/react@18.0.0)(react@18.0.0) + transitivePeerDependencies: + - '@types/react' + dev: false + + registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-LJPDzA1ITc3lhd/iDiINqGeca5bJD09PZAjePGEmmZyLPZZi8nPh/iii0RMxvKyJArsTBwXymCh+dEqK9aDzGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/form-control/-/form-control-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/form-control/2.1.1 + name: '@chakra-ui/form-control' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/hooks@2.2.1(react@18.0.0): + resolution: {integrity: sha512-RQbTnzl6b1tBjbDPf9zGRo9rf/pQMholsOudTxjy4i9GfTfz6kgp5ValGjQm2z7ng6Z31N1cnjZ1AlSzQ//ZfQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/hooks/-/hooks-2.2.1.tgz} + id: registry.npmmirror.com/@chakra-ui/hooks/2.2.1 + name: '@chakra-ui/hooks' + version: 2.2.1 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-utils': registry.npmmirror.com/@chakra-ui/react-utils@2.0.12(react@18.0.0) + '@chakra-ui/utils': registry.npmmirror.com/@chakra-ui/utils@2.0.15 + compute-scroll-into-view: registry.npmmirror.com/compute-scroll-into-view@3.0.3 + copy-to-clipboard: registry.npmmirror.com/copy-to-clipboard@3.3.3 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-xxjGLvlX2Ys4H0iHrI16t74rG9EBcpFvJ3Y3B7KMQTrnW34Kf7Da/UC8J67Gtx85mTHW020ml85SVPKORWNNKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/icon/-/icon-3.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/icon/3.2.0 + name: '@chakra-ui/icon' + version: 3.2.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/image@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-bskumBYKLiLMySIWDGcz0+D9Th0jPvmX6xnRMs4o92tT3Od/bW26lahmV2a2Op2ItXeCmRMY+XxJH5Gy1i46VA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/image/-/image-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/image/2.1.0 + name: '@chakra-ui/image' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/input@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-RQYzQ/qcak3eCuCfvSqc1kEFx0sCcnIeiSi7i0r70CeBnAUK/CP1/4Uz849FpKz81K4z2SikC9MkHPQd8ZpOwg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/input/-/input-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/input/2.1.1 + name: '@chakra-ui/input' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/object-utils': registry.npmmirror.com/@chakra-ui/object-utils@2.1.0 + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-nXuZ6WRbq0WdgnRgLw+QuxWAHuhDtVX8ElWqcTK+cSMFg/52eVP47czYBE5F35YhnoW2XBwfNoNgZ7+e8Z01Rg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/layout/-/layout-2.3.1.tgz} + id: registry.npmmirror.com/@chakra-ui/layout/2.3.1 + name: '@chakra-ui/layout' + version: 2.3.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/breakpoint-utils': registry.npmmirror.com/@chakra-ui/breakpoint-utils@2.0.8 + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/object-utils': registry.npmmirror.com/@chakra-ui/object-utils@2.1.0 + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/lazy-utils@2.0.5: + resolution: {integrity: sha512-UULqw7FBvcckQk2n3iPO56TMJvDsNv0FKZI6PlUNJVaGsPbsYxK/8IQ60vZgaTVPtVcjY6BE+y6zg8u9HOqpyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/lazy-utils/-/lazy-utils-2.0.5.tgz} + name: '@chakra-ui/lazy-utils' + version: 2.0.5 + dev: false + + registry.npmmirror.com/@chakra-ui/live-region@2.1.0(react@18.0.0): + resolution: {integrity: sha512-ZOxFXwtaLIsXjqnszYYrVuswBhnIHHP+XIgK1vC6DePKtyK590Wg+0J0slDwThUAd4MSSIUa/nNX84x1GMphWw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/live-region/-/live-region-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/live-region/2.1.0 + name: '@chakra-ui/live-region' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-IsTGgFLoICVoPRp9ykOgqmdMotJG0CnPsKvGQeSFOB/dZfIujdVb14TYxDU4+MURXry1MhJ7LzZhv+Ml7cr8/g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/media-query/-/media-query-3.3.0.tgz} + id: registry.npmmirror.com/@chakra-ui/media-query/3.3.0 + name: '@chakra-ui/media-query' + version: 3.3.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/breakpoint-utils': registry.npmmirror.com/@chakra-ui/breakpoint-utils@2.0.8 + '@chakra-ui/react-env': registry.npmmirror.com/@chakra-ui/react-env@3.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0): + resolution: {integrity: sha512-lJS7XEObzJxsOwWQh7yfG4H8FzFPRP5hVPN/CL+JzytEINCSBvsCDHrYPQGp7jzpCi8vnTqQQGQe0f8dwnXd2g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/menu/-/menu-2.2.1.tgz} + id: registry.npmmirror.com/@chakra-ui/menu/2.2.1 + name: '@chakra-ui/menu' + version: 2.2.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + dependencies: + '@chakra-ui/clickable': registry.npmmirror.com/@chakra-ui/clickable@2.1.0(react@18.0.0) + '@chakra-ui/descendant': registry.npmmirror.com/@chakra-ui/descendant@3.1.0(react@18.0.0) + '@chakra-ui/lazy-utils': registry.npmmirror.com/@chakra-ui/lazy-utils@2.0.5 + '@chakra-ui/popper': registry.npmmirror.com/@chakra-ui/popper@3.1.0(react@18.0.0) + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-animation-state': registry.npmmirror.com/@chakra-ui/react-use-animation-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-disclosure': registry.npmmirror.com/@chakra-ui/react-use-disclosure@2.1.0(react@18.0.0) + '@chakra-ui/react-use-focus-effect': registry.npmmirror.com/@chakra-ui/react-use-focus-effect@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/react-use-outside-click': registry.npmmirror.com/@chakra-ui/react-use-outside-click@2.2.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/transition': registry.npmmirror.com/@chakra-ui/transition@2.1.0(framer-motion@10.16.4)(react@18.0.0) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/modal@2.3.1(@chakra-ui/system@2.6.1)(@types/react@18.0.0)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-TQv1ZaiJMZN+rR9DK0snx/OPwmtaGH1HbZtlYt4W4s6CzyK541fxLRTjIXfEzIGpvNW+b6VFuFjbcR78p4DEoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/modal/-/modal-2.3.1.tgz} + id: registry.npmmirror.com/@chakra-ui/modal/2.3.1 + name: '@chakra-ui/modal' + version: 2.3.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/close-button': registry.npmmirror.com/@chakra-ui/close-button@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/focus-lock': registry.npmmirror.com/@chakra-ui/focus-lock@2.1.0(@types/react@18.0.0)(react@18.0.0) + '@chakra-ui/portal': registry.npmmirror.com/@chakra-ui/portal@2.1.0(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/transition': registry.npmmirror.com/@chakra-ui/transition@2.1.0(framer-motion@10.16.4)(react@18.0.0) + aria-hidden: registry.npmmirror.com/aria-hidden@1.2.3 + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + react-remove-scroll: registry.npmmirror.com/react-remove-scroll@2.5.7(@types/react@18.0.0)(react@18.0.0) + transitivePeerDependencies: + - '@types/react' + dev: false + + registry.npmmirror.com/@chakra-ui/number-input@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-B4xwUPyr0NmjGN/dBhOmCD2xjX6OY1pr9GmGH3GQRozMsLAClD3TibwiZetwlyCp02qQqiFwEcZmUxaX88794Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/number-input/-/number-input-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/number-input/2.1.1 + name: '@chakra-ui/number-input' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/counter': registry.npmmirror.com/@chakra-ui/counter@2.1.0(react@18.0.0) + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + '@chakra-ui/react-use-event-listener': registry.npmmirror.com/@chakra-ui/react-use-event-listener@2.1.0(react@18.0.0) + '@chakra-ui/react-use-interval': registry.npmmirror.com/@chakra-ui/react-use-interval@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/number-utils@2.0.7: + resolution: {integrity: sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/number-utils/-/number-utils-2.0.7.tgz} + name: '@chakra-ui/number-utils' + version: 2.0.7 + dev: false + + registry.npmmirror.com/@chakra-ui/object-utils@2.1.0: + resolution: {integrity: sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/object-utils/-/object-utils-2.1.0.tgz} + name: '@chakra-ui/object-utils' + version: 2.1.0 + dev: false + + registry.npmmirror.com/@chakra-ui/pin-input@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-x4vBqLStDxJFMt+jdAHHS8jbh294O53CPQJoL4g228P513rHylV/uPscYUHrVJXRxsHfRztQO9k45jjTYaPRMw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/pin-input/-/pin-input-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/pin-input/2.1.0 + name: '@chakra-ui/pin-input' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/descendant': registry.npmmirror.com/@chakra-ui/descendant@3.1.0(react@18.0.0) + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/popover@2.2.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0): + resolution: {integrity: sha512-K+2ai2dD0ljvJnlrzesCDT9mNzLifE3noGKZ3QwLqd/K34Ym1W/0aL1ERSynrcG78NKoXS54SdEzkhCZ4Gn/Zg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/popover/-/popover-2.2.1.tgz} + id: registry.npmmirror.com/@chakra-ui/popover/2.2.1 + name: '@chakra-ui/popover' + version: 2.2.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + dependencies: + '@chakra-ui/close-button': registry.npmmirror.com/@chakra-ui/close-button@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/lazy-utils': registry.npmmirror.com/@chakra-ui/lazy-utils@2.0.5 + '@chakra-ui/popper': registry.npmmirror.com/@chakra-ui/popper@3.1.0(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-animation-state': registry.npmmirror.com/@chakra-ui/react-use-animation-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-disclosure': registry.npmmirror.com/@chakra-ui/react-use-disclosure@2.1.0(react@18.0.0) + '@chakra-ui/react-use-focus-effect': registry.npmmirror.com/@chakra-ui/react-use-focus-effect@2.1.0(react@18.0.0) + '@chakra-ui/react-use-focus-on-pointer-down': registry.npmmirror.com/@chakra-ui/react-use-focus-on-pointer-down@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/popper@3.1.0(react@18.0.0): + resolution: {integrity: sha512-ciDdpdYbeFG7og6/6J8lkTFxsSvwTdMLFkpVylAF6VNC22jssiWfquj2eyD4rJnzkRFPvIWJq8hvbfhsm+AjSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/popper/-/popper-3.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/popper/3.1.0 + name: '@chakra-ui/popper' + version: 3.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@popperjs/core': registry.npmmirror.com/@popperjs/core@2.11.8 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/portal@2.1.0(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-9q9KWf6SArEcIq1gGofNcFPSWEyl+MfJjEUg/un1SMlQjaROOh3zYr+6JAwvcORiX7tyHosnmWC3d3wI2aPSQg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/portal/-/portal-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/portal/2.1.0 + name: '@chakra-ui/portal' + version: 2.1.0 + peerDependencies: + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + dev: false + + registry.npmmirror.com/@chakra-ui/progress@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-qUXuKbuhN60EzDD9mHR7B67D7p/ZqNS2Aze4Pbl1qGGZfulPW0PY8Rof32qDtttDQBkzQIzFGE8d9QpAemToIQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/progress/-/progress-2.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/progress/2.2.0 + name: '@chakra-ui/progress' + version: 2.2.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/provider@2.4.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-u4g02V9tJ9vVYfkLz5jBn/bKlAyjLdg4Sh3f7uckmYVAZpOL/uUlrStyADrynu3tZhI+BE8XdmXC4zs/SYD7ow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/provider/-/provider-2.4.1.tgz} + id: registry.npmmirror.com/@chakra-ui/provider/2.4.1 + name: '@chakra-ui/provider' + version: 2.4.1 + peerDependencies: + '@emotion/react': ^11.0.0 + '@emotion/styled': ^11.0.0 + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/css-reset': registry.npmmirror.com/@chakra-ui/css-reset@2.3.0(@emotion/react@11.11.1)(react@18.0.0) + '@chakra-ui/portal': registry.npmmirror.com/@chakra-ui/portal@2.1.0(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/react-env': registry.npmmirror.com/@chakra-ui/react-env@3.1.0(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/utils': registry.npmmirror.com/@chakra-ui/utils@2.0.15 + '@emotion/react': registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0) + '@emotion/styled': registry.npmmirror.com/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + dev: false + + registry.npmmirror.com/@chakra-ui/radio@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-5JXDVvMWsF/Cprh6BKfcTLbLtRcgD6Wl2zwbNU30nmKIE8+WUfqD7JQETV08oWEzhi3Ea4e5EHvyll2sGx8H3w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/radio/-/radio-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/radio/2.1.1 + name: '@chakra-ui/radio' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@zag-js/focus-visible': registry.npmmirror.com/@zag-js/focus-visible@0.16.0 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0): + resolution: {integrity: sha512-QVR2RC7QsOsbWwEnq9YduhpqSFnZGvjjGREV8ygKi8ADhXh93C8azLECCUVgRJF2Wc+So1fgxmjLcbZfY2VmBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-children-utils/-/react-children-utils-2.0.6.tgz} + id: registry.npmmirror.com/@chakra-ui/react-children-utils/2.0.6 + name: '@chakra-ui/react-children-utils' + version: 2.0.6 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0): + resolution: {integrity: sha512-iahyStvzQ4AOwKwdPReLGfDesGG+vWJfEsn0X/NoGph/SkN+HXtv2sCfYFFR9k7bb+Kvc6YfpLlSuLvKMHi2+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-context/-/react-context-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-context/2.1.0 + name: '@chakra-ui/react-context' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-env@3.1.0(react@18.0.0): + resolution: {integrity: sha512-Vr96GV2LNBth3+IKzr/rq1IcnkXv+MLmwjQH6C8BRtn3sNskgDFD5vLkVXcEhagzZMCh8FR3V/bzZPojBOyNhw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-env/-/react-env-3.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-env/3.1.0 + name: '@chakra-ui/react-env' + version: 3.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0): + resolution: {integrity: sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-types/-/react-types-2.0.7.tgz} + id: registry.npmmirror.com/@chakra-ui/react-types/2.0.7 + name: '@chakra-ui/react-types' + version: 2.0.7 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-animation-state@2.1.0(react@18.0.0): + resolution: {integrity: sha512-CFZkQU3gmDBwhqy0vC1ryf90BVHxVN8cTLpSyCpdmExUEtSEInSCGMydj2fvn7QXsz/za8JNdO2xxgJwxpLMtg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-animation-state/-/react-use-animation-state-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-animation-state/2.1.0 + name: '@chakra-ui/react-use-animation-state' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/dom-utils': registry.npmmirror.com/@chakra-ui/dom-utils@2.1.0 + '@chakra-ui/react-use-event-listener': registry.npmmirror.com/@chakra-ui/react-use-event-listener@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0): + resolution: {integrity: sha512-efnJrBtGDa4YaxDzDE90EnKD3Vkh5a1t3w7PhnRQmsphLy3g2UieasoKTlT2Hn118TwDjIv5ZjHJW6HbzXA9wQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-callback-ref/2.1.0 + name: '@chakra-ui/react-use-callback-ref' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0): + resolution: {integrity: sha512-QR/8fKNokxZUs4PfxjXuwl0fj/d71WPrmLJvEpCTkHjnzu7LnYvzoe2wB867IdooQJL0G1zBxl0Dq+6W1P3jpg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-controllable-state/-/react-use-controllable-state-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-controllable-state/2.1.0 + name: '@chakra-ui/react-use-controllable-state' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-disclosure@2.1.0(react@18.0.0): + resolution: {integrity: sha512-Ax4pmxA9LBGMyEZJhhUZobg9C0t3qFE4jVF1tGBsrLDcdBeLR9fwOogIPY9Hf0/wqSlAryAimICbr5hkpa5GSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-disclosure/-/react-use-disclosure-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-disclosure/2.1.0 + name: '@chakra-ui/react-use-disclosure' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-event-listener@2.1.0(react@18.0.0): + resolution: {integrity: sha512-U5greryDLS8ISP69DKDsYcsXRtAdnTQT+jjIlRYZ49K/XhUR/AqVZCK5BkR1spTDmO9H8SPhgeNKI70ODuDU/Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-event-listener/2.1.0 + name: '@chakra-ui/react-use-event-listener' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-focus-effect@2.1.0(react@18.0.0): + resolution: {integrity: sha512-xzVboNy7J64xveLcxTIJ3jv+lUJKDwRM7Szwn9tNzUIPD94O3qwjV7DDCUzN2490nSYDF4OBMt/wuDBtaR3kUQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-focus-effect/-/react-use-focus-effect-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-focus-effect/2.1.0 + name: '@chakra-ui/react-use-focus-effect' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/dom-utils': registry.npmmirror.com/@chakra-ui/dom-utils@2.1.0 + '@chakra-ui/react-use-event-listener': registry.npmmirror.com/@chakra-ui/react-use-event-listener@2.1.0(react@18.0.0) + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-focus-on-pointer-down@2.1.0(react@18.0.0): + resolution: {integrity: sha512-2jzrUZ+aiCG/cfanrolsnSMDykCAbv9EK/4iUyZno6BYb3vziucmvgKuoXbMPAzWNtwUwtuMhkby8rc61Ue+Lg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-focus-on-pointer-down/-/react-use-focus-on-pointer-down-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-focus-on-pointer-down/2.1.0 + name: '@chakra-ui/react-use-focus-on-pointer-down' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-event-listener': registry.npmmirror.com/@chakra-ui/react-use-event-listener@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-interval@2.1.0(react@18.0.0): + resolution: {integrity: sha512-8iWj+I/+A0J08pgEXP1J1flcvhLBHkk0ln7ZvGIyXiEyM6XagOTJpwNhiu+Bmk59t3HoV/VyvyJTa+44sEApuw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-interval/-/react-use-interval-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-interval/2.1.0 + name: '@chakra-ui/react-use-interval' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-latest-ref@2.1.0(react@18.0.0): + resolution: {integrity: sha512-m0kxuIYqoYB0va9Z2aW4xP/5b7BzlDeWwyXCH6QpT2PpW3/281L3hLCm1G0eOUcdVlayqrQqOeD6Mglq+5/xoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-latest-ref/-/react-use-latest-ref-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-latest-ref/2.1.0 + name: '@chakra-ui/react-use-latest-ref' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0): + resolution: {integrity: sha512-lERa6AWF1cjEtWSGjxWTaSMvneccnAVH4V4ozh8SYiN9fSPZLlSG3kNxfNzdFvMEhM7dnP60vynF7WjGdTgQbQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-merge-refs/2.1.0 + name: '@chakra-ui/react-use-merge-refs' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-outside-click@2.2.0(react@18.0.0): + resolution: {integrity: sha512-PNX+s/JEaMneijbgAM4iFL+f3m1ga9+6QK0E5Yh4s8KZJQ/bLwZzdhMz8J/+mL+XEXQ5J0N8ivZN28B82N1kNw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-outside-click/-/react-use-outside-click-2.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-outside-click/2.2.0 + name: '@chakra-ui/react-use-outside-click' + version: 2.2.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-pan-event@2.1.0(react@18.0.0): + resolution: {integrity: sha512-xmL2qOHiXqfcj0q7ZK5s9UjTh4Gz0/gL9jcWPA6GVf+A0Od5imEDa/Vz+533yQKWiNSm1QGrIj0eJAokc7O4fg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-pan-event/-/react-use-pan-event-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-pan-event/2.1.0 + name: '@chakra-ui/react-use-pan-event' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/event-utils': registry.npmmirror.com/@chakra-ui/event-utils@2.0.8 + '@chakra-ui/react-use-latest-ref': registry.npmmirror.com/@chakra-ui/react-use-latest-ref@2.1.0(react@18.0.0) + framesync: registry.npmmirror.com/framesync@6.1.2 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-previous@2.1.0(react@18.0.0): + resolution: {integrity: sha512-pjxGwue1hX8AFcmjZ2XfrQtIJgqbTF3Qs1Dy3d1krC77dEsiCUbQ9GzOBfDc8pfd60DrB5N2tg5JyHbypqh0Sg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-previous/-/react-use-previous-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-previous/2.1.0 + name: '@chakra-ui/react-use-previous' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0): + resolution: {integrity: sha512-Knbrrx/bcPwVS1TorFdzrK/zWA8yuU/eaXDkNj24IrKoRlQrSBFarcgAEzlCHtzuhufP3OULPkELTzz91b0tCw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect/2.1.0 + name: '@chakra-ui/react-use-safe-layout-effect' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-size@2.1.0(react@18.0.0): + resolution: {integrity: sha512-tbLqrQhbnqOjzTaMlYytp7wY8BW1JpL78iG7Ru1DlV4EWGiAmXFGvtnEt9HftU0NJ0aJyjgymkxfVGI55/1Z4A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-size/-/react-use-size-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-size/2.1.0 + name: '@chakra-ui/react-use-size' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@zag-js/element-size': registry.npmmirror.com/@zag-js/element-size@0.10.5 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-timeout@2.1.0(react@18.0.0): + resolution: {integrity: sha512-cFN0sobKMM9hXUhyCofx3/Mjlzah6ADaEl/AXl5Y+GawB5rgedgAcu2ErAgarEkwvsKdP6c68CKjQ9dmTQlJxQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-timeout/-/react-use-timeout-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-timeout/2.1.0 + name: '@chakra-ui/react-use-timeout' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0): + resolution: {integrity: sha512-ND4Q23tETaR2Qd3zwCKYOOS1dfssojPLJMLvUtUbW5M9uW1ejYWgGUobeAiOVfSplownG8QYMmHTP86p/v0lbA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/react-use-update-effect/2.1.0 + name: '@chakra-ui/react-use-update-effect' + version: 2.1.0 + peerDependencies: + react: '>=18' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react-utils@2.0.12(react@18.0.0): + resolution: {integrity: sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react-utils/-/react-utils-2.0.12.tgz} + id: registry.npmmirror.com/@chakra-ui/react-utils/2.0.12 + name: '@chakra-ui/react-utils' + version: 2.0.12 + peerDependencies: + react: '>=18' + dependencies: + '@chakra-ui/utils': registry.npmmirror.com/@chakra-ui/utils@2.0.15 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/react@2.8.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.0.0)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-UL9Rtj4DovP3+oVbI06gsdfyJJb+wmS2RYnGNXjW9tsjCyXxjlBw9TAUj0jyOfWe0+zd/4juL8+J+QCwmdhptg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/react/-/react-2.8.1.tgz} + id: registry.npmmirror.com/@chakra-ui/react/2.8.1 + name: '@chakra-ui/react' + version: 2.8.1 + peerDependencies: + '@emotion/react': ^11.0.0 + '@emotion/styled': ^11.0.0 + framer-motion: '>=4.0.0' + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/accordion': registry.npmmirror.com/@chakra-ui/accordion@2.3.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0) + '@chakra-ui/alert': registry.npmmirror.com/@chakra-ui/alert@2.2.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/avatar': registry.npmmirror.com/@chakra-ui/avatar@2.3.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/breadcrumb': registry.npmmirror.com/@chakra-ui/breadcrumb@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/button': registry.npmmirror.com/@chakra-ui/button@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/card': registry.npmmirror.com/@chakra-ui/card@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/checkbox': registry.npmmirror.com/@chakra-ui/checkbox@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/close-button': registry.npmmirror.com/@chakra-ui/close-button@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/control-box': registry.npmmirror.com/@chakra-ui/control-box@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/counter': registry.npmmirror.com/@chakra-ui/counter@2.1.0(react@18.0.0) + '@chakra-ui/css-reset': registry.npmmirror.com/@chakra-ui/css-reset@2.3.0(@emotion/react@11.11.1)(react@18.0.0) + '@chakra-ui/editable': registry.npmmirror.com/@chakra-ui/editable@3.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/focus-lock': registry.npmmirror.com/@chakra-ui/focus-lock@2.1.0(@types/react@18.0.0)(react@18.0.0) + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/hooks': registry.npmmirror.com/@chakra-ui/hooks@2.2.1(react@18.0.0) + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/image': registry.npmmirror.com/@chakra-ui/image@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/input': registry.npmmirror.com/@chakra-ui/input@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/layout': registry.npmmirror.com/@chakra-ui/layout@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/live-region': registry.npmmirror.com/@chakra-ui/live-region@2.1.0(react@18.0.0) + '@chakra-ui/media-query': registry.npmmirror.com/@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/menu': registry.npmmirror.com/@chakra-ui/menu@2.2.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0) + '@chakra-ui/modal': registry.npmmirror.com/@chakra-ui/modal@2.3.1(@chakra-ui/system@2.6.1)(@types/react@18.0.0)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/number-input': registry.npmmirror.com/@chakra-ui/number-input@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/pin-input': registry.npmmirror.com/@chakra-ui/pin-input@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/popover': registry.npmmirror.com/@chakra-ui/popover@2.2.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0) + '@chakra-ui/popper': registry.npmmirror.com/@chakra-ui/popper@3.1.0(react@18.0.0) + '@chakra-ui/portal': registry.npmmirror.com/@chakra-ui/portal@2.1.0(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/progress': registry.npmmirror.com/@chakra-ui/progress@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/provider': registry.npmmirror.com/@chakra-ui/provider@2.4.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/radio': registry.npmmirror.com/@chakra-ui/radio@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-env': registry.npmmirror.com/@chakra-ui/react-env@3.1.0(react@18.0.0) + '@chakra-ui/select': registry.npmmirror.com/@chakra-ui/select@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/skeleton': registry.npmmirror.com/@chakra-ui/skeleton@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/skip-nav': registry.npmmirror.com/@chakra-ui/skip-nav@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/slider': registry.npmmirror.com/@chakra-ui/slider@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/spinner': registry.npmmirror.com/@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/stat': registry.npmmirror.com/@chakra-ui/stat@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/stepper': registry.npmmirror.com/@chakra-ui/stepper@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/styled-system': registry.npmmirror.com/@chakra-ui/styled-system@2.9.1 + '@chakra-ui/switch': registry.npmmirror.com/@chakra-ui/switch@2.1.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/table': registry.npmmirror.com/@chakra-ui/table@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/tabs': registry.npmmirror.com/@chakra-ui/tabs@3.0.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/tag': registry.npmmirror.com/@chakra-ui/tag@3.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/textarea': registry.npmmirror.com/@chakra-ui/textarea@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/theme': registry.npmmirror.com/@chakra-ui/theme@3.3.0(@chakra-ui/styled-system@2.9.1) + '@chakra-ui/theme-utils': registry.npmmirror.com/@chakra-ui/theme-utils@2.0.20 + '@chakra-ui/toast': registry.npmmirror.com/@chakra-ui/toast@7.0.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/tooltip': registry.npmmirror.com/@chakra-ui/tooltip@2.3.0(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/transition': registry.npmmirror.com/@chakra-ui/transition@2.1.0(framer-motion@10.16.4)(react@18.0.0) + '@chakra-ui/utils': registry.npmmirror.com/@chakra-ui/utils@2.0.15 + '@chakra-ui/visually-hidden': registry.npmmirror.com/@chakra-ui/visually-hidden@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@emotion/react': registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0) + '@emotion/styled': registry.npmmirror.com/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.0.0)(react@18.0.0) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + transitivePeerDependencies: + - '@types/react' + dev: false + + registry.npmmirror.com/@chakra-ui/select@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-CERDATncv5w05Zo5/LrFtf1yKp1deyMUyDGv6eZvQG/etyukH4TstsuIHt/0GfNXrCF3CJLZ8lINzpv5wayVjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/select/-/select-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/select/2.1.1 + name: '@chakra-ui/select' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5: + resolution: {integrity: sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz} + name: '@chakra-ui/shared-utils' + version: 2.0.5 + dev: false + + registry.npmmirror.com/@chakra-ui/skeleton@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-JNRuMPpdZGd6zFVKjVQ0iusu3tXAdI29n4ZENYwAJEMf/fN0l12sVeirOxkJ7oEL0yOx2AgEYFSKdbcAgfUsAQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/skeleton/-/skeleton-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/skeleton/2.1.0 + name: '@chakra-ui/skeleton' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/media-query': registry.npmmirror.com/@chakra-ui/media-query@3.3.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-use-previous': registry.npmmirror.com/@chakra-ui/react-use-previous@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/skip-nav@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-Hk+FG+vadBSH0/7hwp9LJnLjkO0RPGnx7gBJWI4/SpoJf3e4tZlWYtwGj0toYY4aGKl93jVghuwGbDBEMoHDug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/skip-nav/-/skip-nav-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/skip-nav/2.1.0 + name: '@chakra-ui/skip-nav' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/slider@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-lUOBcLMCnFZiA/s2NONXhELJh6sY5WtbRykPtclGfynqqOo47lwWJx+VP7xaeuhDOPcWSSecWc9Y1BfPOCz9cQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/slider/-/slider-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/slider/2.1.0 + name: '@chakra-ui/slider' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/number-utils': registry.npmmirror.com/@chakra-ui/number-utils@2.0.7 + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-callback-ref': registry.npmmirror.com/@chakra-ui/react-use-callback-ref@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-latest-ref': registry.npmmirror.com/@chakra-ui/react-use-latest-ref@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/react-use-pan-event': registry.npmmirror.com/@chakra-ui/react-use-pan-event@2.1.0(react@18.0.0) + '@chakra-ui/react-use-size': registry.npmmirror.com/@chakra-ui/react-use-size@2.1.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/spinner@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-hczbnoXt+MMv/d3gE+hjQhmkzLiKuoTo42YhUG7Bs9OSv2lg1fZHW1fGNRFP3wTi6OIbD044U1P9HK+AOgFH3g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/spinner/-/spinner-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/spinner/2.1.0 + name: '@chakra-ui/spinner' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/stat@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-LDn0d/LXQNbAn2KaR3F1zivsZCewY4Jsy1qShmfBMKwn6rI8yVlbvu6SiA3OpHS0FhxbsZxQI6HefEoIgtqY6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/stat/-/stat-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/stat/2.1.1 + name: '@chakra-ui/stat' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/stepper@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-ky77lZbW60zYkSXhYz7kbItUpAQfEdycT0Q4bkHLxfqbuiGMf8OmgZOQkOB9uM4v0zPwy2HXhe0vq4Dd0xa55Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/stepper/-/stepper-2.3.1.tgz} + id: registry.npmmirror.com/@chakra-ui/stepper/2.3.1 + name: '@chakra-ui/stepper' + version: 2.3.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/styled-system@2.9.1: + resolution: {integrity: sha512-jhYKBLxwOPi9/bQt9kqV3ELa/4CjmNNruTyXlPp5M0v0+pDMUngPp48mVLoskm9RKZGE0h1qpvj/jZ3K7c7t8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/styled-system/-/styled-system-2.9.1.tgz} + name: '@chakra-ui/styled-system' + version: 2.9.1 + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + csstype: registry.npmmirror.com/csstype@3.1.2 + lodash.mergewith: registry.npmmirror.com/lodash.mergewith@4.6.2 + dev: false + + registry.npmmirror.com/@chakra-ui/switch@2.1.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react@18.0.0): + resolution: {integrity: sha512-cOHIhW5AlLZSFENxFEBYTBniqiduOowa1WdzslP1Fd0usBFaD5iAgOY1Fvr7xKhE8nmzzeMCkPB3XBvUSWnawQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/switch/-/switch-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/switch/2.1.1 + name: '@chakra-ui/switch' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + dependencies: + '@chakra-ui/checkbox': registry.npmmirror.com/@chakra-ui/checkbox@2.3.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0): + resolution: {integrity: sha512-P5Q/XRWy3f1pXJ7IxDkV+Z6AT7GJeR2JlBnQl109xewVQcBLWWMIp702fFMFw8KZ2ALB/aYKtWm5EmQMddC/tg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/system/-/system-2.6.1.tgz} + id: registry.npmmirror.com/@chakra-ui/system/2.6.1 + name: '@chakra-ui/system' + version: 2.6.1 + peerDependencies: + '@emotion/react': ^11.0.0 + '@emotion/styled': ^11.0.0 + react: '>=18' + dependencies: + '@chakra-ui/color-mode': registry.npmmirror.com/@chakra-ui/color-mode@2.2.0(react@18.0.0) + '@chakra-ui/object-utils': registry.npmmirror.com/@chakra-ui/object-utils@2.1.0 + '@chakra-ui/react-utils': registry.npmmirror.com/@chakra-ui/react-utils@2.0.12(react@18.0.0) + '@chakra-ui/styled-system': registry.npmmirror.com/@chakra-ui/styled-system@2.9.1 + '@chakra-ui/theme-utils': registry.npmmirror.com/@chakra-ui/theme-utils@2.0.20 + '@chakra-ui/utils': registry.npmmirror.com/@chakra-ui/utils@2.0.15 + '@emotion/react': registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0) + '@emotion/styled': registry.npmmirror.com/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-fast-compare: registry.npmmirror.com/react-fast-compare@3.2.2 + dev: false + + registry.npmmirror.com/@chakra-ui/table@2.1.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-o5OrjoHCh5uCLdiUb0Oc0vq9rIAeHSIRScc2ExTC9Qg/uVZl2ygLrjToCaKfaaKl1oQexIeAcZDKvPG8tVkHyQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/table/-/table-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/table/2.1.0 + name: '@chakra-ui/table' + version: 2.1.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/tabs@3.0.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-6Mlclp8L9lqXmsGWF5q5gmemZXOiOYuh0SGT/7PgJVNPz3LXREXlXg2an4MBUD8W5oTkduCX+3KTMCwRrVrDYw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/tabs/-/tabs-3.0.0.tgz} + id: registry.npmmirror.com/@chakra-ui/tabs/3.0.0 + name: '@chakra-ui/tabs' + version: 3.0.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/clickable': registry.npmmirror.com/@chakra-ui/clickable@2.1.0(react@18.0.0) + '@chakra-ui/descendant': registry.npmmirror.com/@chakra-ui/descendant@3.1.0(react@18.0.0) + '@chakra-ui/lazy-utils': registry.npmmirror.com/@chakra-ui/lazy-utils@2.0.5 + '@chakra-ui/react-children-utils': registry.npmmirror.com/@chakra-ui/react-children-utils@2.0.6(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-controllable-state': registry.npmmirror.com/@chakra-ui/react-use-controllable-state@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/react-use-safe-layout-effect': registry.npmmirror.com/@chakra-ui/react-use-safe-layout-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/tag@3.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-Bdel79Dv86Hnge2PKOU+t8H28nm/7Y3cKd4Kfk9k3lOpUh4+nkSGe58dhRzht59lEqa4N9waCgQiBdkydjvBXQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/tag/-/tag-3.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/tag/3.1.1 + name: '@chakra-ui/tag' + version: 3.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/icon': registry.npmmirror.com/@chakra-ui/icon@3.2.0(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/textarea@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-28bpwgmXg3BzSpg8i1Ao9h7pHaE1j2mBBFJpWaqPgMhS0IHm0BQsqqyWU6PsxxJDvrC4HN6MTzrIL4C1RA1I0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/textarea/-/textarea-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/textarea/2.1.1 + name: '@chakra-ui/textarea' + version: 2.1.1 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/form-control': registry.npmmirror.com/@chakra-ui/form-control@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/theme-tools@2.1.1(@chakra-ui/styled-system@2.9.1): + resolution: {integrity: sha512-n14L5L3ej3Zy+Xm/kDKO1G6/DkmieT7Li1C7NzMRcUj5C9YybQpyo7IZZ0BBUh3u+OVnKVhNC3d4P2NYDGRXmA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/theme-tools/-/theme-tools-2.1.1.tgz} + id: registry.npmmirror.com/@chakra-ui/theme-tools/2.1.1 + name: '@chakra-ui/theme-tools' + version: 2.1.1 + peerDependencies: + '@chakra-ui/styled-system': '>=2.0.0' + dependencies: + '@chakra-ui/anatomy': registry.npmmirror.com/@chakra-ui/anatomy@2.2.1 + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/styled-system': registry.npmmirror.com/@chakra-ui/styled-system@2.9.1 + color2k: registry.npmmirror.com/color2k@2.0.2 + dev: false + + registry.npmmirror.com/@chakra-ui/theme-utils@2.0.20: + resolution: {integrity: sha512-IkAzSmwBlRIZ3dN2InDz0tf9SldbckVkgwylCobSFmYP8lnMjykL8Lex1BBo9U8UQjZxEDVZ+Qw6SeayKRntOQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/theme-utils/-/theme-utils-2.0.20.tgz} + name: '@chakra-ui/theme-utils' + version: 2.0.20 + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/styled-system': registry.npmmirror.com/@chakra-ui/styled-system@2.9.1 + '@chakra-ui/theme': registry.npmmirror.com/@chakra-ui/theme@3.3.0(@chakra-ui/styled-system@2.9.1) + lodash.mergewith: registry.npmmirror.com/lodash.mergewith@4.6.2 + dev: false + + registry.npmmirror.com/@chakra-ui/theme@3.3.0(@chakra-ui/styled-system@2.9.1): + resolution: {integrity: sha512-VHY2ax5Wqgfm83U/zYBk0GS0TGD8m41s/rxQgnEq8tU+ug1YZjvOZmtOq/VjfKP/bQraFhCt05zchcxXmDpEYg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/theme/-/theme-3.3.0.tgz} + id: registry.npmmirror.com/@chakra-ui/theme/3.3.0 + name: '@chakra-ui/theme' + version: 3.3.0 + peerDependencies: + '@chakra-ui/styled-system': '>=2.8.0' + dependencies: + '@chakra-ui/anatomy': registry.npmmirror.com/@chakra-ui/anatomy@2.2.1 + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/styled-system': registry.npmmirror.com/@chakra-ui/styled-system@2.9.1 + '@chakra-ui/theme-tools': registry.npmmirror.com/@chakra-ui/theme-tools@2.1.1(@chakra-ui/styled-system@2.9.1) + dev: false + + registry.npmmirror.com/@chakra-ui/toast@7.0.1(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-V5JUhw6RZxbGRTijvd5k4iEMLCfbzTLNWbZLZhRZk10YvFfAP5OYfRCm68zpE/t3orN/f+4ZLL3P+Wb4E7oSmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/toast/-/toast-7.0.1.tgz} + id: registry.npmmirror.com/@chakra-ui/toast/7.0.1 + name: '@chakra-ui/toast' + version: 7.0.1 + peerDependencies: + '@chakra-ui/system': 2.6.1 + framer-motion: '>=4.0.0' + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/alert': registry.npmmirror.com/@chakra-ui/alert@2.2.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/close-button': registry.npmmirror.com/@chakra-ui/close-button@2.1.1(@chakra-ui/system@2.6.1)(react@18.0.0) + '@chakra-ui/portal': registry.npmmirror.com/@chakra-ui/portal@2.1.0(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/react-context': registry.npmmirror.com/@chakra-ui/react-context@2.1.0(react@18.0.0) + '@chakra-ui/react-use-timeout': registry.npmmirror.com/@chakra-ui/react-use-timeout@2.1.0(react@18.0.0) + '@chakra-ui/react-use-update-effect': registry.npmmirror.com/@chakra-ui/react-use-update-effect@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/styled-system': registry.npmmirror.com/@chakra-ui/styled-system@2.9.1 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + '@chakra-ui/theme': registry.npmmirror.com/@chakra-ui/theme@3.3.0(@chakra-ui/styled-system@2.9.1) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + dev: false + + registry.npmmirror.com/@chakra-ui/tooltip@2.3.0(@chakra-ui/system@2.6.1)(framer-motion@10.16.4)(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-2s23f93YIij1qEDwIK//KtEu4LLYOslhR1cUhDBk/WUzyFR3Ez0Ee+HlqlGEGfGe9x77E6/UXPnSAKKdF/cpsg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/tooltip/-/tooltip-2.3.0.tgz} + id: registry.npmmirror.com/@chakra-ui/tooltip/2.3.0 + name: '@chakra-ui/tooltip' + version: 2.3.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + framer-motion: '>=4.0.0' + react: '>=18' + react-dom: '>=18' + dependencies: + '@chakra-ui/dom-utils': registry.npmmirror.com/@chakra-ui/dom-utils@2.1.0 + '@chakra-ui/popper': registry.npmmirror.com/@chakra-ui/popper@3.1.0(react@18.0.0) + '@chakra-ui/portal': registry.npmmirror.com/@chakra-ui/portal@2.1.0(react-dom@18.0.0)(react@18.0.0) + '@chakra-ui/react-types': registry.npmmirror.com/@chakra-ui/react-types@2.0.7(react@18.0.0) + '@chakra-ui/react-use-disclosure': registry.npmmirror.com/@chakra-ui/react-use-disclosure@2.1.0(react@18.0.0) + '@chakra-ui/react-use-event-listener': registry.npmmirror.com/@chakra-ui/react-use-event-listener@2.1.0(react@18.0.0) + '@chakra-ui/react-use-merge-refs': registry.npmmirror.com/@chakra-ui/react-use-merge-refs@2.1.0(react@18.0.0) + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + dev: false + + registry.npmmirror.com/@chakra-ui/transition@2.1.0(framer-motion@10.16.4)(react@18.0.0): + resolution: {integrity: sha512-orkT6T/Dt+/+kVwJNy7zwJ+U2xAZ3EU7M3XCs45RBvUnZDr/u9vdmaM/3D/rOpmQJWgQBwKPJleUXrYWUagEDQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/transition/-/transition-2.1.0.tgz} + id: registry.npmmirror.com/@chakra-ui/transition/2.1.0 + name: '@chakra-ui/transition' + version: 2.1.0 + peerDependencies: + framer-motion: '>=4.0.0' + react: '>=18' + dependencies: + '@chakra-ui/shared-utils': registry.npmmirror.com/@chakra-ui/shared-utils@2.0.5 + framer-motion: registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@chakra-ui/utils@2.0.15: + resolution: {integrity: sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/utils/-/utils-2.0.15.tgz} + name: '@chakra-ui/utils' + version: 2.0.15 + dependencies: + '@types/lodash.mergewith': registry.npmmirror.com/@types/lodash.mergewith@4.6.7 + css-box-model: registry.npmmirror.com/css-box-model@1.2.1 + framesync: registry.npmmirror.com/framesync@6.1.2 + lodash.mergewith: registry.npmmirror.com/lodash.mergewith@4.6.2 + dev: false + + registry.npmmirror.com/@chakra-ui/visually-hidden@2.2.0(@chakra-ui/system@2.6.1)(react@18.0.0): + resolution: {integrity: sha512-KmKDg01SrQ7VbTD3+cPWf/UfpF5MSwm3v7MWi0n5t8HnnadT13MF0MJCDSXbBWnzLv1ZKJ6zlyAOeARWX+DpjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@chakra-ui/visually-hidden/-/visually-hidden-2.2.0.tgz} + id: registry.npmmirror.com/@chakra-ui/visually-hidden/2.2.0 + name: '@chakra-ui/visually-hidden' + version: 2.2.0 + peerDependencies: + '@chakra-ui/system': '>=2.0.0' + react: '>=18' + dependencies: + '@chakra-ui/system': registry.npmmirror.com/@chakra-ui/system@2.6.1(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@emotion/babel-plugin@11.11.0: + resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz} + name: '@emotion/babel-plugin' + version: 11.11.0 + dependencies: + '@babel/helper-module-imports': registry.npmmirror.com/@babel/helper-module-imports@7.22.15 + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + '@emotion/hash': registry.npmmirror.com/@emotion/hash@0.9.1 + '@emotion/memoize': registry.npmmirror.com/@emotion/memoize@0.8.1 + '@emotion/serialize': registry.npmmirror.com/@emotion/serialize@1.1.2 + babel-plugin-macros: registry.npmmirror.com/babel-plugin-macros@3.1.0 + convert-source-map: registry.npmmirror.com/convert-source-map@1.9.0 + escape-string-regexp: registry.npmmirror.com/escape-string-regexp@4.0.0 + find-root: registry.npmmirror.com/find-root@1.1.0 + source-map: registry.npmmirror.com/source-map@0.5.7 + stylis: registry.npmmirror.com/stylis@4.2.0 + dev: false + + registry.npmmirror.com/@emotion/cache@11.11.0: + resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/cache/-/cache-11.11.0.tgz} + name: '@emotion/cache' + version: 11.11.0 + dependencies: + '@emotion/memoize': registry.npmmirror.com/@emotion/memoize@0.8.1 + '@emotion/sheet': registry.npmmirror.com/@emotion/sheet@1.2.2 + '@emotion/utils': registry.npmmirror.com/@emotion/utils@1.2.1 + '@emotion/weak-memoize': registry.npmmirror.com/@emotion/weak-memoize@0.3.1 + stylis: registry.npmmirror.com/stylis@4.2.0 + dev: false + + registry.npmmirror.com/@emotion/hash@0.9.1: + resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/hash/-/hash-0.9.1.tgz} + name: '@emotion/hash' + version: 0.9.1 + dev: false + + registry.npmmirror.com/@emotion/is-prop-valid@0.8.8: + resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz} + name: '@emotion/is-prop-valid' + version: 0.8.8 + requiresBuild: true + dependencies: + '@emotion/memoize': registry.npmmirror.com/@emotion/memoize@0.7.4 + dev: false + optional: true + + registry.npmmirror.com/@emotion/is-prop-valid@1.2.1: + resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz} + name: '@emotion/is-prop-valid' + version: 1.2.1 + dependencies: + '@emotion/memoize': registry.npmmirror.com/@emotion/memoize@0.8.1 + dev: false + + registry.npmmirror.com/@emotion/memoize@0.7.4: + resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/memoize/-/memoize-0.7.4.tgz} + name: '@emotion/memoize' + version: 0.7.4 + dev: false + optional: true + + registry.npmmirror.com/@emotion/memoize@0.8.1: + resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/memoize/-/memoize-0.8.1.tgz} + name: '@emotion/memoize' + version: 0.8.1 + dev: false + + registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/react/-/react-11.11.1.tgz} + id: registry.npmmirror.com/@emotion/react/11.11.1 + name: '@emotion/react' + version: 11.11.1 + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + '@emotion/babel-plugin': registry.npmmirror.com/@emotion/babel-plugin@11.11.0 + '@emotion/cache': registry.npmmirror.com/@emotion/cache@11.11.0 + '@emotion/serialize': registry.npmmirror.com/@emotion/serialize@1.1.2 + '@emotion/use-insertion-effect-with-fallbacks': registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.0.0) + '@emotion/utils': registry.npmmirror.com/@emotion/utils@1.2.1 + '@emotion/weak-memoize': registry.npmmirror.com/@emotion/weak-memoize@0.3.1 + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + hoist-non-react-statics: registry.npmmirror.com/hoist-non-react-statics@3.3.2 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@emotion/serialize@1.1.2: + resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/serialize/-/serialize-1.1.2.tgz} + name: '@emotion/serialize' + version: 1.1.2 + dependencies: + '@emotion/hash': registry.npmmirror.com/@emotion/hash@0.9.1 + '@emotion/memoize': registry.npmmirror.com/@emotion/memoize@0.8.1 + '@emotion/unitless': registry.npmmirror.com/@emotion/unitless@0.8.1 + '@emotion/utils': registry.npmmirror.com/@emotion/utils@1.2.1 + csstype: registry.npmmirror.com/csstype@3.1.2 + dev: false + + registry.npmmirror.com/@emotion/sheet@1.2.2: + resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/sheet/-/sheet-1.2.2.tgz} + name: '@emotion/sheet' + version: 1.2.2 + dev: false + + registry.npmmirror.com/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/styled/-/styled-11.11.0.tgz} + id: registry.npmmirror.com/@emotion/styled/11.11.0 + name: '@emotion/styled' + version: 11.11.0 + peerDependencies: + '@emotion/react': ^11.0.0-rc.0 + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + '@emotion/babel-plugin': registry.npmmirror.com/@emotion/babel-plugin@11.11.0 + '@emotion/is-prop-valid': registry.npmmirror.com/@emotion/is-prop-valid@1.2.1 + '@emotion/react': registry.npmmirror.com/@emotion/react@11.11.1(@types/react@18.0.0)(react@18.0.0) + '@emotion/serialize': registry.npmmirror.com/@emotion/serialize@1.1.2 + '@emotion/use-insertion-effect-with-fallbacks': registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.0.0) + '@emotion/utils': registry.npmmirror.com/@emotion/utils@1.2.1 + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@emotion/unitless@0.8.1: + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/unitless/-/unitless-0.8.1.tgz} + name: '@emotion/unitless' + version: 0.8.1 + dev: false + + registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.0.0): + resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz} + id: registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks/1.0.1 + name: '@emotion/use-insertion-effect-with-fallbacks' + version: 1.0.1 + peerDependencies: + react: '>=16.8.0' + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/@emotion/utils@1.2.1: + resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/utils/-/utils-1.2.1.tgz} + name: '@emotion/utils' + version: 1.2.1 + dev: false + + registry.npmmirror.com/@emotion/weak-memoize@0.3.1: + resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz} + name: '@emotion/weak-memoize' + version: 0.3.1 + dev: false + + registry.npmmirror.com/@eslint/eslintrc@1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz} + name: '@eslint/eslintrc' + version: 1.4.1 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: registry.npmmirror.com/ajv@6.12.6 + debug: registry.npmmirror.com/debug@4.3.4 + espree: registry.npmmirror.com/espree@9.6.1 + globals: registry.npmmirror.com/globals@13.23.0 + ignore: registry.npmmirror.com/ignore@5.2.4 + import-fresh: registry.npmmirror.com/import-fresh@3.3.0 + js-yaml: registry.npmmirror.com/js-yaml@4.1.0 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + strip-json-comments: registry.npmmirror.com/strip-json-comments@3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@humanwhocodes/config-array@0.6.0: + resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.6.0.tgz} + name: '@humanwhocodes/config-array' + version: 0.6.0 + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': registry.npmmirror.com/@humanwhocodes/object-schema@1.2.1 + debug: registry.npmmirror.com/debug@4.3.4 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@humanwhocodes/object-schema@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz} + name: '@humanwhocodes/object-schema' + version: 1.2.1 + dev: true + + registry.npmmirror.com/@mongodb-js/saslprep@1.1.0: + resolution: {integrity: sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz} + name: '@mongodb-js/saslprep' + version: 1.1.0 + dependencies: + sparse-bitfield: registry.npmmirror.com/sparse-bitfield@3.0.3 + dev: false + + registry.npmmirror.com/@next/env@13.5.4: + resolution: {integrity: sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/env/-/env-13.5.4.tgz} + name: '@next/env' + version: 13.5.4 + dev: false + + registry.npmmirror.com/@next/eslint-plugin-next@13.5.4: + resolution: {integrity: sha512-vI94U+D7RNgX6XypSyjeFrOzxGlZyxOplU0dVE5norIfZGn/LDjJYPHdvdsR5vN1eRtl6PDAsOHmycFEOljK5A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.4.tgz} + name: '@next/eslint-plugin-next' + version: 13.5.4 + dependencies: + glob: registry.npmmirror.com/glob@7.1.7 + dev: true + + registry.npmmirror.com/@next/swc-darwin-arm64@13.5.4: + resolution: {integrity: sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz} + name: '@next/swc-darwin-arm64' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-darwin-x64@13.5.4: + resolution: {integrity: sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz} + name: '@next/swc-darwin-x64' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.4: + resolution: {integrity: sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz} + name: '@next/swc-linux-arm64-gnu' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.4: + resolution: {integrity: sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz} + name: '@next/swc-linux-arm64-musl' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.4: + resolution: {integrity: sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz} + name: '@next/swc-linux-x64-gnu' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.4: + resolution: {integrity: sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz} + name: '@next/swc-linux-x64-musl' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.4: + resolution: {integrity: sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz} + name: '@next/swc-win32-arm64-msvc' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.4: + resolution: {integrity: sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz} + name: '@next/swc-win32-ia32-msvc' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.4: + resolution: {integrity: sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz} + name: '@next/swc-win32-x64-msvc' + version: 13.5.4 + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + registry.npmmirror.com/@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz} + name: '@nodelib/fs.scandir' + version: 2.1.5 + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': registry.npmmirror.com/@nodelib/fs.stat@2.0.5 + run-parallel: registry.npmmirror.com/run-parallel@1.2.0 + dev: true + + registry.npmmirror.com/@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz} + name: '@nodelib/fs.stat' + version: 2.0.5 + engines: {node: '>= 8'} + dev: true + + registry.npmmirror.com/@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz} + name: '@nodelib/fs.walk' + version: 1.2.8 + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': registry.npmmirror.com/@nodelib/fs.scandir@2.1.5 + fastq: registry.npmmirror.com/fastq@1.15.0 + dev: true + + registry.npmmirror.com/@popperjs/core@2.11.8: + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@popperjs/core/-/core-2.11.8.tgz} + name: '@popperjs/core' + version: 2.11.8 + dev: false + + registry.npmmirror.com/@rushstack/eslint-patch@1.5.1: + resolution: {integrity: sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz} + name: '@rushstack/eslint-patch' + version: 1.5.1 + dev: true + + registry.npmmirror.com/@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.2.tgz} + name: '@swc/helpers' + version: 0.5.2 + dependencies: + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/@tanstack/query-core@4.36.1: + resolution: {integrity: sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tanstack/query-core/-/query-core-4.36.1.tgz} + name: '@tanstack/query-core' + version: 4.36.1 + dev: false + + registry.npmmirror.com/@tanstack/react-query@4.36.1(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@tanstack/react-query/-/react-query-4.36.1.tgz} + id: registry.npmmirror.com/@tanstack/react-query/4.36.1 + name: '@tanstack/react-query' + version: 4.36.1 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@tanstack/query-core': registry.npmmirror.com/@tanstack/query-core@4.36.1 + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + use-sync-external-store: registry.npmmirror.com/use-sync-external-store@1.2.0(react@18.0.0) + dev: false + + registry.npmmirror.com/@types/hoist-non-react-statics@3.3.3: + resolution: {integrity: sha512-Wny3a2UXn5FEA1l7gc6BbpoV5mD1XijZqgkp4TRgDCDL5r3B5ieOFGUX5h3n78Tr1MEG7BfvoM8qeztdvNU0fw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.3.tgz} + name: '@types/hoist-non-react-statics' + version: 3.3.3 + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + hoist-non-react-statics: registry.npmmirror.com/hoist-non-react-statics@3.3.2 + dev: false + + registry.npmmirror.com/@types/js-cookie@3.0.4: + resolution: {integrity: sha512-vMMnFF+H5KYqdd/myCzq6wLDlPpteJK+jGFgBus3Da7lw+YsDmx2C8feGTzY2M3Fo823yON+HC2CL240j4OV+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/js-cookie/-/js-cookie-3.0.4.tgz} + name: '@types/js-cookie' + version: 3.0.4 + dev: true + + registry.npmmirror.com/@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz} + name: '@types/json5' + version: 0.0.29 + dev: true + + registry.npmmirror.com/@types/jsonwebtoken@9.0.3: + resolution: {integrity: sha512-b0jGiOgHtZ2jqdPgPnP6WLCXZk1T8p06A/vPGzUvxpFGgKMbjXJDjC5m52ErqBnIuWZFgGoIJyRdeG5AyreJjA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz} + name: '@types/jsonwebtoken' + version: 9.0.3 + dependencies: + '@types/node': registry.npmmirror.com/@types/node@20.0.0 + dev: true + + registry.npmmirror.com/@types/lodash.mergewith@4.6.7: + resolution: {integrity: sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz} + name: '@types/lodash.mergewith' + version: 4.6.7 + dependencies: + '@types/lodash': registry.npmmirror.com/@types/lodash@4.14.199 + dev: false + + registry.npmmirror.com/@types/lodash@4.14.199: + resolution: {integrity: sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.199.tgz} + name: '@types/lodash' + version: 4.14.199 + + registry.npmmirror.com/@types/node@12.20.55: + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-12.20.55.tgz} + name: '@types/node' + version: 12.20.55 + dev: false + + registry.npmmirror.com/@types/node@20.0.0: + resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-20.0.0.tgz} + name: '@types/node' + version: 20.0.0 + + registry.npmmirror.com/@types/nprogress@0.2.1: + resolution: {integrity: sha512-TYuyVnp+nOnimgdOydDIDYIxv2kSeuJZw4tF0p/KG7hpzcMF1WkHaREwM8O4blqfT1F7rq0nht6Ko2KVUfWzBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/nprogress/-/nprogress-0.2.1.tgz} + name: '@types/nprogress' + version: 0.2.1 + dev: true + + registry.npmmirror.com/@types/parse-json@4.0.0: + resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.0.tgz} + name: '@types/parse-json' + version: 4.0.0 + dev: false + + registry.npmmirror.com/@types/prop-types@15.7.8: + resolution: {integrity: sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.8.tgz} + name: '@types/prop-types' + version: 15.7.8 + + registry.npmmirror.com/@types/react-dom@18.0.0: + resolution: {integrity: sha512-49897Y0UiCGmxZqpC8Blrf6meL8QUla6eb+BBhn69dTXlmuOlzkfr7HHY/O8J25e1lTUMs+YYxSlVDAaGHCOLg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/react-dom/-/react-dom-18.0.0.tgz} + name: '@types/react-dom' + version: 18.0.0 + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + dev: true + + registry.npmmirror.com/@types/react@18.0.0: + resolution: {integrity: sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/react/-/react-18.0.0.tgz} + name: '@types/react' + version: 18.0.0 + dependencies: + '@types/prop-types': registry.npmmirror.com/@types/prop-types@15.7.8 + '@types/scheduler': registry.npmmirror.com/@types/scheduler@0.16.4 + csstype: registry.npmmirror.com/csstype@3.1.2 + + registry.npmmirror.com/@types/scheduler@0.16.4: + resolution: {integrity: sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/scheduler/-/scheduler-0.16.4.tgz} + name: '@types/scheduler' + version: 0.16.4 + + registry.npmmirror.com/@types/uuid@9.0.5: + resolution: {integrity: sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/uuid/-/uuid-9.0.5.tgz} + name: '@types/uuid' + version: 9.0.5 + dev: true + + registry.npmmirror.com/@types/webidl-conversions@7.0.1: + resolution: {integrity: sha512-8hKOnOan+Uu+NgMaCouhg3cT9x5fFZ92Jwf+uDLXLu/MFRbXxlWwGeQY7KVHkeSft6RvY+tdxklUBuyY9eIEKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.1.tgz} + name: '@types/webidl-conversions' + version: 7.0.1 + dev: false + + registry.npmmirror.com/@types/whatwg-url@8.2.2: + resolution: {integrity: sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz} + name: '@types/whatwg-url' + version: 8.2.2 + dependencies: + '@types/node': registry.npmmirror.com/@types/node@20.0.0 + '@types/webidl-conversions': registry.npmmirror.com/@types/webidl-conversions@7.0.1 + dev: false + + registry.npmmirror.com/@types/xml2js@0.4.12: + resolution: {integrity: sha512-CZPpQKBZ8db66EP5hCjwvYrLThgZvnyZrPXK2W+UI1oOaWezGt34iOaUCX4Jah2X8+rQqjvl9VKEIT8TR1I0rA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/xml2js/-/xml2js-0.4.12.tgz} + name: '@types/xml2js' + version: 0.4.12 + dependencies: + '@types/node': registry.npmmirror.com/@types/node@20.0.0 + dev: false + + registry.npmmirror.com/@typescript-eslint/parser@6.7.5(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-6.7.5.tgz} + id: registry.npmmirror.com/@typescript-eslint/parser/6.7.5 + name: '@typescript-eslint/parser' + version: 6.7.5 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': registry.npmmirror.com/@typescript-eslint/scope-manager@6.7.5 + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.7.5 + '@typescript-eslint/typescript-estree': registry.npmmirror.com/@typescript-eslint/typescript-estree@6.7.5(typescript@5.0.2) + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.7.5 + debug: registry.npmmirror.com/debug@4.3.4 + eslint: registry.npmmirror.com/eslint@8.0.0 + typescript: registry.npmmirror.com/typescript@5.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@typescript-eslint/scope-manager@6.7.5: + resolution: {integrity: sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz} + name: '@typescript-eslint/scope-manager' + version: 6.7.5 + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.7.5 + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.7.5 + dev: true + + registry.npmmirror.com/@typescript-eslint/types@6.7.5: + resolution: {integrity: sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/types/-/types-6.7.5.tgz} + name: '@typescript-eslint/types' + version: 6.7.5 + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + + registry.npmmirror.com/@typescript-eslint/typescript-estree@6.7.5(typescript@5.0.2): + resolution: {integrity: sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz} + id: registry.npmmirror.com/@typescript-eslint/typescript-estree/6.7.5 + name: '@typescript-eslint/typescript-estree' + version: 6.7.5 + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.7.5 + '@typescript-eslint/visitor-keys': registry.npmmirror.com/@typescript-eslint/visitor-keys@6.7.5 + debug: registry.npmmirror.com/debug@4.3.4 + globby: registry.npmmirror.com/globby@11.1.0 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + semver: registry.npmmirror.com/semver@7.5.4 + ts-api-utils: registry.npmmirror.com/ts-api-utils@1.0.3(typescript@5.0.2) + typescript: registry.npmmirror.com/typescript@5.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/@typescript-eslint/visitor-keys@6.7.5: + resolution: {integrity: sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz} + name: '@typescript-eslint/visitor-keys' + version: 6.7.5 + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': registry.npmmirror.com/@typescript-eslint/types@6.7.5 + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + dev: true + + registry.npmmirror.com/@zag-js/dom-query@0.16.0: + resolution: {integrity: sha512-Oqhd6+biWyKnhKwFFuZrrf6lxBz2tX2pRQe6grUnYwO6HJ8BcbqZomy2lpOdr+3itlaUqx+Ywj5E5ZZDr/LBfQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@zag-js/dom-query/-/dom-query-0.16.0.tgz} + name: '@zag-js/dom-query' + version: 0.16.0 + dev: false + + registry.npmmirror.com/@zag-js/element-size@0.10.5: + resolution: {integrity: sha512-uQre5IidULANvVkNOBQ1tfgwTQcGl4hliPSe69Fct1VfYb2Fd0jdAcGzqQgPhfrXFpR62MxLPB7erxJ/ngtL8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@zag-js/element-size/-/element-size-0.10.5.tgz} + name: '@zag-js/element-size' + version: 0.10.5 + dev: false + + registry.npmmirror.com/@zag-js/focus-visible@0.16.0: + resolution: {integrity: sha512-a7U/HSopvQbrDU4GLerpqiMcHKEkQkNPeDZJWz38cw/6Upunh41GjHetq5TB84hxyCaDzJ6q2nEdNoBQfC0FKA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@zag-js/focus-visible/-/focus-visible-0.16.0.tgz} + name: '@zag-js/focus-visible' + version: 0.16.0 + dependencies: + '@zag-js/dom-query': registry.npmmirror.com/@zag-js/dom-query@0.16.0 + dev: false + + registry.npmmirror.com/acorn-jsx@5.3.2(acorn@8.10.0): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz} + id: registry.npmmirror.com/acorn-jsx/5.3.2 + name: acorn-jsx + version: 5.3.2 + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: registry.npmmirror.com/acorn@8.10.0 + dev: true + + registry.npmmirror.com/acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/acorn/-/acorn-8.10.0.tgz} + name: acorn + version: 8.10.0 + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + registry.npmmirror.com/ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz} + name: ajv + version: 6.12.6 + dependencies: + fast-deep-equal: registry.npmmirror.com/fast-deep-equal@3.1.3 + fast-json-stable-stringify: registry.npmmirror.com/fast-json-stable-stringify@2.1.0 + json-schema-traverse: registry.npmmirror.com/json-schema-traverse@0.4.1 + uri-js: registry.npmmirror.com/uri-js@4.4.1 + dev: true + + registry.npmmirror.com/ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz} + name: ansi-colors + version: 4.1.3 + engines: {node: '>=6'} + dev: true + + registry.npmmirror.com/ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz} + name: ansi-regex + version: 5.0.1 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz} + name: ansi-styles + version: 3.2.1 + engines: {node: '>=4'} + dependencies: + color-convert: registry.npmmirror.com/color-convert@1.9.3 + dev: false + + registry.npmmirror.com/ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz} + name: ansi-styles + version: 4.3.0 + engines: {node: '>=8'} + dependencies: + color-convert: registry.npmmirror.com/color-convert@2.0.1 + dev: true + + registry.npmmirror.com/argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz} + name: argparse + version: 2.0.1 + dev: true + + registry.npmmirror.com/aria-hidden@1.2.3: + resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.3.tgz} + name: aria-hidden + version: 1.2.3 + engines: {node: '>=10'} + dependencies: + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/aria-query/-/aria-query-5.3.0.tgz} + name: aria-query + version: 5.3.0 + dependencies: + dequal: registry.npmmirror.com/dequal@2.0.3 + dev: true + + registry.npmmirror.com/array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz} + name: array-buffer-byte-length + version: 1.0.0 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + is-array-buffer: registry.npmmirror.com/is-array-buffer@3.0.2 + dev: true + + registry.npmmirror.com/array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array-includes/-/array-includes-3.1.7.tgz} + name: array-includes + version: 3.1.7 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + is-string: registry.npmmirror.com/is-string@1.0.7 + dev: true + + registry.npmmirror.com/array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz} + name: array-union + version: 2.1.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz} + name: array.prototype.findlastindex + version: 1.2.3 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + es-shim-unscopables: registry.npmmirror.com/es-shim-unscopables@1.0.0 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz} + name: array.prototype.flat + version: 1.3.2 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + es-shim-unscopables: registry.npmmirror.com/es-shim-unscopables@1.0.0 + dev: true + + registry.npmmirror.com/array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz} + name: array.prototype.flatmap + version: 1.3.2 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + es-shim-unscopables: registry.npmmirror.com/es-shim-unscopables@1.0.0 + dev: true + + registry.npmmirror.com/array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz} + name: array.prototype.tosorted + version: 1.1.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + es-shim-unscopables: registry.npmmirror.com/es-shim-unscopables@1.0.0 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz} + name: arraybuffer.prototype.slice + version: 1.0.2 + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: registry.npmmirror.com/array-buffer-byte-length@1.0.0 + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + is-array-buffer: registry.npmmirror.com/is-array-buffer@3.0.2 + is-shared-array-buffer: registry.npmmirror.com/is-shared-array-buffer@1.0.2 + dev: true + + registry.npmmirror.com/ast-types-flow@0.0.7: + resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz} + name: ast-types-flow + version: 0.0.7 + dev: true + + registry.npmmirror.com/asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz} + name: asynciterator.prototype + version: 1.0.0 + dependencies: + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + dev: true + + registry.npmmirror.com/asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz} + name: asynckit + version: 0.4.0 + dev: false + + registry.npmmirror.com/available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz} + name: available-typed-arrays + version: 1.0.5 + engines: {node: '>= 0.4'} + dev: true + + registry.npmmirror.com/axe-core@4.8.2: + resolution: {integrity: sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/axe-core/-/axe-core-4.8.2.tgz} + name: axe-core + version: 4.8.2 + engines: {node: '>=4'} + dev: true + + registry.npmmirror.com/axios@1.5.1: + resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/axios/-/axios-1.5.1.tgz} + name: axios + version: 1.5.1 + dependencies: + follow-redirects: registry.npmmirror.com/follow-redirects@1.15.3 + form-data: registry.npmmirror.com/form-data@4.0.0 + proxy-from-env: registry.npmmirror.com/proxy-from-env@1.1.0 + transitivePeerDependencies: + - debug + dev: false + + registry.npmmirror.com/axobject-query@3.2.1: + resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/axobject-query/-/axobject-query-3.2.1.tgz} + name: axobject-query + version: 3.2.1 + dependencies: + dequal: registry.npmmirror.com/dequal@2.0.3 + dev: true + + registry.npmmirror.com/babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz} + name: babel-plugin-macros + version: 3.1.0 + engines: {node: '>=10', npm: '>=6'} + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + cosmiconfig: registry.npmmirror.com/cosmiconfig@7.1.0 + resolve: registry.npmmirror.com/resolve@1.22.8 + dev: false + + registry.npmmirror.com/balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz} + name: balanced-match + version: 1.0.2 + dev: true + + registry.npmmirror.com/brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz} + name: brace-expansion + version: 1.1.11 + dependencies: + balanced-match: registry.npmmirror.com/balanced-match@1.0.2 + concat-map: registry.npmmirror.com/concat-map@0.0.1 + dev: true + + registry.npmmirror.com/braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz} + name: braces + version: 3.0.2 + engines: {node: '>=8'} + dependencies: + fill-range: registry.npmmirror.com/fill-range@7.0.1 + dev: true + + registry.npmmirror.com/bson@6.1.0: + resolution: {integrity: sha512-yiQ3KxvpVoRpx1oD1uPz4Jit9tAVTJgjdmjDKtUErkOoL9VNoF8Dd58qtAOL5E40exx2jvAT9sqdRSK/r+SHlA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/bson/-/bson-6.1.0.tgz} + name: bson + version: 6.1.0 + engines: {node: '>=16.20.1'} + dev: false + + registry.npmmirror.com/buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz} + name: buffer-equal-constant-time + version: 1.0.1 + dev: false + + registry.npmmirror.com/busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz} + name: busboy + version: 1.6.0 + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: registry.npmmirror.com/streamsearch@1.1.0 + dev: false + + registry.npmmirror.com/call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz} + name: call-bind + version: 1.0.2 + dependencies: + function-bind: registry.npmmirror.com/function-bind@1.1.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz} + name: callsites + version: 3.1.0 + engines: {node: '>=6'} + + registry.npmmirror.com/caniuse-lite@1.0.30001549: + resolution: {integrity: sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz} + name: caniuse-lite + version: 1.0.30001549 + dev: false + + registry.npmmirror.com/chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz} + name: chalk + version: 2.4.2 + engines: {node: '>=4'} + dependencies: + ansi-styles: registry.npmmirror.com/ansi-styles@3.2.1 + escape-string-regexp: registry.npmmirror.com/escape-string-regexp@1.0.5 + supports-color: registry.npmmirror.com/supports-color@5.5.0 + dev: false + + registry.npmmirror.com/chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz} + name: chalk + version: 4.1.2 + engines: {node: '>=10'} + dependencies: + ansi-styles: registry.npmmirror.com/ansi-styles@4.3.0 + supports-color: registry.npmmirror.com/supports-color@7.2.0 + dev: true + + registry.npmmirror.com/client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/client-only/-/client-only-0.0.1.tgz} + name: client-only + version: 0.0.1 + dev: false + + registry.npmmirror.com/clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/clsx/-/clsx-2.0.0.tgz} + name: clsx + version: 2.0.0 + engines: {node: '>=6'} + dev: false + + registry.npmmirror.com/color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz} + name: color-convert + version: 1.9.3 + dependencies: + color-name: registry.npmmirror.com/color-name@1.1.3 + dev: false + + registry.npmmirror.com/color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz} + name: color-convert + version: 2.0.1 + engines: {node: '>=7.0.0'} + dependencies: + color-name: registry.npmmirror.com/color-name@1.1.4 + dev: true + + registry.npmmirror.com/color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz} + name: color-name + version: 1.1.3 + dev: false + + registry.npmmirror.com/color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz} + name: color-name + version: 1.1.4 + dev: true + + registry.npmmirror.com/color2k@2.0.2: + resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color2k/-/color2k-2.0.2.tgz} + name: color2k + version: 2.0.2 + dev: false + + registry.npmmirror.com/combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz} + name: combined-stream + version: 1.0.8 + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: registry.npmmirror.com/delayed-stream@1.0.0 + dev: false + + registry.npmmirror.com/compute-scroll-into-view@3.0.3: + resolution: {integrity: sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz} + name: compute-scroll-into-view + version: 3.0.3 + dev: false + + registry.npmmirror.com/concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz} + name: concat-map + version: 0.0.1 + dev: true + + registry.npmmirror.com/convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz} + name: convert-source-map + version: 1.9.0 + dev: false + + registry.npmmirror.com/copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz} + name: copy-to-clipboard + version: 3.3.3 + dependencies: + toggle-selection: registry.npmmirror.com/toggle-selection@1.0.6 + dev: false + + registry.npmmirror.com/core-js@3.33.0: + resolution: {integrity: sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/core-js/-/core-js-3.33.0.tgz} + name: core-js + version: 3.33.0 + requiresBuild: true + dev: false + + registry.npmmirror.com/cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz} + name: cosmiconfig + version: 7.1.0 + engines: {node: '>=10'} + dependencies: + '@types/parse-json': registry.npmmirror.com/@types/parse-json@4.0.0 + import-fresh: registry.npmmirror.com/import-fresh@3.3.0 + parse-json: registry.npmmirror.com/parse-json@5.2.0 + path-type: registry.npmmirror.com/path-type@4.0.0 + yaml: registry.npmmirror.com/yaml@1.10.2 + dev: false + + registry.npmmirror.com/cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz} + name: cross-spawn + version: 7.0.3 + engines: {node: '>= 8'} + dependencies: + path-key: registry.npmmirror.com/path-key@3.1.1 + shebang-command: registry.npmmirror.com/shebang-command@2.0.0 + which: registry.npmmirror.com/which@2.0.2 + dev: true + + registry.npmmirror.com/css-box-model@1.2.1: + resolution: {integrity: sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/css-box-model/-/css-box-model-1.2.1.tgz} + name: css-box-model + version: 1.2.1 + dependencies: + tiny-invariant: registry.npmmirror.com/tiny-invariant@1.3.1 + dev: false + + registry.npmmirror.com/csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/csstype/-/csstype-3.1.2.tgz} + name: csstype + version: 3.1.2 + + registry.npmmirror.com/damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz} + name: damerau-levenshtein + version: 1.0.8 + dev: true + + registry.npmmirror.com/dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz} + name: dayjs + version: 1.11.10 + dev: false + + registry.npmmirror.com/debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz} + name: debug + version: 3.2.7 + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: registry.npmmirror.com/ms@2.1.3 + dev: true + + registry.npmmirror.com/debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz} + name: debug + version: 4.3.4 + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: registry.npmmirror.com/ms@2.1.2 + + registry.npmmirror.com/deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz} + name: deep-is + version: 0.1.4 + dev: true + + registry.npmmirror.com/define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.1.tgz} + name: define-data-property + version: 1.1.1 + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + gopd: registry.npmmirror.com/gopd@1.0.1 + has-property-descriptors: registry.npmmirror.com/has-property-descriptors@1.0.0 + dev: true + + registry.npmmirror.com/define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz} + name: define-properties + version: 1.2.1 + engines: {node: '>= 0.4'} + dependencies: + define-data-property: registry.npmmirror.com/define-data-property@1.1.1 + has-property-descriptors: registry.npmmirror.com/has-property-descriptors@1.0.0 + object-keys: registry.npmmirror.com/object-keys@1.1.1 + dev: true + + registry.npmmirror.com/delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz} + name: delayed-stream + version: 1.0.0 + engines: {node: '>=0.4.0'} + dev: false + + registry.npmmirror.com/dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz} + name: dequal + version: 2.0.3 + engines: {node: '>=6'} + dev: true + + registry.npmmirror.com/detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz} + name: detect-node-es + version: 1.1.0 + dev: false + + registry.npmmirror.com/dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz} + name: dir-glob + version: 3.0.1 + engines: {node: '>=8'} + dependencies: + path-type: registry.npmmirror.com/path-type@4.0.0 + dev: true + + registry.npmmirror.com/doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/doctrine/-/doctrine-2.1.0.tgz} + name: doctrine + version: 2.1.0 + engines: {node: '>=0.10.0'} + dependencies: + esutils: registry.npmmirror.com/esutils@2.0.3 + dev: true + + registry.npmmirror.com/doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz} + name: doctrine + version: 3.0.0 + engines: {node: '>=6.0.0'} + dependencies: + esutils: registry.npmmirror.com/esutils@2.0.3 + dev: true + + registry.npmmirror.com/ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz} + name: ecdsa-sig-formatter + version: 1.0.11 + dependencies: + safe-buffer: registry.npmmirror.com/safe-buffer@5.2.1 + dev: false + + registry.npmmirror.com/emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz} + name: emoji-regex + version: 9.2.2 + dev: true + + registry.npmmirror.com/enhanced-resolve@5.15.0: + resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz} + name: enhanced-resolve + version: 5.15.0 + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: registry.npmmirror.com/graceful-fs@4.2.11 + tapable: registry.npmmirror.com/tapable@2.2.1 + dev: true + + registry.npmmirror.com/enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/enquirer/-/enquirer-2.4.1.tgz} + name: enquirer + version: 2.4.1 + engines: {node: '>=8.6'} + dependencies: + ansi-colors: registry.npmmirror.com/ansi-colors@4.1.3 + strip-ansi: registry.npmmirror.com/strip-ansi@6.0.1 + dev: true + + registry.npmmirror.com/error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz} + name: error-ex + version: 1.3.2 + dependencies: + is-arrayish: registry.npmmirror.com/is-arrayish@0.2.1 + dev: false + + registry.npmmirror.com/es-abstract@1.22.2: + resolution: {integrity: sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/es-abstract/-/es-abstract-1.22.2.tgz} + name: es-abstract + version: 1.22.2 + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: registry.npmmirror.com/array-buffer-byte-length@1.0.0 + arraybuffer.prototype.slice: registry.npmmirror.com/arraybuffer.prototype.slice@1.0.2 + available-typed-arrays: registry.npmmirror.com/available-typed-arrays@1.0.5 + call-bind: registry.npmmirror.com/call-bind@1.0.2 + es-set-tostringtag: registry.npmmirror.com/es-set-tostringtag@2.0.1 + es-to-primitive: registry.npmmirror.com/es-to-primitive@1.2.1 + function.prototype.name: registry.npmmirror.com/function.prototype.name@1.1.6 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + get-symbol-description: registry.npmmirror.com/get-symbol-description@1.0.0 + globalthis: registry.npmmirror.com/globalthis@1.0.3 + gopd: registry.npmmirror.com/gopd@1.0.1 + has: registry.npmmirror.com/has@1.0.4 + has-property-descriptors: registry.npmmirror.com/has-property-descriptors@1.0.0 + has-proto: registry.npmmirror.com/has-proto@1.0.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + internal-slot: registry.npmmirror.com/internal-slot@1.0.5 + is-array-buffer: registry.npmmirror.com/is-array-buffer@3.0.2 + is-callable: registry.npmmirror.com/is-callable@1.2.7 + is-negative-zero: registry.npmmirror.com/is-negative-zero@2.0.2 + is-regex: registry.npmmirror.com/is-regex@1.1.4 + is-shared-array-buffer: registry.npmmirror.com/is-shared-array-buffer@1.0.2 + is-string: registry.npmmirror.com/is-string@1.0.7 + is-typed-array: registry.npmmirror.com/is-typed-array@1.1.12 + is-weakref: registry.npmmirror.com/is-weakref@1.0.2 + object-inspect: registry.npmmirror.com/object-inspect@1.12.3 + object-keys: registry.npmmirror.com/object-keys@1.1.1 + object.assign: registry.npmmirror.com/object.assign@4.1.4 + regexp.prototype.flags: registry.npmmirror.com/regexp.prototype.flags@1.5.1 + safe-array-concat: registry.npmmirror.com/safe-array-concat@1.0.1 + safe-regex-test: registry.npmmirror.com/safe-regex-test@1.0.0 + string.prototype.trim: registry.npmmirror.com/string.prototype.trim@1.2.8 + string.prototype.trimend: registry.npmmirror.com/string.prototype.trimend@1.0.7 + string.prototype.trimstart: registry.npmmirror.com/string.prototype.trimstart@1.0.7 + typed-array-buffer: registry.npmmirror.com/typed-array-buffer@1.0.0 + typed-array-byte-length: registry.npmmirror.com/typed-array-byte-length@1.0.0 + typed-array-byte-offset: registry.npmmirror.com/typed-array-byte-offset@1.0.0 + typed-array-length: registry.npmmirror.com/typed-array-length@1.0.4 + unbox-primitive: registry.npmmirror.com/unbox-primitive@1.0.2 + which-typed-array: registry.npmmirror.com/which-typed-array@1.1.11 + dev: true + + registry.npmmirror.com/es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz} + name: es-iterator-helpers + version: 1.0.15 + dependencies: + asynciterator.prototype: registry.npmmirror.com/asynciterator.prototype@1.0.0 + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + es-set-tostringtag: registry.npmmirror.com/es-set-tostringtag@2.0.1 + function-bind: registry.npmmirror.com/function-bind@1.1.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + globalthis: registry.npmmirror.com/globalthis@1.0.3 + has-property-descriptors: registry.npmmirror.com/has-property-descriptors@1.0.0 + has-proto: registry.npmmirror.com/has-proto@1.0.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + internal-slot: registry.npmmirror.com/internal-slot@1.0.5 + iterator.prototype: registry.npmmirror.com/iterator.prototype@1.1.2 + safe-array-concat: registry.npmmirror.com/safe-array-concat@1.0.1 + dev: true + + registry.npmmirror.com/es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz} + name: es-set-tostringtag + version: 2.0.1 + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + has: registry.npmmirror.com/has@1.0.4 + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz} + name: es-shim-unscopables + version: 1.0.0 + dependencies: + has: registry.npmmirror.com/has@1.0.4 + dev: true + + registry.npmmirror.com/es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz} + name: es-to-primitive + version: 1.2.1 + engines: {node: '>= 0.4'} + dependencies: + is-callable: registry.npmmirror.com/is-callable@1.2.7 + is-date-object: registry.npmmirror.com/is-date-object@1.0.5 + is-symbol: registry.npmmirror.com/is-symbol@1.0.4 + dev: true + + registry.npmmirror.com/escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz} + name: escape-string-regexp + version: 1.0.5 + engines: {node: '>=0.8.0'} + dev: false + + registry.npmmirror.com/escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz} + name: escape-string-regexp + version: 4.0.0 + engines: {node: '>=10'} + + registry.npmmirror.com/eslint-config-next@13.5.4(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-FzQGIj4UEszRX7fcRSJK6L1LrDiVZvDFW320VVntVKh3BSU8Fb9kpaoxQx0cdFgf3MQXdeSbrCXJ/5Z/NndDkQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-config-next/-/eslint-config-next-13.5.4.tgz} + id: registry.npmmirror.com/eslint-config-next/13.5.4 + name: eslint-config-next + version: 13.5.4 + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@next/eslint-plugin-next': registry.npmmirror.com/@next/eslint-plugin-next@13.5.4 + '@rushstack/eslint-patch': registry.npmmirror.com/@rushstack/eslint-patch@1.5.1 + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@6.7.5(eslint@8.0.0)(typescript@5.0.2) + eslint: registry.npmmirror.com/eslint@8.0.0 + eslint-import-resolver-node: registry.npmmirror.com/eslint-import-resolver-node@0.3.9 + eslint-import-resolver-typescript: registry.npmmirror.com/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.0.0) + eslint-plugin-import: registry.npmmirror.com/eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.0.0) + eslint-plugin-jsx-a11y: registry.npmmirror.com/eslint-plugin-jsx-a11y@6.7.1(eslint@8.0.0) + eslint-plugin-react: registry.npmmirror.com/eslint-plugin-react@7.33.2(eslint@8.0.0) + eslint-plugin-react-hooks: registry.npmmirror.com/eslint-plugin-react-hooks@4.6.0(eslint@8.0.0) + typescript: registry.npmmirror.com/typescript@5.0.2 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - supports-color + dev: true + + registry.npmmirror.com/eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz} + name: eslint-import-resolver-node + version: 0.3.9 + dependencies: + debug: registry.npmmirror.com/debug@3.2.7 + is-core-module: registry.npmmirror.com/is-core-module@2.13.0 + resolve: registry.npmmirror.com/resolve@1.22.8 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.0.0): + resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz} + id: registry.npmmirror.com/eslint-import-resolver-typescript/3.6.1 + name: eslint-import-resolver-typescript + version: 3.6.1 + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: registry.npmmirror.com/debug@4.3.4 + enhanced-resolve: registry.npmmirror.com/enhanced-resolve@5.15.0 + eslint: registry.npmmirror.com/eslint@8.0.0 + eslint-module-utils: registry.npmmirror.com/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.0.0) + eslint-plugin-import: registry.npmmirror.com/eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.0.0) + fast-glob: registry.npmmirror.com/fast-glob@3.3.1 + get-tsconfig: registry.npmmirror.com/get-tsconfig@4.7.2 + is-core-module: registry.npmmirror.com/is-core-module@2.13.0 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + dev: true + + registry.npmmirror.com/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.0.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz} + id: registry.npmmirror.com/eslint-module-utils/2.8.0 + name: eslint-module-utils + version: 2.8.0 + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@6.7.5(eslint@8.0.0)(typescript@5.0.2) + debug: registry.npmmirror.com/debug@3.2.7 + eslint: registry.npmmirror.com/eslint@8.0.0 + eslint-import-resolver-node: registry.npmmirror.com/eslint-import-resolver-node@0.3.9 + eslint-import-resolver-typescript: registry.npmmirror.com/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@8.0.0) + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/eslint-plugin-import@2.28.1(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-typescript@3.6.1)(eslint@8.0.0): + resolution: {integrity: sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz} + id: registry.npmmirror.com/eslint-plugin-import/2.28.1 + name: eslint-plugin-import + version: 2.28.1 + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@6.7.5(eslint@8.0.0)(typescript@5.0.2) + array-includes: registry.npmmirror.com/array-includes@3.1.7 + array.prototype.findlastindex: registry.npmmirror.com/array.prototype.findlastindex@1.2.3 + array.prototype.flat: registry.npmmirror.com/array.prototype.flat@1.3.2 + array.prototype.flatmap: registry.npmmirror.com/array.prototype.flatmap@1.3.2 + debug: registry.npmmirror.com/debug@3.2.7 + doctrine: registry.npmmirror.com/doctrine@2.1.0 + eslint: registry.npmmirror.com/eslint@8.0.0 + eslint-import-resolver-node: registry.npmmirror.com/eslint-import-resolver-node@0.3.9 + eslint-module-utils: registry.npmmirror.com/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.7.5)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.0.0) + has: registry.npmmirror.com/has@1.0.4 + is-core-module: registry.npmmirror.com/is-core-module@2.13.0 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + object.fromentries: registry.npmmirror.com/object.fromentries@2.0.7 + object.groupby: registry.npmmirror.com/object.groupby@1.0.1 + object.values: registry.npmmirror.com/object.values@1.1.7 + semver: registry.npmmirror.com/semver@6.3.1 + tsconfig-paths: registry.npmmirror.com/tsconfig-paths@3.14.2 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + registry.npmmirror.com/eslint-plugin-jsx-a11y@6.7.1(eslint@8.0.0): + resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz} + id: registry.npmmirror.com/eslint-plugin-jsx-a11y/6.7.1 + name: eslint-plugin-jsx-a11y + version: 6.7.1 + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + aria-query: registry.npmmirror.com/aria-query@5.3.0 + array-includes: registry.npmmirror.com/array-includes@3.1.7 + array.prototype.flatmap: registry.npmmirror.com/array.prototype.flatmap@1.3.2 + ast-types-flow: registry.npmmirror.com/ast-types-flow@0.0.7 + axe-core: registry.npmmirror.com/axe-core@4.8.2 + axobject-query: registry.npmmirror.com/axobject-query@3.2.1 + damerau-levenshtein: registry.npmmirror.com/damerau-levenshtein@1.0.8 + emoji-regex: registry.npmmirror.com/emoji-regex@9.2.2 + eslint: registry.npmmirror.com/eslint@8.0.0 + has: registry.npmmirror.com/has@1.0.4 + jsx-ast-utils: registry.npmmirror.com/jsx-ast-utils@3.3.5 + language-tags: registry.npmmirror.com/language-tags@1.0.5 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + object.entries: registry.npmmirror.com/object.entries@1.1.7 + object.fromentries: registry.npmmirror.com/object.fromentries@2.0.7 + semver: registry.npmmirror.com/semver@6.3.1 + dev: true + + registry.npmmirror.com/eslint-plugin-react-hooks@4.6.0(eslint@8.0.0): + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz} + id: registry.npmmirror.com/eslint-plugin-react-hooks/4.6.0 + name: eslint-plugin-react-hooks + version: 4.6.0 + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: registry.npmmirror.com/eslint@8.0.0 + dev: true + + registry.npmmirror.com/eslint-plugin-react@7.33.2(eslint@8.0.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz} + id: registry.npmmirror.com/eslint-plugin-react/7.33.2 + name: eslint-plugin-react + version: 7.33.2 + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: registry.npmmirror.com/array-includes@3.1.7 + array.prototype.flatmap: registry.npmmirror.com/array.prototype.flatmap@1.3.2 + array.prototype.tosorted: registry.npmmirror.com/array.prototype.tosorted@1.1.2 + doctrine: registry.npmmirror.com/doctrine@2.1.0 + es-iterator-helpers: registry.npmmirror.com/es-iterator-helpers@1.0.15 + eslint: registry.npmmirror.com/eslint@8.0.0 + estraverse: registry.npmmirror.com/estraverse@5.3.0 + jsx-ast-utils: registry.npmmirror.com/jsx-ast-utils@3.3.5 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + object.entries: registry.npmmirror.com/object.entries@1.1.7 + object.fromentries: registry.npmmirror.com/object.fromentries@2.0.7 + object.hasown: registry.npmmirror.com/object.hasown@1.1.3 + object.values: registry.npmmirror.com/object.values@1.1.7 + prop-types: registry.npmmirror.com/prop-types@15.8.1 + resolve: registry.npmmirror.com/resolve@2.0.0-next.5 + semver: registry.npmmirror.com/semver@6.3.1 + string.prototype.matchall: registry.npmmirror.com/string.prototype.matchall@4.0.10 + dev: true + + registry.npmmirror.com/eslint-scope@6.0.0: + resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-scope/-/eslint-scope-6.0.0.tgz} + name: eslint-scope + version: 6.0.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: registry.npmmirror.com/esrecurse@4.3.0 + estraverse: registry.npmmirror.com/estraverse@5.3.0 + dev: true + + registry.npmmirror.com/eslint-utils@3.0.0(eslint@8.0.0): + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-utils/-/eslint-utils-3.0.0.tgz} + id: registry.npmmirror.com/eslint-utils/3.0.0 + name: eslint-utils + version: 3.0.0 + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: registry.npmmirror.com/eslint@8.0.0 + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@2.1.0 + dev: true + + registry.npmmirror.com/eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz} + name: eslint-visitor-keys + version: 2.1.0 + engines: {node: '>=10'} + dev: true + + registry.npmmirror.com/eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz} + name: eslint-visitor-keys + version: 3.4.3 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + registry.npmmirror.com/eslint@8.0.0: + resolution: {integrity: sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/eslint/-/eslint-8.0.0.tgz} + name: eslint + version: 8.0.0 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': registry.npmmirror.com/@eslint/eslintrc@1.4.1 + '@humanwhocodes/config-array': registry.npmmirror.com/@humanwhocodes/config-array@0.6.0 + ajv: registry.npmmirror.com/ajv@6.12.6 + chalk: registry.npmmirror.com/chalk@4.1.2 + cross-spawn: registry.npmmirror.com/cross-spawn@7.0.3 + debug: registry.npmmirror.com/debug@4.3.4 + doctrine: registry.npmmirror.com/doctrine@3.0.0 + enquirer: registry.npmmirror.com/enquirer@2.4.1 + escape-string-regexp: registry.npmmirror.com/escape-string-regexp@4.0.0 + eslint-scope: registry.npmmirror.com/eslint-scope@6.0.0 + eslint-utils: registry.npmmirror.com/eslint-utils@3.0.0(eslint@8.0.0) + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + espree: registry.npmmirror.com/espree@9.6.1 + esquery: registry.npmmirror.com/esquery@1.5.0 + esutils: registry.npmmirror.com/esutils@2.0.3 + fast-deep-equal: registry.npmmirror.com/fast-deep-equal@3.1.3 + file-entry-cache: registry.npmmirror.com/file-entry-cache@6.0.1 + functional-red-black-tree: registry.npmmirror.com/functional-red-black-tree@1.0.1 + glob-parent: registry.npmmirror.com/glob-parent@6.0.2 + globals: registry.npmmirror.com/globals@13.23.0 + ignore: registry.npmmirror.com/ignore@4.0.6 + import-fresh: registry.npmmirror.com/import-fresh@3.3.0 + imurmurhash: registry.npmmirror.com/imurmurhash@0.1.4 + is-glob: registry.npmmirror.com/is-glob@4.0.3 + js-yaml: registry.npmmirror.com/js-yaml@4.1.0 + json-stable-stringify-without-jsonify: registry.npmmirror.com/json-stable-stringify-without-jsonify@1.0.1 + levn: registry.npmmirror.com/levn@0.4.1 + lodash.merge: registry.npmmirror.com/lodash.merge@4.6.2 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + natural-compare: registry.npmmirror.com/natural-compare@1.4.0 + optionator: registry.npmmirror.com/optionator@0.9.3 + progress: registry.npmmirror.com/progress@2.0.3 + regexpp: registry.npmmirror.com/regexpp@3.2.0 + semver: registry.npmmirror.com/semver@7.5.4 + strip-ansi: registry.npmmirror.com/strip-ansi@6.0.1 + strip-json-comments: registry.npmmirror.com/strip-json-comments@3.1.1 + text-table: registry.npmmirror.com/text-table@0.2.0 + v8-compile-cache: registry.npmmirror.com/v8-compile-cache@2.4.0 + transitivePeerDependencies: + - supports-color + dev: true + + registry.npmmirror.com/espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz} + name: espree + version: 9.6.1 + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: registry.npmmirror.com/acorn@8.10.0 + acorn-jsx: registry.npmmirror.com/acorn-jsx@5.3.2(acorn@8.10.0) + eslint-visitor-keys: registry.npmmirror.com/eslint-visitor-keys@3.4.3 + dev: true + + registry.npmmirror.com/esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz} + name: esquery + version: 1.5.0 + engines: {node: '>=0.10'} + dependencies: + estraverse: registry.npmmirror.com/estraverse@5.3.0 + dev: true + + registry.npmmirror.com/esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz} + name: esrecurse + version: 4.3.0 + engines: {node: '>=4.0'} + dependencies: + estraverse: registry.npmmirror.com/estraverse@5.3.0 + dev: true + + registry.npmmirror.com/estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz} + name: estraverse + version: 5.3.0 + engines: {node: '>=4.0'} + dev: true + + registry.npmmirror.com/esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz} + name: esutils + version: 2.0.3 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz} + name: fast-deep-equal + version: 3.1.3 + dev: true + + registry.npmmirror.com/fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz} + name: fast-glob + version: 3.3.1 + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': registry.npmmirror.com/@nodelib/fs.stat@2.0.5 + '@nodelib/fs.walk': registry.npmmirror.com/@nodelib/fs.walk@1.2.8 + glob-parent: registry.npmmirror.com/glob-parent@5.1.2 + merge2: registry.npmmirror.com/merge2@1.4.1 + micromatch: registry.npmmirror.com/micromatch@4.0.5 + dev: true + + registry.npmmirror.com/fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz} + name: fast-json-stable-stringify + version: 2.1.0 + dev: true + + registry.npmmirror.com/fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz} + name: fast-levenshtein + version: 2.0.6 + dev: true + + registry.npmmirror.com/fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz} + name: fastq + version: 1.15.0 + dependencies: + reusify: registry.npmmirror.com/reusify@1.0.4 + dev: true + + registry.npmmirror.com/file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz} + name: file-entry-cache + version: 6.0.1 + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: registry.npmmirror.com/flat-cache@3.1.1 + dev: true + + registry.npmmirror.com/fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz} + name: fill-range + version: 7.0.1 + engines: {node: '>=8'} + dependencies: + to-regex-range: registry.npmmirror.com/to-regex-range@5.0.1 + dev: true + + registry.npmmirror.com/find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/find-root/-/find-root-1.1.0.tgz} + name: find-root + version: 1.1.0 + dev: false + + registry.npmmirror.com/flat-cache@3.1.1: + resolution: {integrity: sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/flat-cache/-/flat-cache-3.1.1.tgz} + name: flat-cache + version: 3.1.1 + engines: {node: '>=12.0.0'} + dependencies: + flatted: registry.npmmirror.com/flatted@3.2.9 + keyv: registry.npmmirror.com/keyv@4.5.4 + rimraf: registry.npmmirror.com/rimraf@3.0.2 + dev: true + + registry.npmmirror.com/flatted@3.2.9: + resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/flatted/-/flatted-3.2.9.tgz} + name: flatted + version: 3.2.9 + dev: true + + registry.npmmirror.com/focus-lock@1.0.0: + resolution: {integrity: sha512-a8Ge6cdKh9za/GZR/qtigTAk7SrGore56EFcoMshClsh7FLk1zwszc/ltuMfKhx56qeuyL/jWQ4J4axou0iJ9w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/focus-lock/-/focus-lock-1.0.0.tgz} + name: focus-lock + version: 1.0.0 + engines: {node: '>=10'} + dependencies: + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/follow-redirects@1.15.3: + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.3.tgz} + name: follow-redirects + version: 1.15.3 + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + registry.npmmirror.com/for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz} + name: for-each + version: 0.3.3 + dependencies: + is-callable: registry.npmmirror.com/is-callable@1.2.7 + dev: true + + registry.npmmirror.com/form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz} + name: form-data + version: 4.0.0 + engines: {node: '>= 6'} + dependencies: + asynckit: registry.npmmirror.com/asynckit@0.4.0 + combined-stream: registry.npmmirror.com/combined-stream@1.0.8 + mime-types: registry.npmmirror.com/mime-types@2.1.35 + dev: false + + registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-p9V9nGomS3m6/CALXqv6nFGMuFOxbWsmaOrdmhyQimMIlLl3LC7h7l86wge/Js/8cRu5ktutS/zlzgR7eBOtFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/framer-motion/-/framer-motion-10.16.4.tgz} + id: registry.npmmirror.com/framer-motion/10.16.4 + name: framer-motion + version: 10.16.4 + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + tslib: registry.npmmirror.com/tslib@2.6.2 + optionalDependencies: + '@emotion/is-prop-valid': registry.npmmirror.com/@emotion/is-prop-valid@0.8.8 + dev: false + + registry.npmmirror.com/framesync@6.1.2: + resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/framesync/-/framesync-6.1.2.tgz} + name: framesync + version: 6.1.2 + dependencies: + tslib: registry.npmmirror.com/tslib@2.4.0 + dev: false + + registry.npmmirror.com/fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz} + name: fs.realpath + version: 1.0.0 + dev: true + + registry.npmmirror.com/function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz} + name: function-bind + version: 1.1.2 + dev: true + + registry.npmmirror.com/function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz} + name: function.prototype.name + version: 1.1.6 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + functions-have-names: registry.npmmirror.com/functions-have-names@1.2.3 + dev: true + + registry.npmmirror.com/functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz} + name: functional-red-black-tree + version: 1.0.1 + dev: true + + registry.npmmirror.com/functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz} + name: functions-have-names + version: 1.2.3 + dev: true + + registry.npmmirror.com/get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz} + name: get-intrinsic + version: 1.2.1 + dependencies: + function-bind: registry.npmmirror.com/function-bind@1.1.2 + has: registry.npmmirror.com/has@1.0.4 + has-proto: registry.npmmirror.com/has-proto@1.0.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + dev: true + + registry.npmmirror.com/get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-nonce/-/get-nonce-1.0.1.tgz} + name: get-nonce + version: 1.0.1 + engines: {node: '>=6'} + dev: false + + registry.npmmirror.com/get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz} + name: get-symbol-description + version: 1.0.0 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz} + name: get-tsconfig + version: 4.7.2 + dependencies: + resolve-pkg-maps: registry.npmmirror.com/resolve-pkg-maps@1.0.0 + dev: true + + registry.npmmirror.com/glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz} + name: glob-parent + version: 5.1.2 + engines: {node: '>= 6'} + dependencies: + is-glob: registry.npmmirror.com/is-glob@4.0.3 + dev: true + + registry.npmmirror.com/glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz} + name: glob-parent + version: 6.0.2 + engines: {node: '>=10.13.0'} + dependencies: + is-glob: registry.npmmirror.com/is-glob@4.0.3 + dev: true + + registry.npmmirror.com/glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz} + name: glob-to-regexp + version: 0.4.1 + dev: false + + registry.npmmirror.com/glob@7.1.7: + resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob/-/glob-7.1.7.tgz} + name: glob + version: 7.1.7 + dependencies: + fs.realpath: registry.npmmirror.com/fs.realpath@1.0.0 + inflight: registry.npmmirror.com/inflight@1.0.6 + inherits: registry.npmmirror.com/inherits@2.0.4 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + once: registry.npmmirror.com/once@1.4.0 + path-is-absolute: registry.npmmirror.com/path-is-absolute@1.0.1 + dev: true + + registry.npmmirror.com/glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz} + name: glob + version: 7.2.3 + dependencies: + fs.realpath: registry.npmmirror.com/fs.realpath@1.0.0 + inflight: registry.npmmirror.com/inflight@1.0.6 + inherits: registry.npmmirror.com/inherits@2.0.4 + minimatch: registry.npmmirror.com/minimatch@3.1.2 + once: registry.npmmirror.com/once@1.4.0 + path-is-absolute: registry.npmmirror.com/path-is-absolute@1.0.1 + dev: true + + registry.npmmirror.com/globals@13.23.0: + resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/globals/-/globals-13.23.0.tgz} + name: globals + version: 13.23.0 + engines: {node: '>=8'} + dependencies: + type-fest: registry.npmmirror.com/type-fest@0.20.2 + dev: true + + registry.npmmirror.com/globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/globalthis/-/globalthis-1.0.3.tgz} + name: globalthis + version: 1.0.3 + engines: {node: '>= 0.4'} + dependencies: + define-properties: registry.npmmirror.com/define-properties@1.2.1 + dev: true + + registry.npmmirror.com/globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz} + name: globby + version: 11.1.0 + engines: {node: '>=10'} + dependencies: + array-union: registry.npmmirror.com/array-union@2.1.0 + dir-glob: registry.npmmirror.com/dir-glob@3.0.1 + fast-glob: registry.npmmirror.com/fast-glob@3.3.1 + ignore: registry.npmmirror.com/ignore@5.2.4 + merge2: registry.npmmirror.com/merge2@1.4.1 + slash: registry.npmmirror.com/slash@3.0.0 + dev: true + + registry.npmmirror.com/gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz} + name: gopd + version: 1.0.1 + dependencies: + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz} + name: graceful-fs + version: 4.2.11 + + registry.npmmirror.com/has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz} + name: has-bigints + version: 1.0.2 + dev: true + + registry.npmmirror.com/has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz} + name: has-flag + version: 3.0.0 + engines: {node: '>=4'} + dev: false + + registry.npmmirror.com/has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz} + name: has-flag + version: 4.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz} + name: has-property-descriptors + version: 1.0.0 + dependencies: + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz} + name: has-proto + version: 1.0.1 + engines: {node: '>= 0.4'} + dev: true + + registry.npmmirror.com/has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz} + name: has-symbols + version: 1.0.3 + engines: {node: '>= 0.4'} + dev: true + + registry.npmmirror.com/has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz} + name: has-tostringtag + version: 1.0.0 + engines: {node: '>= 0.4'} + dependencies: + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + dev: true + + registry.npmmirror.com/has@1.0.4: + resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has/-/has-1.0.4.tgz} + name: has + version: 1.0.4 + engines: {node: '>= 0.4.0'} + + registry.npmmirror.com/hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz} + name: hoist-non-react-statics + version: 3.3.2 + dependencies: + react-is: registry.npmmirror.com/react-is@16.13.1 + dev: false + + registry.npmmirror.com/html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz} + name: html-parse-stringify + version: 3.0.1 + dependencies: + void-elements: registry.npmmirror.com/void-elements@3.1.0 + dev: false + + registry.npmmirror.com/httpx@2.3.0: + resolution: {integrity: sha512-DdjwCJ+MauS+V/ta4/DFVGMolHytaS3oEy+Zh2Zzu14NVczqQ0lWexY5Elg52prEJxTzRboBNkSttkXOT/LDCw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/httpx/-/httpx-2.3.0.tgz} + name: httpx + version: 2.3.0 + dependencies: + '@types/node': registry.npmmirror.com/@types/node@20.0.0 + debug: registry.npmmirror.com/debug@4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + registry.npmmirror.com/i18next-fs-backend@2.2.0: + resolution: {integrity: sha512-VOPHhdDX0M/csRqEw+9Ectpf6wvTIg1MZDfAHxc3JKnAlJz7fcZSAKAeyDohOq0xuLx57esYpJopIvBaRb0Bag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/i18next-fs-backend/-/i18next-fs-backend-2.2.0.tgz} + name: i18next-fs-backend + version: 2.2.0 + dev: false + + registry.npmmirror.com/i18next@23.5.1: + resolution: {integrity: sha512-JelYzcaCoFDaa+Ysbfz2JsGAKkrHiMG6S61+HLBUEIPaF40WMwW9hCPymlQGrP+wWawKxKPuSuD71WZscCsWHg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/i18next/-/i18next-23.5.1.tgz} + name: i18next + version: 23.5.1 + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + dev: false + + registry.npmmirror.com/ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz} + name: ignore + version: 4.0.6 + engines: {node: '>= 4'} + dev: true + + registry.npmmirror.com/ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz} + name: ignore + version: 5.2.4 + engines: {node: '>= 4'} + dev: true + + registry.npmmirror.com/immer@10.0.3: + resolution: {integrity: sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/immer/-/immer-10.0.3.tgz} + name: immer + version: 10.0.3 + dev: false + + registry.npmmirror.com/import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz} + name: import-fresh + version: 3.3.0 + engines: {node: '>=6'} + dependencies: + parent-module: registry.npmmirror.com/parent-module@1.0.1 + resolve-from: registry.npmmirror.com/resolve-from@4.0.0 + + registry.npmmirror.com/imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz} + name: imurmurhash + version: 0.1.4 + engines: {node: '>=0.8.19'} + dev: true + + registry.npmmirror.com/inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz} + name: inflight + version: 1.0.6 + dependencies: + once: registry.npmmirror.com/once@1.4.0 + wrappy: registry.npmmirror.com/wrappy@1.0.2 + dev: true + + registry.npmmirror.com/inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz} + name: inherits + version: 2.0.4 + dev: true + + registry.npmmirror.com/ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz} + name: ini + version: 1.3.8 + dev: false + + registry.npmmirror.com/internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.5.tgz} + name: internal-slot + version: 1.0.5 + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + has: registry.npmmirror.com/has@1.0.4 + side-channel: registry.npmmirror.com/side-channel@1.0.4 + dev: true + + registry.npmmirror.com/invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz} + name: invariant + version: 2.2.4 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + dev: false + + registry.npmmirror.com/is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz} + name: is-array-buffer + version: 3.0.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + is-typed-array: registry.npmmirror.com/is-typed-array@1.1.12 + dev: true + + registry.npmmirror.com/is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz} + name: is-arrayish + version: 0.2.1 + dev: false + + registry.npmmirror.com/is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-async-function/-/is-async-function-2.0.0.tgz} + name: is-async-function + version: 2.0.0 + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-bigint/-/is-bigint-1.0.4.tgz} + name: is-bigint + version: 1.0.4 + dependencies: + has-bigints: registry.npmmirror.com/has-bigints@1.0.2 + dev: true + + registry.npmmirror.com/is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz} + name: is-boolean-object + version: 1.1.2 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz} + name: is-callable + version: 1.2.7 + engines: {node: '>= 0.4'} + dev: true + + registry.npmmirror.com/is-core-module@2.13.0: + resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.0.tgz} + name: is-core-module + version: 2.13.0 + dependencies: + has: registry.npmmirror.com/has@1.0.4 + + registry.npmmirror.com/is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz} + name: is-date-object + version: 1.0.5 + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz} + name: is-extglob + version: 2.1.1 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz} + name: is-finalizationregistry + version: 1.0.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + dev: true + + registry.npmmirror.com/is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-generator-function/-/is-generator-function-1.0.10.tgz} + name: is-generator-function + version: 1.0.10 + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz} + name: is-glob + version: 4.0.3 + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: registry.npmmirror.com/is-extglob@2.1.1 + dev: true + + registry.npmmirror.com/is-map@2.0.2: + resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-map/-/is-map-2.0.2.tgz} + name: is-map + version: 2.0.2 + dev: true + + registry.npmmirror.com/is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz} + name: is-negative-zero + version: 2.0.2 + engines: {node: '>= 0.4'} + dev: true + + registry.npmmirror.com/is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-number-object/-/is-number-object-1.0.7.tgz} + name: is-number-object + version: 1.0.7 + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz} + name: is-number + version: 7.0.0 + engines: {node: '>=0.12.0'} + dev: true + + registry.npmmirror.com/is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz} + name: is-regex + version: 1.1.4 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-set@2.0.2: + resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-set/-/is-set-2.0.2.tgz} + name: is-set + version: 2.0.2 + dev: true + + registry.npmmirror.com/is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz} + name: is-shared-array-buffer + version: 1.0.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + dev: true + + registry.npmmirror.com/is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz} + name: is-string + version: 1.0.7 + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-symbol/-/is-symbol-1.0.4.tgz} + name: is-symbol + version: 1.0.4 + engines: {node: '>= 0.4'} + dependencies: + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + dev: true + + registry.npmmirror.com/is-typed-array@1.1.12: + resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.12.tgz} + name: is-typed-array + version: 1.1.12 + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: registry.npmmirror.com/which-typed-array@1.1.11 + dev: true + + registry.npmmirror.com/is-weakmap@2.0.1: + resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.1.tgz} + name: is-weakmap + version: 2.0.1 + dev: true + + registry.npmmirror.com/is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-weakref/-/is-weakref-1.0.2.tgz} + name: is-weakref + version: 1.0.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + dev: true + + registry.npmmirror.com/is-weakset@2.0.2: + resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.2.tgz} + name: is-weakset + version: 2.0.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz} + name: isarray + version: 2.0.5 + dev: true + + registry.npmmirror.com/isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz} + name: isexe + version: 2.0.0 + dev: true + + registry.npmmirror.com/iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz} + name: iterator.prototype + version: 1.1.2 + dependencies: + define-properties: registry.npmmirror.com/define-properties@1.2.1 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + reflect.getprototypeof: registry.npmmirror.com/reflect.getprototypeof@1.0.4 + set-function-name: registry.npmmirror.com/set-function-name@2.0.1 + dev: true + + registry.npmmirror.com/js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz} + name: js-cookie + version: 3.0.5 + engines: {node: '>=14'} + dev: false + + registry.npmmirror.com/js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz} + name: js-tokens + version: 4.0.0 + + registry.npmmirror.com/js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz} + name: js-yaml + version: 4.1.0 + hasBin: true + dependencies: + argparse: registry.npmmirror.com/argparse@2.0.1 + dev: true + + registry.npmmirror.com/json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz} + name: json-buffer + version: 3.0.1 + dev: true + + registry.npmmirror.com/json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz} + name: json-parse-even-better-errors + version: 2.3.1 + dev: false + + registry.npmmirror.com/json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz} + name: json-schema-traverse + version: 0.4.1 + dev: true + + registry.npmmirror.com/json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz} + name: json-stable-stringify-without-jsonify + version: 1.0.1 + dev: true + + registry.npmmirror.com/json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz} + name: json5 + version: 1.0.2 + hasBin: true + dependencies: + minimist: registry.npmmirror.com/minimist@1.2.8 + dev: true + + registry.npmmirror.com/jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz} + name: jsonwebtoken + version: 9.0.2 + engines: {node: '>=12', npm: '>=6'} + dependencies: + jws: registry.npmmirror.com/jws@3.2.2 + lodash.includes: registry.npmmirror.com/lodash.includes@4.3.0 + lodash.isboolean: registry.npmmirror.com/lodash.isboolean@3.0.3 + lodash.isinteger: registry.npmmirror.com/lodash.isinteger@4.0.4 + lodash.isnumber: registry.npmmirror.com/lodash.isnumber@3.0.3 + lodash.isplainobject: registry.npmmirror.com/lodash.isplainobject@4.0.6 + lodash.isstring: registry.npmmirror.com/lodash.isstring@4.0.1 + lodash.once: registry.npmmirror.com/lodash.once@4.1.1 + ms: registry.npmmirror.com/ms@2.1.3 + semver: registry.npmmirror.com/semver@7.5.4 + dev: false + + registry.npmmirror.com/jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz} + name: jsx-ast-utils + version: 3.3.5 + engines: {node: '>=4.0'} + dependencies: + array-includes: registry.npmmirror.com/array-includes@3.1.7 + array.prototype.flat: registry.npmmirror.com/array.prototype.flat@1.3.2 + object.assign: registry.npmmirror.com/object.assign@4.1.4 + object.values: registry.npmmirror.com/object.values@1.1.7 + dev: true + + registry.npmmirror.com/jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jwa/-/jwa-1.4.1.tgz} + name: jwa + version: 1.4.1 + dependencies: + buffer-equal-constant-time: registry.npmmirror.com/buffer-equal-constant-time@1.0.1 + ecdsa-sig-formatter: registry.npmmirror.com/ecdsa-sig-formatter@1.0.11 + safe-buffer: registry.npmmirror.com/safe-buffer@5.2.1 + dev: false + + registry.npmmirror.com/jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jws/-/jws-3.2.2.tgz} + name: jws + version: 3.2.2 + dependencies: + jwa: registry.npmmirror.com/jwa@1.4.1 + safe-buffer: registry.npmmirror.com/safe-buffer@5.2.1 + dev: false + + registry.npmmirror.com/keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz} + name: keyv + version: 4.5.4 + dependencies: + json-buffer: registry.npmmirror.com/json-buffer@3.0.1 + dev: true + + registry.npmmirror.com/kitx@2.1.0: + resolution: {integrity: sha512-C/5v9MtIX7aHGOjwn5BmrrbNkJSf7i0R5mRzmh13GSAdRqQ7bYQo/Su2pTYNylFicqKNTVX3HML9k1u8k51+pQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/kitx/-/kitx-2.1.0.tgz} + name: kitx + version: 2.1.0 + dependencies: + '@types/node': registry.npmmirror.com/@types/node@12.20.55 + dev: false + + registry.npmmirror.com/language-subtag-registry@0.3.22: + resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz} + name: language-subtag-registry + version: 0.3.22 + dev: true + + registry.npmmirror.com/language-tags@1.0.5: + resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/language-tags/-/language-tags-1.0.5.tgz} + name: language-tags + version: 1.0.5 + dependencies: + language-subtag-registry: registry.npmmirror.com/language-subtag-registry@0.3.22 + dev: true + + registry.npmmirror.com/levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz} + name: levn + version: 0.4.1 + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: registry.npmmirror.com/prelude-ls@1.2.1 + type-check: registry.npmmirror.com/type-check@0.4.0 + dev: true + + registry.npmmirror.com/lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz} + name: lines-and-columns + version: 1.2.4 + dev: false + + registry.npmmirror.com/lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.includes/-/lodash.includes-4.3.0.tgz} + name: lodash.includes + version: 4.3.0 + dev: false + + registry.npmmirror.com/lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz} + name: lodash.isboolean + version: 3.0.3 + dev: false + + registry.npmmirror.com/lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz} + name: lodash.isinteger + version: 4.0.4 + dev: false + + registry.npmmirror.com/lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz} + name: lodash.isnumber + version: 3.0.3 + dev: false + + registry.npmmirror.com/lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz} + name: lodash.isplainobject + version: 4.0.6 + dev: false + + registry.npmmirror.com/lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz} + name: lodash.isstring + version: 4.0.1 + dev: false + + registry.npmmirror.com/lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz} + name: lodash.merge + version: 4.6.2 + dev: true + + registry.npmmirror.com/lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz} + name: lodash.mergewith + version: 4.6.2 + dev: false + + registry.npmmirror.com/lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash.once/-/lodash.once-4.1.1.tgz} + name: lodash.once + version: 4.1.1 + dev: false + + registry.npmmirror.com/lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz} + name: lodash + version: 4.17.21 + dev: false + + registry.npmmirror.com/loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz} + name: loose-envify + version: 1.4.0 + hasBin: true + dependencies: + js-tokens: registry.npmmirror.com/js-tokens@4.0.0 + + registry.npmmirror.com/lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz} + name: lru-cache + version: 6.0.0 + engines: {node: '>=10'} + dependencies: + yallist: registry.npmmirror.com/yallist@4.0.0 + + registry.npmmirror.com/memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz} + name: memory-pager + version: 1.5.0 + dev: false + + registry.npmmirror.com/merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz} + name: merge2 + version: 1.4.1 + engines: {node: '>= 8'} + dev: true + + registry.npmmirror.com/micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz} + name: micromatch + version: 4.0.5 + engines: {node: '>=8.6'} + dependencies: + braces: registry.npmmirror.com/braces@3.0.2 + picomatch: registry.npmmirror.com/picomatch@2.3.1 + dev: true + + registry.npmmirror.com/mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz} + name: mime-db + version: 1.52.0 + engines: {node: '>= 0.6'} + dev: false + + registry.npmmirror.com/mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz} + name: mime-types + version: 2.1.35 + engines: {node: '>= 0.6'} + dependencies: + mime-db: registry.npmmirror.com/mime-db@1.52.0 + dev: false + + registry.npmmirror.com/minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz} + name: minimatch + version: 3.1.2 + dependencies: + brace-expansion: registry.npmmirror.com/brace-expansion@1.1.11 + dev: true + + registry.npmmirror.com/minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz} + name: minimist + version: 1.2.8 + dev: true + + registry.npmmirror.com/mongodb-connection-string-url@2.6.0: + resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz} + name: mongodb-connection-string-url + version: 2.6.0 + dependencies: + '@types/whatwg-url': registry.npmmirror.com/@types/whatwg-url@8.2.2 + whatwg-url: registry.npmmirror.com/whatwg-url@11.0.0 + dev: false + + registry.npmmirror.com/mongodb@6.1.0: + resolution: {integrity: sha512-AvzNY0zMkpothZ5mJAaIo2bGDjlJQqqAbn9fvtVgwIIUPEfdrqGxqNjjbuKyrgQxg2EvCmfWdjq+4uj96c0YPw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mongodb/-/mongodb-6.1.0.tgz} + name: mongodb + version: 6.1.0 + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + dependencies: + '@mongodb-js/saslprep': registry.npmmirror.com/@mongodb-js/saslprep@1.1.0 + bson: registry.npmmirror.com/bson@6.1.0 + mongodb-connection-string-url: registry.npmmirror.com/mongodb-connection-string-url@2.6.0 + dev: false + + registry.npmmirror.com/ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz} + name: ms + version: 2.1.2 + + registry.npmmirror.com/ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz} + name: ms + version: 2.1.3 + + registry.npmmirror.com/nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz} + name: nanoid + version: 3.3.6 + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false + + registry.npmmirror.com/natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz} + name: natural-compare + version: 1.4.0 + dev: true + + registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.4)(react-i18next@13.3.0)(react@18.0.0): + resolution: {integrity: sha512-FtnjRMfhlamk8YyeyWqd+pndNL+3er83iMZnH4M4mhiGA93l0+vtBUvuObgOAMHDJGLLB2SS2xOOZq69oiJh7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next-i18next/-/next-i18next-14.0.3.tgz} + id: registry.npmmirror.com/next-i18next/14.0.3 + name: next-i18next + version: 14.0.3 + engines: {node: '>=14'} + peerDependencies: + i18next: ^23.4.6 + next: '>= 12.0.0' + react: '>= 17.0.2' + react-i18next: ^13.2.1 + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + '@types/hoist-non-react-statics': registry.npmmirror.com/@types/hoist-non-react-statics@3.3.3 + core-js: registry.npmmirror.com/core-js@3.33.0 + hoist-non-react-statics: registry.npmmirror.com/hoist-non-react-statics@3.3.2 + i18next: registry.npmmirror.com/i18next@23.5.1 + i18next-fs-backend: registry.npmmirror.com/i18next-fs-backend@2.2.0 + next: registry.npmmirror.com/next@13.5.4(react-dom@18.0.0)(react@18.0.0) + react: registry.npmmirror.com/react@18.0.0 + react-i18next: registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0) + dev: false + + registry.npmmirror.com/next@13.5.4(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next/-/next-13.5.4.tgz} + id: registry.npmmirror.com/next/13.5.4 + name: next + version: 13.5.4 + engines: {node: '>=16.14.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': registry.npmmirror.com/@next/env@13.5.4 + '@swc/helpers': registry.npmmirror.com/@swc/helpers@0.5.2 + busboy: registry.npmmirror.com/busboy@1.6.0 + caniuse-lite: registry.npmmirror.com/caniuse-lite@1.0.30001549 + postcss: registry.npmmirror.com/postcss@8.4.31 + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + styled-jsx: registry.npmmirror.com/styled-jsx@5.1.1(react@18.0.0) + watchpack: registry.npmmirror.com/watchpack@2.4.0 + optionalDependencies: + '@next/swc-darwin-arm64': registry.npmmirror.com/@next/swc-darwin-arm64@13.5.4 + '@next/swc-darwin-x64': registry.npmmirror.com/@next/swc-darwin-x64@13.5.4 + '@next/swc-linux-arm64-gnu': registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.4 + '@next/swc-linux-arm64-musl': registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.4 + '@next/swc-linux-x64-gnu': registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.4 + '@next/swc-linux-x64-musl': registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.4 + '@next/swc-win32-arm64-msvc': registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.4 + '@next/swc-win32-ia32-msvc': registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.4 + '@next/swc-win32-x64-msvc': registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false + + registry.npmmirror.com/nprogress@0.2.0: + resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz} + name: nprogress + version: 0.2.0 + dev: false + + registry.npmmirror.com/object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz} + name: object-assign + version: 4.1.1 + engines: {node: '>=0.10.0'} + + registry.npmmirror.com/object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz} + name: object-inspect + version: 1.12.3 + dev: true + + registry.npmmirror.com/object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz} + name: object-keys + version: 1.1.1 + engines: {node: '>= 0.4'} + dev: true + + registry.npmmirror.com/object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object.assign/-/object.assign-4.1.4.tgz} + name: object.assign + version: 4.1.4 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + object-keys: registry.npmmirror.com/object-keys@1.1.1 + dev: true + + registry.npmmirror.com/object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object.entries/-/object.entries-1.1.7.tgz} + name: object.entries + version: 1.1.7 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object.fromentries/-/object.fromentries-2.0.7.tgz} + name: object.fromentries + version: 2.0.7 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object.groupby/-/object.groupby-1.0.1.tgz} + name: object.groupby + version: 1.0.1 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + dev: true + + registry.npmmirror.com/object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object.hasown/-/object.hasown-1.1.3.tgz} + name: object.hasown + version: 1.1.3 + dependencies: + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object.values/-/object.values-1.1.7.tgz} + name: object.values + version: 1.1.7 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/once/-/once-1.4.0.tgz} + name: once + version: 1.4.0 + dependencies: + wrappy: registry.npmmirror.com/wrappy@1.0.2 + dev: true + + registry.npmmirror.com/optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz} + name: optionator + version: 0.9.3 + engines: {node: '>= 0.8.0'} + dependencies: + '@aashutoshrathi/word-wrap': registry.npmmirror.com/@aashutoshrathi/word-wrap@1.2.6 + deep-is: registry.npmmirror.com/deep-is@0.1.4 + fast-levenshtein: registry.npmmirror.com/fast-levenshtein@2.0.6 + levn: registry.npmmirror.com/levn@0.4.1 + prelude-ls: registry.npmmirror.com/prelude-ls@1.2.1 + type-check: registry.npmmirror.com/type-check@0.4.0 + dev: true + + registry.npmmirror.com/parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz} + name: parent-module + version: 1.0.1 + engines: {node: '>=6'} + dependencies: + callsites: registry.npmmirror.com/callsites@3.1.0 + + registry.npmmirror.com/parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz} + name: parse-json + version: 5.2.0 + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': registry.npmmirror.com/@babel/code-frame@7.22.13 + error-ex: registry.npmmirror.com/error-ex@1.3.2 + json-parse-even-better-errors: registry.npmmirror.com/json-parse-even-better-errors@2.3.1 + lines-and-columns: registry.npmmirror.com/lines-and-columns@1.2.4 + dev: false + + registry.npmmirror.com/path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz} + name: path-is-absolute + version: 1.0.1 + engines: {node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz} + name: path-key + version: 3.1.1 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz} + name: path-parse + version: 1.0.7 + + registry.npmmirror.com/path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz} + name: path-type + version: 4.0.0 + engines: {node: '>=8'} + + registry.npmmirror.com/picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz} + name: picocolors + version: 1.0.0 + dev: false + + registry.npmmirror.com/picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz} + name: picomatch + version: 2.3.1 + engines: {node: '>=8.6'} + dev: true + + registry.npmmirror.com/postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/postcss/-/postcss-8.4.31.tgz} + name: postcss + version: 8.4.31 + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: registry.npmmirror.com/nanoid@3.3.6 + picocolors: registry.npmmirror.com/picocolors@1.0.0 + source-map-js: registry.npmmirror.com/source-map-js@1.0.2 + dev: false + + registry.npmmirror.com/prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz} + name: prelude-ls + version: 1.2.1 + engines: {node: '>= 0.8.0'} + dev: true + + registry.npmmirror.com/prettier@3.0.3: + resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prettier/-/prettier-3.0.3.tgz} + name: prettier + version: 3.0.3 + engines: {node: '>=14'} + hasBin: true + dev: true + + registry.npmmirror.com/progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz} + name: progress + version: 2.0.3 + engines: {node: '>=0.4.0'} + dev: true + + registry.npmmirror.com/prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz} + name: prop-types + version: 15.8.1 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + object-assign: registry.npmmirror.com/object-assign@4.1.1 + react-is: registry.npmmirror.com/react-is@16.13.1 + + registry.npmmirror.com/proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz} + name: proxy-from-env + version: 1.1.0 + dev: false + + registry.npmmirror.com/punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz} + name: punycode + version: 2.3.0 + engines: {node: '>=6'} + + registry.npmmirror.com/qrcode.react@3.1.0(react@18.0.0): + resolution: {integrity: sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/qrcode.react/-/qrcode.react-3.1.0.tgz} + id: registry.npmmirror.com/qrcode.react/3.1.0 + name: qrcode.react + version: 3.1.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz} + name: queue-microtask + version: 1.2.3 + dev: true + + registry.npmmirror.com/react-clientside-effect@1.2.6(react@18.0.0): + resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz} + id: registry.npmmirror.com/react-clientside-effect/1.2.6 + name: react-clientside-effect + version: 1.2.6 + peerDependencies: + react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/react-dom@18.0.0(react@18.0.0): + resolution: {integrity: sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-dom/-/react-dom-18.0.0.tgz} + id: registry.npmmirror.com/react-dom/18.0.0 + name: react-dom + version: 18.0.0 + peerDependencies: + react: ^18.0.0 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + react: registry.npmmirror.com/react@18.0.0 + scheduler: registry.npmmirror.com/scheduler@0.21.0 + dev: false + + registry.npmmirror.com/react-fast-compare@3.2.2: + resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz} + name: react-fast-compare + version: 3.2.2 + dev: false + + registry.npmmirror.com/react-focus-lock@2.9.6(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-B7gYnCjHNrNYwY2juS71dHbf0+UpXXojt02svxybj8N5bxceAkzPChKEncHuratjUHkIFNCn06k2qj1DRlzTug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-focus-lock/-/react-focus-lock-2.9.6.tgz} + id: registry.npmmirror.com/react-focus-lock/2.9.6 + name: react-focus-lock + version: 2.9.6 + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + focus-lock: registry.npmmirror.com/focus-lock@1.0.0 + prop-types: registry.npmmirror.com/prop-types@15.8.1 + react: registry.npmmirror.com/react@18.0.0 + react-clientside-effect: registry.npmmirror.com/react-clientside-effect@1.2.6(react@18.0.0) + use-callback-ref: registry.npmmirror.com/use-callback-ref@1.3.0(@types/react@18.0.0)(react@18.0.0) + use-sidecar: registry.npmmirror.com/use-sidecar@1.1.2(@types/react@18.0.0)(react@18.0.0) + dev: false + + registry.npmmirror.com/react-hook-form@7.47.0(react@18.0.0): + resolution: {integrity: sha512-F/TroLjTICipmHeFlMrLtNLceO2xr1jU3CyiNla5zdwsGUGu2UOxxR4UyJgLlhMwLW/Wzp4cpJ7CPfgJIeKdSg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-hook-form/-/react-hook-form-7.47.0.tgz} + id: registry.npmmirror.com/react-hook-form/7.47.0 + name: react-hook-form + version: 7.47.0 + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-FlR9xjYHSPIJfQspEmkN0yOlxgRyNuiJKJ8gCaZH08UJ7SZHG+VrptEPcpEMEchjNoCOZdKcvJ3PnmHEZhkeXg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-i18next/-/react-i18next-13.3.0.tgz} + id: registry.npmmirror.com/react-i18next/13.3.0 + name: react-i18next + version: 13.3.0 + peerDependencies: + i18next: '>= 23.2.3' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + html-parse-stringify: registry.npmmirror.com/html-parse-stringify@3.0.1 + i18next: registry.npmmirror.com/i18next@23.5.1 + react: registry.npmmirror.com/react@18.0.0 + react-dom: registry.npmmirror.com/react-dom@18.0.0(react@18.0.0) + dev: false + + registry.npmmirror.com/react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz} + name: react-is + version: 16.13.1 + + registry.npmmirror.com/react-remove-scroll-bar@2.3.4(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz} + id: registry.npmmirror.com/react-remove-scroll-bar/2.3.4 + name: react-remove-scroll-bar + version: 2.3.4 + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + react: registry.npmmirror.com/react@18.0.0 + react-style-singleton: registry.npmmirror.com/react-style-singleton@2.2.1(@types/react@18.0.0)(react@18.0.0) + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/react-remove-scroll@2.5.7(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz} + id: registry.npmmirror.com/react-remove-scroll/2.5.7 + name: react-remove-scroll + version: 2.5.7 + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + react: registry.npmmirror.com/react@18.0.0 + react-remove-scroll-bar: registry.npmmirror.com/react-remove-scroll-bar@2.3.4(@types/react@18.0.0)(react@18.0.0) + react-style-singleton: registry.npmmirror.com/react-style-singleton@2.2.1(@types/react@18.0.0)(react@18.0.0) + tslib: registry.npmmirror.com/tslib@2.6.2 + use-callback-ref: registry.npmmirror.com/use-callback-ref@1.3.0(@types/react@18.0.0)(react@18.0.0) + use-sidecar: registry.npmmirror.com/use-sidecar@1.1.2(@types/react@18.0.0)(react@18.0.0) + dev: false + + registry.npmmirror.com/react-style-singleton@2.2.1(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz} + id: registry.npmmirror.com/react-style-singleton/2.2.1 + name: react-style-singleton + version: 2.2.1 + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + get-nonce: registry.npmmirror.com/get-nonce@1.0.1 + invariant: registry.npmmirror.com/invariant@2.2.4 + react: registry.npmmirror.com/react@18.0.0 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/react@18.0.0: + resolution: {integrity: sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react/-/react-18.0.0.tgz} + name: react + version: 18.0.0 + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + dev: false + + registry.npmmirror.com/reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz} + name: reflect.getprototypeof + version: 1.0.4 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + globalthis: registry.npmmirror.com/globalthis@1.0.3 + which-builtin-type: registry.npmmirror.com/which-builtin-type@1.1.3 + dev: true + + registry.npmmirror.com/regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz} + name: regenerator-runtime + version: 0.14.0 + + registry.npmmirror.com/regexp.prototype.flags@1.5.1: + resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz} + name: regexp.prototype.flags + version: 1.5.1 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + set-function-name: registry.npmmirror.com/set-function-name@2.0.1 + dev: true + + registry.npmmirror.com/regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/regexpp/-/regexpp-3.2.0.tgz} + name: regexpp + version: 3.2.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz} + name: resolve-from + version: 4.0.0 + engines: {node: '>=4'} + + registry.npmmirror.com/resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz} + name: resolve-pkg-maps + version: 1.0.0 + dev: true + + registry.npmmirror.com/resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz} + name: resolve + version: 1.22.8 + hasBin: true + dependencies: + is-core-module: registry.npmmirror.com/is-core-module@2.13.0 + path-parse: registry.npmmirror.com/path-parse@1.0.7 + supports-preserve-symlinks-flag: registry.npmmirror.com/supports-preserve-symlinks-flag@1.0.0 + + registry.npmmirror.com/resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve/-/resolve-2.0.0-next.5.tgz} + name: resolve + version: 2.0.0-next.5 + hasBin: true + dependencies: + is-core-module: registry.npmmirror.com/is-core-module@2.13.0 + path-parse: registry.npmmirror.com/path-parse@1.0.7 + supports-preserve-symlinks-flag: registry.npmmirror.com/supports-preserve-symlinks-flag@1.0.0 + dev: true + + registry.npmmirror.com/reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz} + name: reusify + version: 1.0.4 + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + registry.npmmirror.com/rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz} + name: rimraf + version: 3.0.2 + hasBin: true + dependencies: + glob: registry.npmmirror.com/glob@7.2.3 + dev: true + + registry.npmmirror.com/run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz} + name: run-parallel + version: 1.2.0 + dependencies: + queue-microtask: registry.npmmirror.com/queue-microtask@1.2.3 + dev: true + + registry.npmmirror.com/safe-array-concat@1.0.1: + resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz} + name: safe-array-concat + version: 1.0.1 + engines: {node: '>=0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + isarray: registry.npmmirror.com/isarray@2.0.5 + dev: true + + registry.npmmirror.com/safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz} + name: safe-buffer + version: 5.2.1 + dev: false + + registry.npmmirror.com/safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz} + name: safe-regex-test + version: 1.0.0 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + is-regex: registry.npmmirror.com/is-regex@1.1.4 + dev: true + + registry.npmmirror.com/sax@1.3.0: + resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sax/-/sax-1.3.0.tgz} + name: sax + version: 1.3.0 + dev: false + + registry.npmmirror.com/scheduler@0.21.0: + resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/scheduler/-/scheduler-0.21.0.tgz} + name: scheduler + version: 0.21.0 + dependencies: + loose-envify: registry.npmmirror.com/loose-envify@1.4.0 + dev: false + + registry.npmmirror.com/semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz} + name: semver + version: 6.3.1 + hasBin: true + dev: true + + registry.npmmirror.com/semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz} + name: semver + version: 7.5.4 + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: registry.npmmirror.com/lru-cache@6.0.0 + + registry.npmmirror.com/set-function-name@2.0.1: + resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.1.tgz} + name: set-function-name + version: 2.0.1 + engines: {node: '>= 0.4'} + dependencies: + define-data-property: registry.npmmirror.com/define-data-property@1.1.1 + functions-have-names: registry.npmmirror.com/functions-have-names@1.2.3 + has-property-descriptors: registry.npmmirror.com/has-property-descriptors@1.0.0 + dev: true + + registry.npmmirror.com/shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz} + name: shebang-command + version: 2.0.0 + engines: {node: '>=8'} + dependencies: + shebang-regex: registry.npmmirror.com/shebang-regex@3.0.0 + dev: true + + registry.npmmirror.com/shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz} + name: shebang-regex + version: 3.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz} + name: side-channel + version: 1.0.4 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + object-inspect: registry.npmmirror.com/object-inspect@1.12.3 + dev: true + + registry.npmmirror.com/slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz} + name: slash + version: 3.0.0 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/sm3@1.0.3: + resolution: {integrity: sha512-KyFkIfr8QBlFG3uc3NaljaXdYcsbRy1KrSfc4tsQV8jW68jAktGeOcifu530Vx/5LC+PULHT0Rv8LiI8Gw+c1g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sm3/-/sm3-1.0.3.tgz} + name: sm3 + version: 1.0.3 + dev: false + + registry.npmmirror.com/source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz} + name: source-map-js + version: 1.0.2 + engines: {node: '>=0.10.0'} + dev: false + + registry.npmmirror.com/source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz} + name: source-map + version: 0.5.7 + engines: {node: '>=0.10.0'} + dev: false + + registry.npmmirror.com/sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz} + name: sparse-bitfield + version: 3.0.3 + dependencies: + memory-pager: registry.npmmirror.com/memory-pager@1.5.0 + dev: false + + registry.npmmirror.com/streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz} + name: streamsearch + version: 1.1.0 + engines: {node: '>=10.0.0'} + dev: false + + registry.npmmirror.com/string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz} + name: string.prototype.matchall + version: 4.0.10 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + internal-slot: registry.npmmirror.com/internal-slot@1.0.5 + regexp.prototype.flags: registry.npmmirror.com/regexp.prototype.flags@1.5.1 + set-function-name: registry.npmmirror.com/set-function-name@2.0.1 + side-channel: registry.npmmirror.com/side-channel@1.0.4 + dev: true + + registry.npmmirror.com/string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz} + name: string.prototype.trim + version: 1.2.8 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz} + name: string.prototype.trimend + version: 1.0.7 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz} + name: string.prototype.trimstart + version: 1.0.7 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + define-properties: registry.npmmirror.com/define-properties@1.2.1 + es-abstract: registry.npmmirror.com/es-abstract@1.22.2 + dev: true + + registry.npmmirror.com/strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz} + name: strip-ansi + version: 6.0.1 + engines: {node: '>=8'} + dependencies: + ansi-regex: registry.npmmirror.com/ansi-regex@5.0.1 + dev: true + + registry.npmmirror.com/strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-bom/-/strip-bom-3.0.0.tgz} + name: strip-bom + version: 3.0.0 + engines: {node: '>=4'} + dev: true + + registry.npmmirror.com/strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz} + name: strip-json-comments + version: 3.1.1 + engines: {node: '>=8'} + dev: true + + registry.npmmirror.com/styled-jsx@5.1.1(react@18.0.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/styled-jsx/-/styled-jsx-5.1.1.tgz} + id: registry.npmmirror.com/styled-jsx/5.1.1 + name: styled-jsx + version: 5.1.1 + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + dependencies: + client-only: registry.npmmirror.com/client-only@0.0.1 + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/stylis/-/stylis-4.2.0.tgz} + name: stylis + version: 4.2.0 + dev: false + + registry.npmmirror.com/supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz} + name: supports-color + version: 5.5.0 + engines: {node: '>=4'} + dependencies: + has-flag: registry.npmmirror.com/has-flag@3.0.0 + dev: false + + registry.npmmirror.com/supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz} + name: supports-color + version: 7.2.0 + engines: {node: '>=8'} + dependencies: + has-flag: registry.npmmirror.com/has-flag@4.0.0 + dev: true + + registry.npmmirror.com/supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz} + name: supports-preserve-symlinks-flag + version: 1.0.0 + engines: {node: '>= 0.4'} + + registry.npmmirror.com/tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tapable/-/tapable-2.2.1.tgz} + name: tapable + version: 2.2.1 + engines: {node: '>=6'} + dev: true + + registry.npmmirror.com/text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz} + name: text-table + version: 0.2.0 + dev: true + + registry.npmmirror.com/tiny-invariant@1.3.1: + resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz} + name: tiny-invariant + version: 1.3.1 + dev: false + + registry.npmmirror.com/to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz} + name: to-fast-properties + version: 2.0.0 + engines: {node: '>=4'} + dev: false + + registry.npmmirror.com/to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz} + name: to-regex-range + version: 5.0.1 + engines: {node: '>=8.0'} + dependencies: + is-number: registry.npmmirror.com/is-number@7.0.0 + dev: true + + registry.npmmirror.com/toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz} + name: toggle-selection + version: 1.0.6 + dev: false + + registry.npmmirror.com/tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz} + name: tr46 + version: 3.0.0 + engines: {node: '>=12'} + dependencies: + punycode: registry.npmmirror.com/punycode@2.3.0 + dev: false + + registry.npmmirror.com/ts-api-utils@1.0.3(typescript@5.0.2): + resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz} + id: registry.npmmirror.com/ts-api-utils/1.0.3 + name: ts-api-utils + version: 1.0.3 + engines: {node: '>=16.13.0'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: registry.npmmirror.com/typescript@5.0.2 + dev: true + + registry.npmmirror.com/tsconfig-paths@3.14.2: + resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz} + name: tsconfig-paths + version: 3.14.2 + dependencies: + '@types/json5': registry.npmmirror.com/@types/json5@0.0.29 + json5: registry.npmmirror.com/json5@1.0.2 + minimist: registry.npmmirror.com/minimist@1.2.8 + strip-bom: registry.npmmirror.com/strip-bom@3.0.0 + dev: true + + registry.npmmirror.com/tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tslib/-/tslib-2.4.0.tgz} + name: tslib + version: 2.4.0 + dev: false + + registry.npmmirror.com/tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tslib/-/tslib-2.6.2.tgz} + name: tslib + version: 2.6.2 + dev: false + + registry.npmmirror.com/type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz} + name: type-check + version: 0.4.0 + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: registry.npmmirror.com/prelude-ls@1.2.1 + dev: true + + registry.npmmirror.com/type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz} + name: type-fest + version: 0.20.2 + engines: {node: '>=10'} + dev: true + + registry.npmmirror.com/typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz} + name: typed-array-buffer + version: 1.0.0 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 + is-typed-array: registry.npmmirror.com/is-typed-array@1.1.12 + dev: true + + registry.npmmirror.com/typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz} + name: typed-array-byte-length + version: 1.0.0 + engines: {node: '>= 0.4'} + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + for-each: registry.npmmirror.com/for-each@0.3.3 + has-proto: registry.npmmirror.com/has-proto@1.0.1 + is-typed-array: registry.npmmirror.com/is-typed-array@1.1.12 + dev: true + + registry.npmmirror.com/typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz} + name: typed-array-byte-offset + version: 1.0.0 + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: registry.npmmirror.com/available-typed-arrays@1.0.5 + call-bind: registry.npmmirror.com/call-bind@1.0.2 + for-each: registry.npmmirror.com/for-each@0.3.3 + has-proto: registry.npmmirror.com/has-proto@1.0.1 + is-typed-array: registry.npmmirror.com/is-typed-array@1.1.12 + dev: true + + registry.npmmirror.com/typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.4.tgz} + name: typed-array-length + version: 1.0.4 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + for-each: registry.npmmirror.com/for-each@0.3.3 + is-typed-array: registry.npmmirror.com/is-typed-array@1.1.12 + dev: true + + registry.npmmirror.com/typescript@5.0.2: + resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/typescript/-/typescript-5.0.2.tgz} + name: typescript + version: 5.0.2 + engines: {node: '>=12.20'} + hasBin: true + dev: true + + registry.npmmirror.com/unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz} + name: unbox-primitive + version: 1.0.2 + dependencies: + call-bind: registry.npmmirror.com/call-bind@1.0.2 + has-bigints: registry.npmmirror.com/has-bigints@1.0.2 + has-symbols: registry.npmmirror.com/has-symbols@1.0.3 + which-boxed-primitive: registry.npmmirror.com/which-boxed-primitive@1.0.2 + dev: true + + registry.npmmirror.com/uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz} + name: uri-js + version: 4.4.1 + dependencies: + punycode: registry.npmmirror.com/punycode@2.3.0 + dev: true + + registry.npmmirror.com/use-callback-ref@1.3.0(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz} + id: registry.npmmirror.com/use-callback-ref/1.3.0 + name: use-callback-ref + version: 1.3.0 + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + react: registry.npmmirror.com/react@18.0.0 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/use-sidecar@1.1.2(@types/react@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/use-sidecar/-/use-sidecar-1.1.2.tgz} + id: registry.npmmirror.com/use-sidecar/1.1.2 + name: use-sidecar + version: 1.1.2 + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + detect-node-es: registry.npmmirror.com/detect-node-es@1.1.0 + react: registry.npmmirror.com/react@18.0.0 + tslib: registry.npmmirror.com/tslib@2.6.2 + dev: false + + registry.npmmirror.com/use-sync-external-store@1.2.0(react@18.0.0): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz} + id: registry.npmmirror.com/use-sync-external-store/1.2.0 + name: use-sync-external-store + version: 1.2.0 + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: registry.npmmirror.com/react@18.0.0 + dev: false + + registry.npmmirror.com/uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz} + name: uuid + version: 9.0.1 + hasBin: true + dev: false + + registry.npmmirror.com/v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz} + name: v8-compile-cache + version: 2.4.0 + dev: true + + registry.npmmirror.com/void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz} + name: void-elements + version: 3.1.0 + engines: {node: '>=0.10.0'} + dev: false + + registry.npmmirror.com/watchpack@2.4.0: + resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/watchpack/-/watchpack-2.4.0.tgz} + name: watchpack + version: 2.4.0 + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: registry.npmmirror.com/glob-to-regexp@0.4.1 + graceful-fs: registry.npmmirror.com/graceful-fs@4.2.11 + dev: false + + registry.npmmirror.com/webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz} + name: webidl-conversions + version: 7.0.0 + engines: {node: '>=12'} + dev: false + + registry.npmmirror.com/whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz} + name: whatwg-url + version: 11.0.0 + engines: {node: '>=12'} + dependencies: + tr46: registry.npmmirror.com/tr46@3.0.0 + webidl-conversions: registry.npmmirror.com/webidl-conversions@7.0.0 + dev: false + + registry.npmmirror.com/which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz} + name: which-boxed-primitive + version: 1.0.2 + dependencies: + is-bigint: registry.npmmirror.com/is-bigint@1.0.4 + is-boolean-object: registry.npmmirror.com/is-boolean-object@1.1.2 + is-number-object: registry.npmmirror.com/is-number-object@1.0.7 + is-string: registry.npmmirror.com/is-string@1.0.7 + is-symbol: registry.npmmirror.com/is-symbol@1.0.4 + dev: true + + registry.npmmirror.com/which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz} + name: which-builtin-type + version: 1.1.3 + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: registry.npmmirror.com/function.prototype.name@1.1.6 + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + is-async-function: registry.npmmirror.com/is-async-function@2.0.0 + is-date-object: registry.npmmirror.com/is-date-object@1.0.5 + is-finalizationregistry: registry.npmmirror.com/is-finalizationregistry@1.0.2 + is-generator-function: registry.npmmirror.com/is-generator-function@1.0.10 + is-regex: registry.npmmirror.com/is-regex@1.1.4 + is-weakref: registry.npmmirror.com/is-weakref@1.0.2 + isarray: registry.npmmirror.com/isarray@2.0.5 + which-boxed-primitive: registry.npmmirror.com/which-boxed-primitive@1.0.2 + which-collection: registry.npmmirror.com/which-collection@1.0.1 + which-typed-array: registry.npmmirror.com/which-typed-array@1.1.11 + dev: true + + registry.npmmirror.com/which-collection@1.0.1: + resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/which-collection/-/which-collection-1.0.1.tgz} + name: which-collection + version: 1.0.1 + dependencies: + is-map: registry.npmmirror.com/is-map@2.0.2 + is-set: registry.npmmirror.com/is-set@2.0.2 + is-weakmap: registry.npmmirror.com/is-weakmap@2.0.1 + is-weakset: registry.npmmirror.com/is-weakset@2.0.2 + dev: true + + registry.npmmirror.com/which-typed-array@1.1.11: + resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.11.tgz} + name: which-typed-array + version: 1.1.11 + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: registry.npmmirror.com/available-typed-arrays@1.0.5 + call-bind: registry.npmmirror.com/call-bind@1.0.2 + for-each: registry.npmmirror.com/for-each@0.3.3 + gopd: registry.npmmirror.com/gopd@1.0.1 + has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 + dev: true + + registry.npmmirror.com/which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/which/-/which-2.0.2.tgz} + name: which + version: 2.0.2 + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: registry.npmmirror.com/isexe@2.0.0 + dev: true + + registry.npmmirror.com/wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz} + name: wrappy + version: 1.0.2 + dev: true + + registry.npmmirror.com/xml2js@0.4.23: + resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xml2js/-/xml2js-0.4.23.tgz} + name: xml2js + version: 0.4.23 + engines: {node: '>=4.0.0'} + dependencies: + sax: registry.npmmirror.com/sax@1.3.0 + xmlbuilder: registry.npmmirror.com/xmlbuilder@11.0.1 + dev: false + + registry.npmmirror.com/xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz} + name: xmlbuilder + version: 11.0.1 + engines: {node: '>=4.0'} + dev: false + + registry.npmmirror.com/yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz} + name: yallist + version: 4.0.0 + + registry.npmmirror.com/yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz} + name: yaml + version: 1.10.2 + engines: {node: '>= 6'} + dev: false + + registry.npmmirror.com/zustand@4.4.3(@types/react@18.0.0)(immer@10.0.3)(react@18.0.0): + resolution: {integrity: sha512-oRy+X3ZazZvLfmv6viIaQmtLOMeij1noakIsK/Y47PWYhT8glfXzQ4j0YcP5i0P0qI1A4rIB//SGROGyZhx91A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/zustand/-/zustand-4.4.3.tgz} + id: registry.npmmirror.com/zustand/4.4.3 + name: zustand + version: 4.4.3 + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + immer: registry.npmmirror.com/immer@10.0.3 + react: registry.npmmirror.com/react@18.0.0 + use-sync-external-store: registry.npmmirror.com/use-sync-external-store@1.2.0(react@18.0.0) + dev: false diff --git a/service/license/public/favicon.ico b/service/license/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..aaf5a412ae67e11d07dc29ffca6ba993b3adc080 GIT binary patch literal 15086 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 OcAGw>%#-py>;D6Ci;7AB literal 0 HcmV?d00001 diff --git a/service/license/public/images/background.svg b/service/license/public/images/background.svg new file mode 100644 index 00000000000..8b3de7be43f --- /dev/null +++ b/service/license/public/images/background.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/license/public/images/empty.svg b/service/license/public/images/empty.svg new file mode 100644 index 00000000000..f213a801161 --- /dev/null +++ b/service/license/public/images/empty.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/service/license/public/images/sealos-title.png b/service/license/public/images/sealos-title.png new file mode 100644 index 0000000000000000000000000000000000000000..c2e7789a8d347a02be391635f9dc6cc72a92ffb9 GIT binary patch literal 54072 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]MEb4>wq`EA(FscmB&x4BT*(xs=6)WJnV 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 \ No newline at end of file diff --git a/service/license/public/locales/en/common.json b/service/license/public/locales/en/common.json new file mode 100644 index 00000000000..436a19a8921 --- /dev/null +++ b/service/license/public/locales/en/common.json @@ -0,0 +1,94 @@ +{ + "Cost Center": "Cost Center", + "Laf on Sealos": "Laf on Sealos", + "App Launchpad": "App Launchpad", + "Database": "Database", + "Sealos Document": "Sealos Document", + "Terminal": "Terminal", + "More Apps": "More Apps", + "Message Center": "Message Center", + "Have Read": "Have read", + "Unread": "Unread", + "Read All": "Read All", + "Username": "Username", + "Log Out": "Log Out", + "Log In": "Log In", + "Password Login": "with Password", + "Verification Code Login": "with Phone", + "Loading": "Loading", + "From": "From", + "Balance": "Balance", + "password tips": "Password must be 8 characters or more", + "username tips": "Username must be 3-16 characters, including letters, numbers", + "Password": "Password", + "Verify password": "Verify password", + "verify code tips": "6-digit Verification Code", + "phone number tips": "Phone Number", + "Invalid phone number": "Invalid phone number", + "Invalid username or password": "Invalid username or password", + "Invalid verification code": "Invalid verification code", + "Get code failed": "Get code failed", + "Read and agree": "Please read and agree to the agreement below", + "agree policy": "I have read and agree to the", + "Service Agreement": "Service Agreement", + "and": "and", + "Privacy Policy": "Privacy Policy", + "Get Code": "verification", + "Total Amount": "Total Amount", + "Payment Result": "Payment Result", + "Payment Successful": "Payment Successful", + "In Payment": "In Payment ...", + "Bonus": "Bonus", + "Select Amount": "Select Amount", + "View Discount Rules": "View recharge discount rules.", + "Payment Status": "Payment Status", + "Scan with WeChat": "Scan with WeChat", + "Charge": "Charge", + "Order Number": "Order Number", + "Confirm": "Confirm", + "Login to your account": "Login to your account", + "Abdication": "Abdication", + "Team": "Team", + "Member List": "Member List", + "Created Time": "Created Time", + "Create Team": "Create Team", + "Name of Team": "Name of Team", + "Dissolve Team": "Dissovle Team", + "Invaild Name of Team": "Dissovle Team", + "Manage Team": "Manage Team", + "Default Team": "Default", + "private team ID of user": "private team ID of user", + "Invite Member": "Invite Member", + "Handle": "Handle", + "Reject": "Reject", + "Accept": "Accept", + "Cancel": "Cancel", + "Quit": "Quit", + "Remove": "Remove", + "Warning": "Warning", + "User Name": "User Name", + "Access": "Access", + "In Time": "In Time", + "Status": "Status", + "Operating": "Operating", + "Waiting": "Waiting", + "Added": "Added", + "Invaild Context": "You need switch to other team for handling", + "Remove Member Tips": "Determine that you want to remove the member?", + "Invalid User ID": "Invalid User ID", + "The invited user must be others": "The invited user must be others", + "Dissovle Tips": "Dissolving the team will clear all resources. Are you sure you want to disband", + "Enter Confirm.": "Please enter {{value}} to confirm", + "Accept Invitation": "Accept Invitation", + "Recive Tips": "{{managerName}} invite you join in {{teamName}} as {{role}}", + "pay with stripe": "Pay With Stripe", + "pay with wechat": "Pay With Wechat", + "License Buy": "License Buy", + "Purchase History": "Purchase History", + "Purchase License": "Purchase License", + "Remaining Time": "Remaining Time: ", + "Please read and agree to the agreement": "Please read and agree to the agreement", + "Purchase Link Error": "Purchase Link Error", + "You have not purchased the License": "You have not purchased the License", + "App Info": "App Info" +} \ No newline at end of file diff --git a/service/license/public/locales/zh/common.json b/service/license/public/locales/zh/common.json new file mode 100644 index 00000000000..acf40eb1d84 --- /dev/null +++ b/service/license/public/locales/zh/common.json @@ -0,0 +1,88 @@ +{ + "More Apps": "更多应用", + "Message Center": "消息中心", + "Have Read": "已读", + "Unread": "未读", + "Read All": "全部已读", + "Username": "用户名", + "Password Login": "密码登录", + "Verification Code Login": "手机号登录", + "Password": "密码", + "Log In": "登录", + "Loading": "加载中", + "Log Out": "退出账号", + "From": "来自", + "Balance": "余额", + "verify code tips": "6位验证码", + "phone number tips": "手机号码", + "password tips": "密码为8位以上字符", + "username tips": "用户名为3-16位的英文或数字的字符", + "Verify password": "确认密码", + "Invalid username or password": "用户名或密码错误", + "Invalid phone number": "无效的手机号码", + "Invalid verification code": "无效的验证码", + "Get code failed": "获取验证码失败", + "Read and agree": "请阅读并同意下方协议", + "agree policy": "我已阅读并同意", + "and": "和", + "Service Agreement": "服务协议", + "Privacy Policy": "隐私政策", + "Get Code": "获取验证码", + "Bonus": "赠", + "Payment Result": "支付结果", + "Payment Successful": "支付成功", + "In Payment": "支付中 ...", + "Recharge Amount": "充值金额", + "Select Amount": "选择金额", + "View Discount Rules": "查看优惠规则", + "Payment Status": "支付状态", + "Scan with WeChat": "微信扫码支付", + "Charge": "充值", + "Order Number": "订单号", + "Confirm": "确认", + "Login to your account": "登录您的帐户", + "Abdication": "移交", + "Team": "团队", + "Member List": "成员列表", + "Created Time": "创建时间", + "Create Team": "创建团队", + "Name of Team": "团队名称", + "Dissolve Team": "解散", + "Invaild Name of Team": "不合法的团队名称", + "Manage Team": "管理团队", + "Default Team": "默认", + "private team ID of user": "用户的 private team 的团队ID", + "Invite Member": "邀请成员", + "Handle": "操作", + "Reject": "拒绝", + "Accept": "接受", + "Cancel": "取消", + "Quit": "退出", + "Remove": "移除", + "Warning": "警告", + "User Name": "用户名", + "Access": "权限", + "In Time": "加入时间", + "Status": "状态", + "Operating": "操作", + "Waiting": "等待中", + "Added": "已加入", + "Invaild Context": "你需要切换到其他团队操作", + "Remove Member Tips": "确认要移除该成员?", + "Invalid User ID": "用户的 ID 不合法", + "The invited user must be others": "只能邀请其他人", + "Dissovle Tips": "解散团队会清空所有资源,确定要解散吗?", + "Enter Confirm.": "请输入 {{value}} 确认", + "Accept Invitation": "接受邀请", + "Recive Tips": "{{managerName}} 邀请你到 {{teamName}} 当 {{role}}", + "pay with wechat": "微信支付", + "pay with stripe": "Stripe 支付", + "License Buy": "License 购买", + "Purchase History": "购买记录", + "Purchase License": "购买 License", + "Remaining Time": "剩余激活时间: ", + "Please read and agree to the agreement": "请阅读并同意协议", + "Purchase Link Error": "购买链接错误", + "You have not purchased the License": "您还没有购买 License", + "App Info": "应用信息" +} \ No newline at end of file diff --git a/service/license/public/logo.svg b/service/license/public/logo.svg new file mode 100644 index 00000000000..ff4b8631a4b --- /dev/null +++ b/service/license/public/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/service/license/src/api/license.ts b/service/license/src/api/license.ts new file mode 100644 index 00000000000..6b67abba7fb --- /dev/null +++ b/service/license/src/api/license.ts @@ -0,0 +1,35 @@ +import { GET, POST } from '@/services/request'; +import { LicensePayStatus, LicensePayload, LicenseRecord, Payment } from '@/types'; +import { number } from 'react-i18next/icu.macro'; + +export const licensePay = ({ + amount, + quota, + paymentMethod, + hid +}: { + amount: number; + quota: number; + paymentMethod: 'wechat' | 'stripe'; + hid: string; +}) => + POST('/api/license/pay', { + amount, + quota, + paymentMethod, + hid + }); + +export const createLicenseRecord = (payload: LicensePayload) => + POST('/api/license/createLicenseRecord', payload); + +export const getLicenseResult = (paymentName: string) => + GET('/api/license/result', { + paymentName: paymentName + }); + +export const getLicenseRecord = ({ page, pageSize }: { page: number; pageSize: number }) => + POST<{ total: number; records: LicenseRecord[] }>('/api/license/getLicenseRecord', { + page, + pageSize + }); diff --git a/service/license/src/api/system.ts b/service/license/src/api/system.ts new file mode 100644 index 00000000000..016af92c008 --- /dev/null +++ b/service/license/src/api/system.ts @@ -0,0 +1,10 @@ +import { GET } from '@/services/request'; +import { SystemEnv } from '@/types'; + +export const getSystemEnv = () => GET('/api/platform/getEnv'); + +export const getPriceBonus = () => + GET<{ + steps: string; + ratios: string; + }>('/api/price/bonus'); diff --git a/service/license/src/api/user.ts b/service/license/src/api/user.ts new file mode 100644 index 00000000000..c5a7cd4e108 --- /dev/null +++ b/service/license/src/api/user.ts @@ -0,0 +1,19 @@ +import { POST } from '@/services/request'; +import { Session } from '@/types'; +import { TUserExist } from '@/types/user'; + +export const signInByPhone = (phoneNumbers: string, code: string) => + POST('/api/auth/phone/verify', { + phoneNumbers: phoneNumbers, + code: code + }); + +export const sendCodeByPhone = (phoneNumbers: string) => + POST('/api/auth/phone/sms', { + phoneNumbers: phoneNumbers + }); + +export const userExistsByPassword = (username: string) => + POST('/api/auth/password/exist', { + user: username + }); diff --git a/service/license/src/components/LangSelect/index.tsx b/service/license/src/components/LangSelect/index.tsx new file mode 100644 index 00000000000..533e74448ee --- /dev/null +++ b/service/license/src/components/LangSelect/index.tsx @@ -0,0 +1,34 @@ +import { setCookie } from '@/utils/cookieUtils'; +import { Flex, FlexProps } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; + +export default function LangSelectSimple(props: FlexProps) { + const { t, i18n } = useTranslation(); + + return ( + { + setCookie('NEXT_LOCALE', i18n?.language === 'en' ? 'zh' : 'en', { + expires: 30, + sameSite: 'None', + secure: true + }); + i18n?.changeLanguage(i18n?.language === 'en' ? 'zh' : 'en'); + }} + > + {i18n?.language === 'en' ? 'En' : '中'} + + ); +} diff --git a/service/license/src/components/icons/CancelIcon.tsx b/service/license/src/components/icons/CancelIcon.tsx new file mode 100644 index 00000000000..0218a440e91 --- /dev/null +++ b/service/license/src/components/icons/CancelIcon.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const CancelIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/CloseIcon.tsx b/service/license/src/components/icons/CloseIcon.tsx new file mode 100644 index 00000000000..0318c24e29e --- /dev/null +++ b/service/license/src/components/icons/CloseIcon.tsx @@ -0,0 +1,8 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const CloseIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/CopyLink.tsx b/service/license/src/components/icons/CopyLink.tsx new file mode 100644 index 00000000000..f60e112963e --- /dev/null +++ b/service/license/src/components/icons/CopyLink.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const CopyLinkIcon = (props: IconProps) => ( + + + +); diff --git a/service/license/src/components/icons/DeleteIcon.tsx b/service/license/src/components/icons/DeleteIcon.tsx new file mode 100644 index 00000000000..86e619a8f9c --- /dev/null +++ b/service/license/src/components/icons/DeleteIcon.tsx @@ -0,0 +1,8 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const DeleteIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/DownloadIcon copy 2.tsx b/service/license/src/components/icons/DownloadIcon copy 2.tsx new file mode 100644 index 00000000000..b37347364f8 --- /dev/null +++ b/service/license/src/components/icons/DownloadIcon copy 2.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const DownloadIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/DownloadIcon copy 3.tsx b/service/license/src/components/icons/DownloadIcon copy 3.tsx new file mode 100644 index 00000000000..b37347364f8 --- /dev/null +++ b/service/license/src/components/icons/DownloadIcon copy 3.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const DownloadIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/DownloadIcon copy 4.tsx b/service/license/src/components/icons/DownloadIcon copy 4.tsx new file mode 100644 index 00000000000..b37347364f8 --- /dev/null +++ b/service/license/src/components/icons/DownloadIcon copy 4.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const DownloadIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/DownloadIcon.tsx b/service/license/src/components/icons/DownloadIcon.tsx new file mode 100644 index 00000000000..b37347364f8 --- /dev/null +++ b/service/license/src/components/icons/DownloadIcon.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const DownloadIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/EmptyIcon.tsx b/service/license/src/components/icons/EmptyIcon.tsx new file mode 100644 index 00000000000..16f8fa41906 --- /dev/null +++ b/service/license/src/components/icons/EmptyIcon.tsx @@ -0,0 +1,29 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const EmptyIcon = (props: IconProps) => { + return ( + + + + + + ); +}; diff --git a/service/license/src/components/icons/ExchangeIcon.tsx b/service/license/src/components/icons/ExchangeIcon.tsx new file mode 100644 index 00000000000..42804db26fb --- /dev/null +++ b/service/license/src/components/icons/ExchangeIcon.tsx @@ -0,0 +1,21 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const ExchangeIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/GithubIcon.tsx b/service/license/src/components/icons/GithubIcon.tsx new file mode 100644 index 00000000000..2910ce7634e --- /dev/null +++ b/service/license/src/components/icons/GithubIcon.tsx @@ -0,0 +1,19 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const GithubIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/GoogleIcon.tsx b/service/license/src/components/icons/GoogleIcon.tsx new file mode 100644 index 00000000000..65a1d2c8621 --- /dev/null +++ b/service/license/src/components/icons/GoogleIcon.tsx @@ -0,0 +1,30 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const GoogleIcon = (props: IconProps) => { + return ( + + + + + {' '} + + ); +}; diff --git a/service/license/src/components/icons/GroupAdd.tsx b/service/license/src/components/icons/GroupAdd.tsx new file mode 100644 index 00000000000..18a3910e027 --- /dev/null +++ b/service/license/src/components/icons/GroupAdd.tsx @@ -0,0 +1,20 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const GroupAddIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/HomePage.tsx b/service/license/src/components/icons/HomePage.tsx new file mode 100644 index 00000000000..5bbbde5e8d3 --- /dev/null +++ b/service/license/src/components/icons/HomePage.tsx @@ -0,0 +1,11 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const HomePageIcon = (props: IconProps) => ( + + + +); diff --git a/service/license/src/components/icons/HtmlIcon.tsx b/service/license/src/components/icons/HtmlIcon.tsx new file mode 100644 index 00000000000..3a0cdf6463f --- /dev/null +++ b/service/license/src/components/icons/HtmlIcon.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const HtmlIcon = (props: IconProps) => ( + + {' '} + +); diff --git a/service/license/src/components/icons/LicenseIcon.tsx b/service/license/src/components/icons/LicenseIcon.tsx new file mode 100644 index 00000000000..f3cd3955bef --- /dev/null +++ b/service/license/src/components/icons/LicenseIcon.tsx @@ -0,0 +1,11 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const LicenseIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/LockIcon.tsx b/service/license/src/components/icons/LockIcon.tsx new file mode 100644 index 00000000000..916ca11ba85 --- /dev/null +++ b/service/license/src/components/icons/LockIcon.tsx @@ -0,0 +1,8 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const LocklIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/MdIcon.tsx b/service/license/src/components/icons/MdIcon.tsx new file mode 100644 index 00000000000..ab888ed11ee --- /dev/null +++ b/service/license/src/components/icons/MdIcon.tsx @@ -0,0 +1,7 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const MdIcon = (props: IconProps) => ( + + {' '} + +); diff --git a/service/license/src/components/icons/PersonIcon.tsx b/service/license/src/components/icons/PersonIcon.tsx new file mode 100644 index 00000000000..c6e9b19e089 --- /dev/null +++ b/service/license/src/components/icons/PersonIcon.tsx @@ -0,0 +1,8 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const PersonIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/RightArrow.tsx b/service/license/src/components/icons/RightArrow.tsx new file mode 100644 index 00000000000..5ccebc75a93 --- /dev/null +++ b/service/license/src/components/icons/RightArrow.tsx @@ -0,0 +1,16 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const RightIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/SafetyIcon.tsx b/service/license/src/components/icons/SafetyIcon.tsx new file mode 100644 index 00000000000..7d1fd36795e --- /dev/null +++ b/service/license/src/components/icons/SafetyIcon.tsx @@ -0,0 +1,9 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const SafetyIcon = (props: IconProps) => { + return ( + + + + + ); +}; diff --git a/service/license/src/components/icons/Share.tsx b/service/license/src/components/icons/Share.tsx new file mode 100644 index 00000000000..ea015044fb3 --- /dev/null +++ b/service/license/src/components/icons/Share.tsx @@ -0,0 +1,8 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const ShareIcon = (props: IconProps) => ( + + + + +); diff --git a/service/license/src/components/icons/TokenIcon.tsx b/service/license/src/components/icons/TokenIcon.tsx new file mode 100644 index 00000000000..191ff56bd6f --- /dev/null +++ b/service/license/src/components/icons/TokenIcon.tsx @@ -0,0 +1,18 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const TokenIcon = (props: IconProps) => { + return ( + + + + + + + + + + + ); +}; diff --git a/service/license/src/components/icons/WarningIcon.tsx b/service/license/src/components/icons/WarningIcon.tsx new file mode 100644 index 00000000000..8b23182eb9e --- /dev/null +++ b/service/license/src/components/icons/WarningIcon.tsx @@ -0,0 +1,15 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const WarningIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/WechatIcon.tsx b/service/license/src/components/icons/WechatIcon.tsx new file mode 100644 index 00000000000..8bbb661ece1 --- /dev/null +++ b/service/license/src/components/icons/WechatIcon.tsx @@ -0,0 +1,22 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const WechatIcon = (props: IconProps) => { + return ( + + + + + ); +}; diff --git a/service/license/src/components/icons/index.ts b/service/license/src/components/icons/index.ts new file mode 100644 index 00000000000..f19aaf2c4c6 --- /dev/null +++ b/service/license/src/components/icons/index.ts @@ -0,0 +1,23 @@ +export * from './CopyLink'; +export * from './Share'; +export * from './HomePage'; +export * from './HtmlIcon'; +export * from './MdIcon'; +export * from './GithubIcon'; +export * from './GoogleIcon'; +export * from './CancelIcon'; +export * from './CopyLink'; +export * from './DeleteIcon'; +export * from './ExchangeIcon'; +export * from './GroupAdd'; +export * from './RightArrow'; +export * from './WechatIcon'; +export * from './WarningIcon'; +export * from './CloseIcon'; +export * from './LockIcon'; +export * from './SafetyIcon'; +export * from './PersonIcon'; +export * from './EmptyIcon'; +export * from './LicenseIcon'; +export * from './DownloadIcon'; +export * from './TokenIcon'; diff --git a/service/license/src/components/signin/auth/useAuthList.tsx b/service/license/src/components/signin/auth/useAuthList.tsx new file mode 100644 index 00000000000..cdf87532ee6 --- /dev/null +++ b/service/license/src/components/signin/auth/useAuthList.tsx @@ -0,0 +1,99 @@ +import { getSystemEnv } from '@/api/system'; +import { GithubIcon, GoogleIcon, WechatIcon } from '@/components/icons'; +import useSessionStore from '@/stores/session'; +import { ApiResp, SystemEnv } from '@/types'; +import { OauthProvider } from '@/types/user'; +import { Button, Flex, Icon } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { MouseEventHandler } from 'react'; + +const useAuthList = () => { + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + + const { + needGithub = false, + needWechat = false, + needGoogle = false, + wechat_client_id = '', + github_client_id = '', + google_client_id = '', + callback_url = '' + } = platformEnv || {}; + const { generateState, setProvider } = useSessionStore(); + + const oauthLogin = async ({ url, provider }: { url: string; provider?: OauthProvider }) => { + setProvider(provider); + window.location.href = url; + }; + + const authList: { icon: typeof Icon; cb: MouseEventHandler; need: boolean }[] = [ + { + // src: '/images/github.svg', + icon: GithubIcon, + cb: (e) => { + e.preventDefault(); + const state = generateState(); + oauthLogin({ + provider: 'github', + url: `https://github.com/login/oauth/authorize?client_id=${github_client_id}&redirect_uri=${callback_url}&scope=user:email%20read:user&state=${state}` + }); + }, + need: needGithub + }, + { + icon: WechatIcon, + cb: (e) => { + e.preventDefault(); + const state = generateState(); + oauthLogin({ + provider: 'wechat', + url: `https://open.weixin.qq.com/connect/qrconnect?appid=${wechat_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}&scope=snsapi_login&#wechat_redirect` + }); + }, + need: needWechat + }, + { + icon: GoogleIcon, + cb: (e) => { + e.preventDefault(); + const state = generateState(); + const scope = encodeURIComponent(`https://www.googleapis.com/auth/userinfo.profile openid`); + oauthLogin({ + provider: 'google', + //https://www.googleapis.com/auth/userinfo.profile + url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${google_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}&scope=${scope}&include_granted_scopes=true` + }); + }, + need: needGoogle + } + ]; + + const AuthList = () => { + return ( + + {authList + .filter((item) => item.need) + .map((item, index) => ( + + ))} + + ); + }; + + return { + AuthList + }; +}; + +export default useAuthList; diff --git a/service/license/src/components/signin/auth/useCustomError.tsx b/service/license/src/components/signin/auth/useCustomError.tsx new file mode 100644 index 00000000000..54234ac6da5 --- /dev/null +++ b/service/license/src/components/signin/auth/useCustomError.tsx @@ -0,0 +1,61 @@ +import { Flex, Img, Button, Text } from '@chakra-ui/react'; +import React, { useState, useEffect } from 'react'; +import { WarningIcon, CloseIcon } from '@/components/icons'; +import { useTranslation } from 'next-i18next'; + +const useCustomError = () => { + const { t } = useTranslation(); + const [error, setError] = useState(''); + + const showError = (errorMessage: string, duration = 5000) => { + setError(errorMessage); + setTimeout(() => { + setError(''); + }, duration); + }; + + const closeError = () => { + setError(''); + }; + + const ErrorComponent = () => { + useEffect(() => { + if (error) { + const timeout = setTimeout(() => { + closeError(); + }, 5000); // 默认 5000 毫秒(5秒)后自动关闭错误消息 + return () => clearTimeout(timeout); + } + }, [error]); + + return error ? ( + + + {t(error)} + + + ) : null; + }; + + return { showError, ErrorComponent }; +}; + +export default useCustomError; diff --git a/service/license/src/components/signin/auth/useLanguage.tsx b/service/license/src/components/signin/auth/useLanguage.tsx new file mode 100644 index 00000000000..8aaecd6e928 --- /dev/null +++ b/service/license/src/components/signin/auth/useLanguage.tsx @@ -0,0 +1,27 @@ +import LangSelectSimple from '@/components/LangSelect'; +import { Flex, UseDisclosureReturn } from '@chakra-ui/react'; +import { I18n } from 'next-i18next'; + +type LanguageType = { disclosure: UseDisclosureReturn; i18n: I18n | null }; + +const Language = ({ disclosure, i18n }: LanguageType) => { + return ( + + + + ); +}; + +export default Language; diff --git a/service/license/src/components/signin/auth/usePassword.tsx b/service/license/src/components/signin/auth/usePassword.tsx new file mode 100644 index 00000000000..c17f96ce871 --- /dev/null +++ b/service/license/src/components/signin/auth/usePassword.tsx @@ -0,0 +1,236 @@ +import useSessionStore from '@/stores/session'; +import { ApiResp, Session } from '@/types'; +import { TUserExist } from '@/types/user'; +import { Flex, Image, Img, Input, InputGroup, InputLeftAddon, Text } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; +import { LocklIcon, PersonIcon } from '@/components/icons'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { userExistsByPassword } from '@/api/user'; + +export default function usePassword({ + showError +}: { + showError: (errorMessage: string, duration?: number) => void; +}) { + const { t } = useTranslation(); + const router = useRouter(); + const [userExist, setUserExist] = useState(true); + const [isLoading, setIsLoading] = useState(false); + // 对于注册的用户,需要先验证密码 0 默认页面;1为验证密码页面 + const [pageState, setPageState] = useState(0); + + const setSession = useSessionStore((s) => s.setSession); + + const { register, handleSubmit, watch, trigger, getValues } = useForm<{ + username: string; + password: string; + confimPassword: string; + }>(); + + const login = async () => { + const deepSearch = (obj: any): string => { + if (!obj || typeof obj !== 'object') return t('Submit Error'); + if (!!obj.message) { + return obj.message; + } + return deepSearch(Object.values(obj)[0]); + }; + + handleSubmit( + async (data) => { + if (data?.username && data?.password) { + try { + setIsLoading(true); + const result = await userExistsByPassword(data.username); + + if (result?.code === 200) { + const result = await request.post>('/api/auth/password', { + user: data.username, + password: data.password + }); + setSession(result.data!); + router.replace('/'); + return; + } + if (result?.code === 201) { + setUserExist(!!result?.data?.exist); + setPageState(1); + if (!!data?.confimPassword) { + if (data?.password !== data?.confimPassword) { + showError('password not match'); + } else { + const result = await request.post>('/api/auth/password', { + user: data.username, + password: data.password + }); + setSession(result.data!); + router.replace('/'); + } + } + } + } catch (error: any) { + console.log(error); + showError(t('Invalid username or password')); + } finally { + setIsLoading(false); + } + } + }, + (err) => { + console.log(err); + showError(deepSearch(err)); + } + )(); + }; + + const PasswordComponent = () => { + if (pageState === 0) { + return ; + } else { + return ; + } + }; + + const PasswordModal = () => { + return ( + <> + + + + + + + + + + + + + + ); + }; + + const ConfirmPasswordModal = () => { + return ( + <> + + Vector setPageState(0)} + /> + {t('Verify password')} + + + + + + + + + ); + }; + + return { + PasswordComponent, + login, + userExist, + pageState, + isLoading + }; +} diff --git a/service/license/src/components/signin/auth/useProtocol.tsx b/service/license/src/components/signin/auth/useProtocol.tsx new file mode 100644 index 00000000000..36574dab25c --- /dev/null +++ b/service/license/src/components/signin/auth/useProtocol.tsx @@ -0,0 +1,70 @@ +import { Checkbox, Flex, Link, Text, TextProps } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { useState } from 'react'; + +const useProtocol = ({ + service_protocol, + private_protocol +}: { + service_protocol: string; + private_protocol: string; +}) => { + const { t, i18n } = useTranslation(); + const [isAgree, setIsAgree] = useState(false); + const [isInvalid, setIsInvalid] = useState(false); + + const Protocol = () => ( + + { + setIsInvalid(false); + setIsAgree(e.target.checked); + }} + /> + + {t('agree policy')} + + {t('Service Agreement')} + + {t('and')} + + {t('Privacy Policy')} + + + + ); + return { + Protocol, + isAgree, + setIsInvalid + }; +}; + +export default useProtocol; diff --git a/service/license/src/components/signin/auth/useSms.tsx b/service/license/src/components/signin/auth/useSms.tsx new file mode 100644 index 00000000000..ea02daa16b8 --- /dev/null +++ b/service/license/src/components/signin/auth/useSms.tsx @@ -0,0 +1,201 @@ +import { sendCodeByPhone, signInByPhone } from '@/api/user'; +import { SafetyIcon } from '@/components/icons'; +import useSessionStore from '@/stores/session'; +import { ApiResp, Session } from '@/types'; +import { + Image, + Input, + InputGroup, + InputLeftAddon, + InputRightAddon, + Link, + Text +} from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import NextLink from 'next/link'; +import { useRouter } from 'next/router'; +import { MouseEventHandler, useEffect, useRef, useState } from 'react'; +import { useForm } from 'react-hook-form'; + +export default function useSms({ + showError +}: { + showError: (errorMessage: string, duration?: number) => void; +}) { + const { t } = useTranslation(); + const _remainTime = useRef(0); + const router = useRouter(); + const { setSession } = useSessionStore(); + const [isLoading, setIsLoading] = useState(false); + + const { register, handleSubmit, trigger, getValues } = useForm<{ + phoneNumber: string; + verifyCode: string; + }>(); + + const login = async () => { + const deepSearch = (obj: any): string => { + if (!obj || typeof obj !== 'object') return t('Submit Error'); + if (!!obj.message) { + return obj.message; + } + return deepSearch(Object.values(obj)[0]); + }; + + handleSubmit( + async (data) => { + try { + setIsLoading(true); + const result = await signInByPhone(data.phoneNumber, data.verifyCode); + setSession(result.data!); + router.replace('/'); + } catch (error) { + showError(t('Invalid verification code') || 'Invalid verification code'); + } finally { + setIsLoading(false); + } + }, + (err) => { + showError(deepSearch(err)); + } + )(); + }; + + const SmsModal = () => { + const [remainTime, setRemainTime] = useState(_remainTime.current); + + useEffect(() => { + if (remainTime <= 0) return; + const interval = setInterval(() => { + setRemainTime(remainTime - 1); + }, 1000); + return () => clearInterval(interval); + }, [remainTime]); + + const getCode: MouseEventHandler = async (e) => { + e.preventDefault(); + + if (!(await trigger('phoneNumber'))) { + showError(t('Invalid phone number') || 'Invalid phone number'); + return; + } + setRemainTime(60); + _remainTime.current = 60; + + try { + const res = await sendCodeByPhone(getValues('phoneNumber')); + if (res.code !== 200 || res.message !== 'successfully') { + throw new Error('Get code failed'); + } + } catch (err) { + showError(t('Get code failed') || 'Get code failed'); + setRemainTime(0); + _remainTime.current = 0; + } + }; + + return ( + <> + + + + +86 + + + + + + {remainTime <= 0 ? ( + + {t('Get Code')} + + ) : ( + {remainTime} s + )} + + + + + + + + + + {getValues('verifyCode')?.length === 6 && ( + material-symbols_update + )} + + + + ); + }; + + return { + SmsModal, + login, + isLoading + }; +} diff --git a/service/license/src/components/signin/index.tsx b/service/license/src/components/signin/index.tsx new file mode 100644 index 00000000000..ade5b1a3e2b --- /dev/null +++ b/service/license/src/components/signin/index.tsx @@ -0,0 +1,189 @@ +import { getSystemEnv } from '@/api/system'; +import useAuthList from '@/components/signin/auth/useAuthList'; +import useCustomError from '@/components/signin/auth/useCustomError'; +import Language from '@/components/signin/auth/useLanguage'; +import usePassword from '@/components/signin/auth/usePassword'; +import useProtocol from '@/components/signin/auth/useProtocol'; +import useSms from '@/components/signin/auth/useSms'; +import useSessionStore from '@/stores/session'; +import { ApiResp, LoginType, SystemEnv } from '@/types'; +import { + Box, + Button, + Flex, + Img, + Tab, + TabIndicator, + TabList, + Tabs, + useDisclosure +} from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { debounce } from 'lodash'; +import { useTranslation } from 'next-i18next'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import sealosTitle from 'public/images/sealos-title.png'; +import { useEffect, useMemo, useState } from 'react'; + +export default function SigninComponent() { + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + console.log(platformEnv); + + const { + service_protocol = '', + private_protocol = '', + needPassword = false, + needSms = false + } = platformEnv || {}; + + const needTabs = needPassword && needSms; + + const disclosure = useDisclosure(); + const { t, i18n } = useTranslation(); + const [tabIndex, setTabIndex] = useState(LoginType.NONE); + + const { ErrorComponent, showError } = useCustomError(); + + const { Protocol, isAgree, setIsInvalid } = useProtocol({ service_protocol, private_protocol }); + const { SmsModal, login: smsSubmit, isLoading: smsLoading } = useSms({ showError }); + const { + PasswordComponent, + pageState, + login: passwordSubmit, + isLoading: passwordLoading + } = usePassword({ showError }); + const isLoading = useMemo(() => passwordLoading || smsLoading, [passwordLoading, smsLoading]); + const isSignIn = useSessionStore((s) => s.isUserLogin); + const router = useRouter(); + // useEffect(() => { + // if (isSignIn()) { + // router.replace('/'); + // } + // }, []); + const { AuthList } = useAuthList(); + + const loginConfig = useMemo(() => { + return { + [LoginType.SMS]: { + login: smsSubmit, + component: + }, + [LoginType.PASSWORD]: { + login: passwordSubmit, + component: + }, + [LoginType.NONE]: null + }; + }, [PasswordComponent, SmsModal, passwordSubmit, smsSubmit]); + + useEffect(() => { + setTabIndex(needSms ? LoginType.SMS : needPassword ? LoginType.PASSWORD : LoginType.NONE); + }, [needPassword, needSms]); + + const LoginComponent = useMemo( + () => (tabIndex !== LoginType.NONE ? loginConfig[tabIndex].component : null), + [loginConfig, tabIndex] + ); + + const handleLogin = debounce(() => { + const selectedConfig = loginConfig[tabIndex]; + if (isAgree && selectedConfig) { + const { login } = selectedConfig; + login(); + } else { + setIsInvalid(true); + showError(t('Read and agree')); + } + }, 500); + + return ( + + + sealos Cloud + + + + + + + + + + {pageState === 0 && needTabs && ( + setTabIndex(idx)} + variant="unstyled" + p={'0'} + width={'full'} + > + + + {t('Verification Code Login')} + + + {t('Password Login')} + + + + + )} + + {LoginComponent} + + + + + + + + + + ); +} diff --git a/service/license/src/hooks/useBonusBox.tsx b/service/license/src/hooks/useBonusBox.tsx new file mode 100644 index 00000000000..e2bd9ab0dae --- /dev/null +++ b/service/license/src/hooks/useBonusBox.tsx @@ -0,0 +1,65 @@ +import { ApiResp } from '@/types'; +import { Flex, Text } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { useCallback, useMemo, useState } from 'react'; +import CurrencySymbol from '../pages/license/components/CurrencySymbol'; +import { getPriceBonus } from '@/api/system'; + +export default function useBonusBox() { + const [selectAmountIndex, setSelectAmountIndex] = useState(0); + + const { data: bonuses, isSuccess } = useQuery(['bonus'], getPriceBonus); + + const { ratios, steps } = useMemo(() => { + return { + ratios: (bonuses?.ratios || '').split(',').map((v) => +v), + steps: (bonuses?.steps || '').split(',').map((v) => +v) + }; + }, [bonuses]); + + const BonusBox = useCallback( + () => ( + + {steps.map((amount, index) => ( + { + e.preventDefault(); + setSelectAmountIndex(index); + }} + > + + + + {amount} + + + + ))} + + ), + [selectAmountIndex, steps] + ); + + return { + BonusBox, + selectAmount: steps[selectAmountIndex] + }; +} diff --git a/service/license/src/hooks/useCopyData.ts b/service/license/src/hooks/useCopyData.ts new file mode 100644 index 00000000000..3cbfe7a9b2d --- /dev/null +++ b/service/license/src/hooks/useCopyData.ts @@ -0,0 +1,32 @@ +import { useToast } from '@chakra-ui/react'; + +/** + * copy text data + */ +export const useCopyData = () => { + const toast = useToast(); + return { + copyData: async (data: string, title: string = '复制成功') => { + try { + if (navigator.clipboard) { + await navigator.clipboard.writeText(data); + } else { + throw new Error(''); + } + } catch (error) { + const textarea = document.createElement('textarea'); + textarea.value = data; + document.body.appendChild(textarea); + textarea.select(); + document.execCommand('copy'); + document.body.removeChild(textarea); + } + toast({ + position: 'top', + title, + status: 'success', + duration: 1000 + }); + } + }; +}; diff --git a/service/license/src/hooks/useCustomToast.ts b/service/license/src/hooks/useCustomToast.ts new file mode 100644 index 00000000000..4e495239b2b --- /dev/null +++ b/service/license/src/hooks/useCustomToast.ts @@ -0,0 +1,13 @@ +import { useToast as uToast, UseToastOptions } from '@chakra-ui/react'; + +export const useCustomToast = (props?: UseToastOptions) => { + const toast = uToast({ + position: 'top', + duration: 2000, + ...props + }); + + return { + toast + }; +}; diff --git a/service/license/src/hooks/useScreen.ts b/service/license/src/hooks/useScreen.ts new file mode 100644 index 00000000000..22fa19fb928 --- /dev/null +++ b/service/license/src/hooks/useScreen.ts @@ -0,0 +1,12 @@ +import { useMediaQuery } from '@chakra-ui/react'; + +export function useScreen() { + // ssr-friendly media query with fallback + const [isPC] = useMediaQuery('(min-width: 650px)', { + ssr: true, + fallback: false // return false on the server, and re-evaluate on the client side + }); + return { + isPC + }; +} diff --git a/service/license/src/pages/404.tsx b/service/license/src/pages/404.tsx new file mode 100644 index 00000000000..07e8393085a --- /dev/null +++ b/service/license/src/pages/404.tsx @@ -0,0 +1,13 @@ +import React, { useEffect } from 'react'; +import { useRouter } from 'next/router'; + +const NonePage = () => { + const router = useRouter(); + // useEffect(() => { + // router.push('/'); + // }, [router]); + + return
; +}; + +export default NonePage; diff --git a/service/license/src/pages/_app.tsx b/service/license/src/pages/_app.tsx new file mode 100644 index 00000000000..26dfe665967 --- /dev/null +++ b/service/license/src/pages/_app.tsx @@ -0,0 +1,32 @@ +import '@/styles/globals.css'; +import { ChakraProvider } from '@chakra-ui/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { appWithTranslation } from 'next-i18next'; +import type { AppProps } from 'next/app'; +import Router from 'next/router'; +import NProgress from 'nprogress'; +import 'nprogress/nprogress.css'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false + } + } +}); + +//Binding events. +Router.events.on('routeChangeStart', () => NProgress.start()); +Router.events.on('routeChangeComplete', () => NProgress.done()); +Router.events.on('routeChangeError', () => NProgress.done()); + +const App = ({ Component, pageProps }: AppProps) => { + return ( + + + + + + ); +}; +export default appWithTranslation(App); diff --git a/service/license/src/pages/_document.tsx b/service/license/src/pages/_document.tsx new file mode 100644 index 00000000000..54e8bf3e2a2 --- /dev/null +++ b/service/license/src/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from 'next/document' + +export default function Document() { + return ( + + + +
+ + + + ) +} diff --git a/service/license/src/pages/api/auth/oauth/github/index.ts b/service/license/src/pages/api/auth/oauth/github/index.ts new file mode 100644 index 00000000000..36984b19aac --- /dev/null +++ b/service/license/src/pages/api/auth/oauth/github/index.ts @@ -0,0 +1,53 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; +const clientId = process.env.GITHUB_CLIENT_ID!; +const clientSecret = process.env.GITHUB_CLIENT_SECRET!; +import { TgithubToken, TgithubUser } from '@/types/user'; + +import { Session } from '@/types/session'; +import { getOauthRes } from '@/services/backend/oauth'; +import { enableGithub } from '@/services/enable'; +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enableGithub()) { + throw new Error('github clinet is not defined'); + } + const { code } = req.body; + const url = ` https://github.com/login/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&code=${code}`; + const __data = (await ( + await fetch(url, { method: 'POST', headers: { Accept: 'application/json' } }) + ).json()) as TgithubToken; + const access_token = __data.access_token; + if (!access_token) { + return jsonRes(res, { + message: 'Failed to authenticate with GitHub', + code: 500, + data: 'access_token is null' + }); + } + const userUrl = `https://api.github.com/user`; + const result = (await ( + await fetch(userUrl, { + headers: { + Authorization: `Bearer ${access_token}` + } + }) + ).json()) as TgithubUser; + const name = result.login; + const id = '' + result.id; + const avatar_url = result.avatar_url; + + const data = await getOauthRes({ provider: 'github', id, name, avatar_url }); + return jsonRes(res, { + data, + code: 200, + message: 'Successfully' + }); + } catch (err) { + console.log(err); + return jsonRes(res, { + message: 'Failed to authenticate with GitHub', + code: 500 + }); + } +} diff --git a/service/license/src/pages/api/auth/oauth/google/index.ts b/service/license/src/pages/api/auth/oauth/google/index.ts new file mode 100644 index 00000000000..438c8cde04a --- /dev/null +++ b/service/license/src/pages/api/auth/oauth/google/index.ts @@ -0,0 +1,63 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; +const clientId = process.env.GOOGLE_CLIENT_ID!; +const clientSecret = process.env.GOOGLE_CLIENT_SECRET!; +const callbackUrl = process.env.CALLBACK_URL || ''; +import { TgithubToken, TgithubUser } from '@/types/user'; +import * as jwt from 'jsonwebtoken'; +import { Session } from '@/types/session'; +import { getOauthRes } from '@/services/backend/oauth'; +import { enableGoogle } from '@/services/enable'; +import { getBase64FromRemote } from '@/utils/tools'; +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enableGoogle()) { + throw new Error('google clinet is not defined'); + } + const { code } = req.body; + if (!code) + return jsonRes(res, { + code: 400, + message: 'The code is required' + }); + const url = `https://oauth2.googleapis.com/token?client_id=${clientId}&client_secret=${clientSecret}&code=${code}&redirect_uri=${callbackUrl}&grant_type=authorization_code`; + const __data = (await ( + await fetch(url, { method: 'POST', headers: { Accept: 'application/json' } }) + ).json()) as { + access_token: string; + scope: string; + token_type: string; + id_token: string; + }; + const userInfo = jwt.decode(__data.id_token) as { + iss: string; + azp: string; + aud: string; + sub: string; + at_hash: string; + name: string; + picture: string; + given_name: string; + family_name: string; + locale: string; + iat: number; + exp: number; + }; + const name = userInfo.name; + const id = userInfo.sub; + const avatar_url = (await getBase64FromRemote(userInfo.picture)) as string; + if (!id) throw new Error('fail to get google openid'); + const data = await getOauthRes({ provider: 'google', id, name, avatar_url }); + return jsonRes(res, { + data, + code: 200, + message: 'Successfully' + }); + } catch (err) { + console.log(err); + return jsonRes(res, { + message: 'Failed to authenticate with Google', + code: 500 + }); + } +} diff --git a/service/license/src/pages/api/auth/oauth/wechat/index.ts b/service/license/src/pages/api/auth/oauth/wechat/index.ts new file mode 100644 index 00000000000..338b7621582 --- /dev/null +++ b/service/license/src/pages/api/auth/oauth/wechat/index.ts @@ -0,0 +1,50 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; + +const APP_ID = process.env.WECHAT_CLIENT_ID!; +const APP_SECRET = process.env.WECHAT_CLIENT_SECRET!; +import { TWechatToken, TWechatUser } from '@/types/user'; +import { Session } from '@/types/session'; +import { getBase64FromRemote } from '@/utils/tools'; +import { getOauthRes } from '@/services/backend/oauth'; +import { enableWechat } from '@/services/enable'; +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enableWechat()) { + throw new Error('wechat clinet is not defined'); + } + const { code } = req.body; + const url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${APP_ID}&secret=${APP_SECRET}&code=${code}&grant_type=authorization_code`; + const { access_token, openid } = (await ( + await fetch(url, { headers: { Accept: 'application/json' } }) + ).json()) as TWechatToken; + + if (!access_token || !openid) { + return jsonRes(res, { + message: 'Failed to authenticate with wechat', + code: 400, + data: 'access_token is null' + }); + } + + const userUrl = `https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=${openid}&lang=zh_CN`; + const { + nickname: name, + unionid: id, + headimgurl + } = (await (await fetch(userUrl)).json()) as TWechatUser; + const avatar_url = (await getBase64FromRemote(headimgurl)) as string; + const data = await getOauthRes({ provider: 'wechat', id: '' + id || openid, name, avatar_url }); + return jsonRes(res, { + data, + code: 200, + message: 'Successfully' + }); + } catch (err) { + console.log(err); + jsonRes(res, { + message: 'Failed to authenticate with wechat', + code: 500 + }); + } +} diff --git a/service/license/src/pages/api/auth/password/exist.ts b/service/license/src/pages/api/auth/password/exist.ts new file mode 100644 index 00000000000..d832891379f --- /dev/null +++ b/service/license/src/pages/api/auth/password/exist.ts @@ -0,0 +1,41 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; + +import { queryUser } from '@/services/backend/db/user'; +import { hashPassword } from '@/utils/crypto'; +import { TUserExist } from '@/types/user'; +import { enablePassword } from '@/services/enable'; +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enablePassword()) { + throw new Error('PASSWORD_SALT is not defined'); + } + const { user } = req.body; + + const result = await queryUser({ id: user, provider: 'password_user' }); + if (!result || !result.password || result.password === hashPassword('')) { + return jsonRes(res, { + message: 'user not found', + code: 201, + data: { + user, + exist: false + } + }); + } + return jsonRes(res, { + code: 200, + message: 'Successfully', + data: { + user, + exist: true + } + }); + } catch (err) { + console.log(err); + return jsonRes(res, { + message: 'Failed to get result', + code: 500 + }); + } +} diff --git a/service/license/src/pages/api/auth/password/index.ts b/service/license/src/pages/api/auth/password/index.ts new file mode 100644 index 00000000000..c6447a85d3f --- /dev/null +++ b/service/license/src/pages/api/auth/password/index.ts @@ -0,0 +1,40 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; + +import { Session } from '@/types/session'; +import { getOauthRes } from '@/services/backend/oauth'; +import { strongPassword } from '@/utils/crypto'; +import { enablePassword } from '@/services/enable'; +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enablePassword()) { + throw new Error('PASSWORD_SALT is not defined'); + } + const { user: name, password } = req.body; + if (!strongPassword(password)) { + return jsonRes(res, { + message: + 'Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number and one special character', + code: 400 + }); + } + const data = await getOauthRes({ + provider: 'password_user', + id: '' + name, + name, + avatar_url: '', + password + }); + return jsonRes(res, { + data, + code: 200, + message: 'Successfully' + }); + } catch (err) { + console.log(err); + return jsonRes(res, { + message: 'Failed to authenticate with password', + code: 500 + }); + } +} diff --git a/service/license/src/pages/api/auth/phone/sms.ts b/service/license/src/pages/api/auth/phone/sms.ts new file mode 100644 index 00000000000..44033caaeb9 --- /dev/null +++ b/service/license/src/pages/api/auth/phone/sms.ts @@ -0,0 +1,85 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +// import twilio from 'twilio'; +//@ts-ignore +import Dysmsapi, * as dysmsapi from '@alicloud/dysmsapi20170525'; +//@ts-ignore +import * as OpenApi from '@alicloud/openapi-client'; +//@ts-ignore +import * as Util from '@alicloud/tea-util'; +import { jsonRes } from '@/services/backend/response'; +import { addOrUpdateCode, checkSendable } from '@/services/backend/db/verifyCode'; +import { enableSms } from '@/services/enable'; +import { retrySerially } from '@/utils/tools'; +const accessKeyId = process.env.ALI_ACCESS_KEY_ID; +const accessKeySecret = process.env.ALI_ACCESS_KEY_SECRET; +const templateCode = process.env.ALI_TEMPLATE_CODE; +const signName = process.env.ALI_SIGN_NAME; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enableSms()) { + throw new Error('SMS is not enabled'); + } + const { phoneNumbers } = req.body; + if (!(await checkSendable(phoneNumbers))) { + return jsonRes(res, { + message: 'code already sent', + code: 400 + }); + } + + // randomly generate six bit check code + const code = Math.floor(Math.random() * 900000 + 100000).toString(); + const sendSmsRequest = new dysmsapi.SendSmsRequest({ + phoneNumbers, + signName, + templateCode, + templateParam: `{"code":${code}}` + }); + const config = new OpenApi.Config({ + accessKeyId, + accessKeySecret + }); + + const client = new Dysmsapi(config); + const runtime = new Util.RuntimeOptions({}); + const result = await retrySerially(async () => { + try { + const _result = await client.sendSmsWithOptions(sendSmsRequest, runtime); + + if (!_result) { + throw new Error('sms result is null'); + } + if (_result.statusCode !== 200) { + throw new Error(`sms result status code is ${_result.statusCode} + ${_result.body} + ${phoneNumbers}, + ${new Date()} + `); + } + if (_result.body.code !== 'OK') { + throw new Error(` + ${_result.body.message} + ${phoneNumbers}, + ${new Date()}`); + } + return _result; + } catch (error) { + return Promise.reject(error); + } + }, 3); + + // update cache + await addOrUpdateCode({ phone: phoneNumbers, code }); + return jsonRes(res, { + message: 'successfully', + code: 200 + }); + } catch (error) { + console.log(error); + jsonRes(res, { + message: 'Failed to send code', + code: 500 + }); + } +} diff --git a/service/license/src/pages/api/auth/phone/verify.ts b/service/license/src/pages/api/auth/phone/verify.ts new file mode 100644 index 00000000000..74d6860ecb5 --- /dev/null +++ b/service/license/src/pages/api/auth/phone/verify.ts @@ -0,0 +1,38 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; +import { Session } from '@/types'; +import { checkCode } from '@/services/backend/db/verifyCode'; +import { getOauthRes } from '@/services/backend/oauth'; +import { enableSms } from '@/services/enable'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + if (!enableSms()) { + throw new Error('sms client is not defined'); + } + const { phoneNumbers, code } = req.body; + if (!(await checkCode({ phone: phoneNumbers, code }))) { + return jsonRes(res, { + message: 'SMS code is wrong', + code: 400 + }); + } + const data = await getOauthRes({ + provider: 'phone', + id: phoneNumbers, + name: phoneNumbers, + avatar_url: '' + }); + return jsonRes(res, { + data, + code: 200, + message: 'Successfully' + }); + } catch (error) { + console.log(error); + jsonRes(res, { + message: 'Failed to authenticate with phone', + code: 400 + }); + } +} diff --git a/service/license/src/pages/api/license/createLicenseRecord.ts b/service/license/src/pages/api/license/createLicenseRecord.ts new file mode 100644 index 00000000000..86aa73f8a32 --- /dev/null +++ b/service/license/src/pages/api/license/createLicenseRecord.ts @@ -0,0 +1,31 @@ +import { authSession } from '@/services/backend/auth'; +import { createLicenseRecord } from '@/services/backend/db/license'; +import { jsonRes } from '@/services/backend/response'; +import { LicensePayload } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const payload = await authSession(req.headers); + if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + + const { token, orderID, amount, quota, paymentMethod } = req.body as LicensePayload; + + const record = { + uid: payload.user.nsid, + amount: amount, + token: token, + orderID: orderID, + quota: quota, + paymentMethod: paymentMethod + }; + + const result = await createLicenseRecord(record); + + return jsonRes(resp, { + data: result + }); + } catch (error) { + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/getLicenseRecord.ts b/service/license/src/pages/api/license/getLicenseRecord.ts new file mode 100644 index 00000000000..cf18b889010 --- /dev/null +++ b/service/license/src/pages/api/license/getLicenseRecord.ts @@ -0,0 +1,29 @@ +import { authSession } from '@/services/backend/auth'; +import { createLicenseRecord, getLicenseRecordsByUid } from '@/services/backend/db/license'; +import { jsonRes } from '@/services/backend/response'; +import { LicensePayload } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const payload = await authSession(req.headers); + if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + + const { page = 1, pageSize = 10 } = req.body as { + page: number; + pageSize: number; + }; + + const result = await getLicenseRecordsByUid({ + uid: payload.user.nsid, + page: page, + pageSize: pageSize + }); + + return jsonRes(resp, { + data: result + }); + } catch (error) { + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/pay.ts b/service/license/src/pages/api/license/pay.ts new file mode 100644 index 00000000000..ad6a127550c --- /dev/null +++ b/service/license/src/pages/api/license/pay.ts @@ -0,0 +1,84 @@ +import { authSession } from '@/services/backend/auth'; +import { ApplyYaml } from '@/services/backend/kubernetes/user'; +import { jsonRes } from '@/services/backend/response'; +import { LicensePaymentForm } from '@/types'; +import yaml from 'js-yaml'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export const generateLicenseCrd = (form: LicensePaymentForm) => { + const paymentCrd = { + apiVersion: 'infostream.sealos.io/v1', + kind: 'Payment', + metadata: { + name: form.paymentName, + namespace: form.namespace + }, + spec: { + userID: form.userId, + amount: form.amount, // weixin + paymentMethod: form.paymentMethod, + service: { + amt: form.quota, // Actual value + hid: form.hashID, + typ: 'account' + } + } + }; + try { + const result = yaml.dump(paymentCrd); + return result; + } catch (error) { + throw error; + } +}; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const payload = await authSession(req.headers); + if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + + const { amount, paymentMethod, hid, quota } = req.body as { + amount: number; + paymentMethod: 'wechat' | 'stripe'; + hid: string; + quota: number; + }; + console.log(amount, quota, paymentMethod, hid); + if (!hid) { + return jsonRes(resp, { + code: 400, + message: 'Missing hid parameter' + }); + } + if (amount <= 0) { + return jsonRes(resp, { + code: 400, + message: 'Amount cannot be less than 0' + }); + } + + const paymentName = crypto.randomUUID(); + const form: LicensePaymentForm = { + namespace: payload.user.nsid, + paymentName: paymentName, + userId: payload.user.k8s_username, + amount: amount, + quota: quota, + paymentMethod: paymentMethod, + hashID: hid + }; + + const LicenseCrd = generateLicenseCrd(form); + + const res = await ApplyYaml(payload.kc, LicenseCrd); + return jsonRes(resp, { + data: { + paymentName: paymentName, + extra: res[0] + } + }); + } catch (error) { + console.log(error); + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/result.ts b/service/license/src/pages/api/license/result.ts new file mode 100644 index 00000000000..1bab777d5e8 --- /dev/null +++ b/service/license/src/pages/api/license/result.ts @@ -0,0 +1,32 @@ +// import { authSession } from '@/services/backend/auth'; +// import { GetCRD } from '@/services/backend/kubernetes/user'; +// import { jsonRes } from '@/services/backend/response'; +// import type { NextApiRequest, NextApiResponse } from 'next'; + +// export default async function handler(req: NextApiRequest, resp: NextApiResponse) { +// try { +// const payload = await authSession(req.headers); +// if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + +// const { paymentName } = req.query as { +// paymentName: string; +// }; + +// if (typeof paymentName !== 'string' || paymentName === '') { +// return jsonRes(resp, { code: 400, message: 'payment name cannot be empty' }); +// } + +// const paymentM = { +// group: 'infostream.sealos.io', +// version: 'v1', +// namespace: payload.user.nsid, +// plural: 'payments' +// }; +// const paymentDesc = await GetCRD(payload.kc, paymentM, paymentName); +// console.log(paymentDesc?.body?.status, 'payment'); +// return jsonRes(resp, { data: paymentDesc?.body?.status }); +// } catch (error) { +// console.log(error); +// jsonRes(resp, { code: 500, data: error }); +// } +// } diff --git a/service/license/src/pages/api/platform/getEnv.ts b/service/license/src/pages/api/platform/getEnv.ts new file mode 100644 index 00000000000..455c83e8e0f --- /dev/null +++ b/service/license/src/pages/api/platform/getEnv.ts @@ -0,0 +1,49 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; +import { jsonRes } from '@/services/backend/response'; +import { + enableGithub, + enableWechat, + enablePassword, + enableSms, + enableGoogle, + enableStripe, + enableWechatRecharge, + enableLicense +} from '@/services/enable'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + const wechat_client_id = process.env.WECHAT_CLIENT_ID || ''; + const github_client_id = process.env.GITHUB_CLIENT_ID || ''; + const google_client_id = process.env.GOOGLE_CLIENT_ID || ''; + const service_protocol = process.env.SERVICE_PROTOCOL || ''; + const private_protocol = process.env.PRIVATE_PROTOCOL || ''; + const needGithub = enableGithub(); + const needWechat = enableWechat(); + const needPassword = enablePassword(); + const needSms = enableSms(); + const needGoogle = enableGoogle(); + const callback_url = process.env.CALLBACK_URL; + const stripeEnabled = enableStripe(); + const wechatEnabledRecharge = enableWechatRecharge(); + const licenseEnabled = enableLicense(); + + jsonRes(res, { + data: { + SEALOS_CLOUD_DOMAIN: process.env.SEALOS_CLOUD_DOMAIN || 'cloud.sealos.io', + wechat_client_id, + github_client_id, + google_client_id, + callback_url, + service_protocol, + private_protocol, + needPassword, + needSms, + needGithub, + needWechat, + needGoogle, + stripeEnabled, + wechatEnabledRecharge, + licenseEnabled + } + }); +} diff --git a/service/license/src/pages/index.tsx b/service/license/src/pages/index.tsx new file mode 100644 index 00000000000..f51b9e8ab2a --- /dev/null +++ b/service/license/src/pages/index.tsx @@ -0,0 +1,23 @@ +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; + +export default function IndexPage() { + const router = useRouter(); + useEffect(() => { + router.push('/signin'); + }, []); + + return
; +} + +export async function getServerSideProps({ req, res, locales }: any) { + const lang: string = req?.headers?.['accept-language'] || 'zh'; + const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; + + return { + props: { + ...(await serverSideTranslations(local, undefined, null, locales || [])) + } + }; +} diff --git a/service/license/src/pages/license/components/CurrencySymbol.tsx b/service/license/src/pages/license/components/CurrencySymbol.tsx new file mode 100644 index 00000000000..2c6c5e5b8d7 --- /dev/null +++ b/service/license/src/pages/license/components/CurrencySymbol.tsx @@ -0,0 +1,22 @@ +import { Text, Icon, IconProps } from '@chakra-ui/react'; +export default function currencysymbol({ + type = 'shellCoin', + ...props +}: { + type?: 'shellCoin' | 'cny' | 'usd'; +} & Pick) { + return type === 'shellCoin' ? ( + + + + ) : type === 'cny' ? ( + + ) : ( + $ + ); +} diff --git a/service/license/src/pages/license/components/OuterLink.tsx b/service/license/src/pages/license/components/OuterLink.tsx new file mode 100644 index 00000000000..9b347bc4364 --- /dev/null +++ b/service/license/src/pages/license/components/OuterLink.tsx @@ -0,0 +1,35 @@ +import { Flex, Link } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; + +export default function Index({ text, href }: { text: string; href?: string }) { + const { t } = useTranslation(); + return ( + + + + + + {text} + + + ); +} diff --git a/service/license/src/pages/license/components/Pagination.tsx b/service/license/src/pages/license/components/Pagination.tsx new file mode 100644 index 00000000000..f5c3e54c430 --- /dev/null +++ b/service/license/src/pages/license/components/Pagination.tsx @@ -0,0 +1,118 @@ +import { Flex, FlexProps, Icon, Text } from '@chakra-ui/react'; +import { useState } from 'react'; +type PaginationProps = { + totalItems: number; + itemsPerPage: number; + onPageChange: any; +}; + +export default function Pagination({ totalItems, itemsPerPage, onPageChange }: PaginationProps) { + const totalPage = Math.ceil(totalItems / itemsPerPage); + const [currentPage, setCurrentPage] = useState(1); + + const goToPage = (page: number) => { + if (page >= 1 && page <= totalPage) { + setCurrentPage(page); + onPageChange(page); + } + }; + + const handlePrevPage = () => { + goToPage(currentPage - 1); + }; + + const handleNextPage = () => { + goToPage(currentPage + 1); + }; + + const buttonStyle: FlexProps = { + justifyContent: 'center', + alignItems: 'center', + w: '24px', + h: '24px', + borderRadius: '50%' + }; + + return ( + + Total: + {totalItems} + + + + + + + goToPage(1)} + > + + + + + + + {currentPage}/{totalPage} + + + + + + + + goToPage(totalPage)} + > + + + + + + {itemsPerPage} + /Page + + ); +} diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx new file mode 100644 index 00000000000..3484738c796 --- /dev/null +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -0,0 +1,248 @@ +import { getLicenseResult, licensePay, createLicenseRecord } from '@/api/license'; +import { getSystemEnv } from '@/api/system'; +import { WechatIcon } from '@/components/icons'; +import useBonusBox from '@/hooks/useBonusBox'; +import { useCustomToast } from '@/hooks/useCustomToast'; +import { LicensePayload } from '@/types'; +import { deFormatMoney } from '@/utils/format'; +import { + Button, + Checkbox, + Flex, + Link, + Modal, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + Text, + useDisclosure +} from '@chakra-ui/react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; +import { useState } from 'react'; +import WechatPayment from './WechatPayment'; + +export default function RechargeComponent() { + const { t } = useTranslation(); + const [isAgree, setIsAgree] = useState(false); + const [isInvalid, setIsInvalid] = useState(false); + const { BonusBox, selectAmount } = useBonusBox(); + const { isOpen, onOpen, onClose } = useDisclosure(); + // 整个流程跑通需要状态管理, 0 初始态, 1 创建支付单, 2 支付中, 3 支付成功 + const [complete, setComplete] = useState<0 | 1 | 2 | 3>(0); + // 0 是微信,1 是stripe + const [payType, setPayType] = useState<'wechat' | 'stripe'>('wechat'); + const [paymentName, setPaymentName] = useState(''); + const queryClient = useQueryClient(); + const { toast } = useCustomToast(); + const { query } = useRouter(); + const [hid, setHid] = useState(''); // license key + + // handle hid + // useEffect(() => { + // if (query?.hid && typeof query.hid === 'string') { + // const decodedHid = decodeURIComponent(query.hid); + // setHid(decodedHid); + // } else { + // toast({ + // status: 'error', + // title: 'Purchase Link Error', + // isClosable: true, + // position: 'top' + // }); + // } + // }, []); + + const onModalClose = () => { + setComplete(0); + onClose(); + }; + + const handleWechatConfirm = () => { + if (isAgree) { + setComplete(1); + createPaymentLicense.mutate(); + onOpen(); + } else { + toast({ + status: 'error', + title: t('Please read and agree to the agreement'), + isClosable: true, + position: 'top' + }); + } + }; + + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + + const createPaymentLicense = useMutation( + () => + licensePay({ + amount: deFormatMoney(selectAmount), + quota: selectAmount, + paymentMethod: payType, + hid: hid + }), + + { + onSuccess(data) { + console.log(data); + setPaymentName((data?.paymentName as string).trim()); + setComplete(2); + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); + } + } + ); + + const licenseRecordMutation = useMutation( + (payload: LicensePayload) => createLicenseRecord(payload), + { + onSuccess(data) { + console.log(data); + queryClient.invalidateQueries(['getLicenseActive']); + }, + onError(err: any) { + console.log(err); + } + } + ); + + const { data } = useQuery( + ['getLicenseResult', paymentName], + () => getLicenseResult(paymentName), + { + refetchInterval: complete === 2 ? 1000 : false, + enabled: complete === 2 && !!paymentName, + cacheTime: 0, + staleTime: 0, + onSuccess(data) { + if (data?.status === 'Completed') { + onModalClose(); + toast({ + status: 'success', + title: t('Payment Successful'), + isClosable: true, + position: 'top' + }); + licenseRecordMutation.mutate({ + uid: '', + amount: deFormatMoney(selectAmount), + quota: selectAmount, + token: data?.token, + orderID: data?.tradeNO, + paymentMethod: 'wechat' + }); + } + } + } + ); + + return ( + + + {t('Purchase License')} + + + {t('Select Amount')} + + + + { + setIsInvalid(false); + setIsAgree(e.target.checked); + }} + /> + + {t('agree policy')} + + {t('Service Agreement')} + + {t('and')} + + {t('Privacy Policy')} + + + {/* */} + + + {/* {platformEnv?.data?.stripeEnabled && ( + + )} */} + + + + + + + 充值金额 + + + + + + + ); +} diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx new file mode 100644 index 00000000000..92c20b48700 --- /dev/null +++ b/service/license/src/pages/license/components/Record.tsx @@ -0,0 +1,104 @@ +import { ApiResp, LicenseRecord } from '@/types'; +import download from '@/utils/downloadFIle'; +import { formatMoney, getRemainingTime } from '@/utils/format'; +import { Box, Flex, Text } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; +import { useState } from 'react'; +import Pagination from './Pagination'; +import { DownloadIcon, EmptyIcon, LicenseIcon, TokenIcon } from '@/components/icons'; +import { getLicenseRecord } from '@/api/license'; + +export default function History() { + const { t } = useTranslation(); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + + const { data } = useQuery(['getLicenseActive', page, pageSize], () => + getLicenseRecord({ + page: page, + pageSize: pageSize + }) + ); + + const downloadToken = (token: string) => { + const result = Buffer.from(token, 'binary').toString('base64'); + download('token.txt', result); + }; + + return ( + + + {t('Purchase History')} + + {data?.records && data?.records?.length > 0 ? ( + + {data?.records.map((item) => ( + + + + + + License + + + + {formatMoney(item.amount)} + + + + {t('Remaining Time')} {getRemainingTime(item.exp)} + + + + + + + Token + + + + + ))} + + ) : ( + + + + {t('You have not purchased the License')} + + + )} + + + {}} /> + + + ); +} diff --git a/service/license/src/pages/license/components/WechatPayment.tsx b/service/license/src/pages/license/components/WechatPayment.tsx new file mode 100644 index 00000000000..8faacec5885 --- /dev/null +++ b/service/license/src/pages/license/components/WechatPayment.tsx @@ -0,0 +1,60 @@ +import { Flex, Box, Text } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { QRCodeSVG } from 'qrcode.react'; + +export default function WechatPayment(props: { + complete: number; + codeURL?: string; + tradeNO?: string; +}) { + const { t } = useTranslation(); + return ( + + + + {t('Scan with WeChat')} + + {props.complete === 2 && !!props.codeURL ? ( + + ) : ( + waiting... + )} + + + {t('Order Number')}: {props.tradeNO || ''} + + + {t('Payment Result')}:{props.complete === 3 ? t('Payment Successful') : t('In Payment')} + + + + + ); +} diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx new file mode 100644 index 00000000000..0ae86428de7 --- /dev/null +++ b/service/license/src/pages/license/index.tsx @@ -0,0 +1,61 @@ +import LangSelectSimple from '@/components/LangSelect'; +import { Flex, Image, Text } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import RechargeComponent from './components/Recharge'; +import LicenseRecord from './components/Record'; +import { useRouter } from 'next/router'; +import { useQuery } from '@tanstack/react-query'; +import { ApiResp, SystemEnv } from '@/types'; + +export default function LicensePage() { + const { t } = useTranslation(); + const router = useRouter(); + const goHome = () => router.replace('/'); + + return ( + + + logo + + Sealos + + + | {t('License Buy')} + + + + + + + + + ); +} + +export async function getServerSideProps({ req, res, locales }: any) { + const local = req?.cookies?.NEXT_LOCALE || 'en'; + + return { + props: { + ...(await serverSideTranslations(local, undefined, null, locales || [])) + } + }; +} diff --git a/service/license/src/pages/signin.tsx b/service/license/src/pages/signin.tsx new file mode 100644 index 00000000000..5e88304d2a4 --- /dev/null +++ b/service/license/src/pages/signin.tsx @@ -0,0 +1,18 @@ +import SigninComponent from '@/components/signin'; +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; + +export default function SigninPage() { + return ; +} + +export async function getServerSideProps({ req, res, locales }: any) { + const lang: string = req?.headers?.['accept-language'] || 'zh'; + const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; + + const props = { + ...(await serverSideTranslations(local, undefined, null, locales || [])) + }; + return { + props + }; +} diff --git a/service/license/src/services/backend/auth.ts b/service/license/src/services/backend/auth.ts new file mode 100644 index 00000000000..e5248badd08 --- /dev/null +++ b/service/license/src/services/backend/auth.ts @@ -0,0 +1,54 @@ +import { IncomingHttpHeaders } from 'http'; +import { sign, verify } from 'jsonwebtoken'; +import { JWTPayload } from '@/types'; + +const jwtSecret = (process.env.JWT_SECRET as string) || '123456789'; + +export const authSession = async (header: IncomingHttpHeaders) => { + try { + // if (!header?.authorization) { + // throw new Error('缺少凭证'); + // } + // const token = decodeURIComponent(header.authorization); + // const payload = await verifyJWT(token); + // if ( + // !payload || + // !payload.kubeconfig || + // !payload?.user?.uid || + // !payload?.user?.nsid || + // !payload?.user?.ns_uid || + // !payload?.user?.k8s_username + // ) + // throw new Error('token is null'); + // console.log('jwt:', payload.kubeconfig) + // const kc = K8sApi(payload.kubeconfig); + // const username = kc.getCurrentUser()?.name; + // const user = payload.user; + // if (!username || user.k8s_username !== username) throw new Error('user is invaild'); + // return Promise.resolve({ kc, user }); + } catch (err) { + console.error(err, '==='); + return Promise.resolve(null); + } +}; + +export const verifyJWT: (token: string) => Promise = (token: string) => + new Promise((resolve) => { + verify(token, jwtSecret, (err, payload) => { + if (err) { + console.log(err); + resolve(null); + } else if (!payload) { + console.log('payload is null'); + resolve(null); + } else { + resolve(payload as JWTPayload); + } + }); + }); +export const generateJWT = (props: JWTPayload) => { + console.log('jwt: ', props); + return sign(props, jwtSecret, { + expiresIn: '7d' + }); +}; diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts new file mode 100644 index 00000000000..89a59485170 --- /dev/null +++ b/service/license/src/services/backend/db/license.ts @@ -0,0 +1,72 @@ +import { LicensePayload, LicenseRecord } from '@/types'; +import { connectToDatabase } from './mongodb'; + +async function connectLicenseRecordCollection() { + const client = await connectToDatabase(); + const collection = client.db().collection('licenseRecord'); + return collection; +} + +export async function createLicenseRecord({ + uid, + amount, + token, + orderID, + quota, + paymentMethod +}: LicensePayload) { + const collection = await connectLicenseRecordCollection(); + + const now = Math.floor(Date.now() / 1000); // Get current timestamp in seconds + const oneDayInSeconds = 24 * 60 * 60; // One day in seconds + + const record: LicenseRecord = { + uid: uid, + token: token, + orderID: orderID, + paymentMethod: paymentMethod, + service: { + quota: quota + }, + iat: now, // Store the current timestamp as iat + exp: now + oneDayInSeconds, // Set expiration to one day from now (in seconds) + amount: amount + }; + + const result = await collection.insertOne(record); + + return result; +} + +export async function getLicenseRecordsByUid({ + uid, + page, + pageSize +}: { + uid: string; + page: number; + pageSize: number; +}) { + const collection = await connectLicenseRecordCollection(); + + const skip = (page - 1) * pageSize; + + const query = { uid: uid }; + const options = { + skip: skip, + limit: pageSize + }; + + // Find records for the specified uid, skip records based on pagination, and limit the result to pageSize + const records = await collection.find(query, options).sort({ iat: -1 }).toArray(); + + // Calculate the total count of records for the given uid + const totalCount = await collection.countDocuments(query); + + const result = { + records: records, + total: totalCount + }; + + return result; +} diff --git a/service/license/src/services/backend/db/mongodb.ts b/service/license/src/services/backend/db/mongodb.ts new file mode 100644 index 00000000000..4002b36215d --- /dev/null +++ b/service/license/src/services/backend/db/mongodb.ts @@ -0,0 +1,24 @@ +import { MongoClient } from 'mongodb'; + +export async function connectToDatabase() { + if (global.mongodb) { + return global.mongodb; + } + const uri = process.env.MONGODB_URI || ''; + global.mongodb = new MongoClient(uri); + // global.mongodb = 'connecting'; + try { + global.mongodb.on('error', (err) => { + global.mongodb = null; + }); + global.mongodb.on('close', () => { + global.mongodb = null; + }); + await global.mongodb.connect(); + return global.mongodb; + } catch (error) { + console.log('error->', 'mongo connect error'); + global.mongodb = null; + return Promise.reject(error); + } +} diff --git a/service/license/src/services/backend/db/user.ts b/service/license/src/services/backend/db/user.ts new file mode 100644 index 00000000000..e8693c03864 --- /dev/null +++ b/service/license/src/services/backend/db/user.ts @@ -0,0 +1,128 @@ +import { connectToDatabase } from './mongodb'; +import { K8s_user, PROVIDERS, Provider, User } from '@/types/user'; +import { customAlphabet } from 'nanoid'; +import { v4 as uuid } from 'uuid'; +const LetterBytes = 'abcdefghijklmnopqrstuvwxyz0123456789'; +const HostnameLength = 8; + +const nanoid = customAlphabet(LetterBytes, HostnameLength); + +async function connectToUserCollection() { + const client = await connectToDatabase(); + const collection = client.db().collection('user'); + await collection.createIndex({ uid: 1 }, { unique: true }); + await collection.createIndex({ 'k8s_users.name': 1 }, { unique: true, sparse: true }); + await collection.createIndex({ password_user: 1 }, { unique: true, sparse: true }); + return collection; +} + +export async function queryUser({ id, provider }: { id: string; provider: Provider }) { + const users = await connectToUserCollection(); + if (!verifyProvider(provider)) return Promise.reject('provider error'); + return await users.findOne({ [provider]: id }); +} +export async function queryUserByk8sUser(k8s_useranme: string) { + const users = await connectToUserCollection(); + return await users.findOne({ 'k8s_users.name': k8s_useranme }); +} +export async function createUser({ + id, + provider, + name, + avatar_url +}: { + id: string; + provider: Provider; + name: string; + avatar_url: string; +}) { + const users = await connectToUserCollection(); + + let uid = uuid(); + const k8s_username = await get_k8s_username(); + let user: User = { + uid, + avatar_url, + name, + created_time: new Date().toISOString(), + k8s_users: [ + { + name: k8s_username + } + ] + }; + if (!verifyProvider(provider)) return Promise.reject('provider error'); + user[provider] = id; + await users.insertOne(user); + return user; +} +export async function updateUser({ + id, + provider, + data +}: { + id: string; + provider: Provider; + data: Partial>; +}) { + const users = await connectToUserCollection(); + if (!verifyProvider(provider)) return Promise.reject('provider error'); + return await users.updateOne({ [provider]: id }, { $set: data }); +} + +export async function addK8sUser({ + id, + provider, + k8s_user +}: { + id: string; + provider: Provider; + k8s_user: K8s_user; +}) { + const users = await connectToUserCollection(); + if (!verifyProvider(provider)) return Promise.reject('provider error'); + const result = await users.findOneAndUpdate( + { [provider]: id }, + { $addToSet: { k8s_users: k8s_user } } + ); + if (!result.ok) { + return null; + } + return result.value; +} +export async function removeK8sUser({ + id, + provider, + k8s_username +}: { + id: string; + provider: Provider; + k8s_username: string; +}) { + const users = await connectToUserCollection(); + if (!verifyProvider(provider)) return Promise.reject('provider error'); + return await users.updateOne( + { [provider]: id }, + { $pull: { k8s_users: { name: k8s_username } } } + ); +} +function verifyProvider(provider: string): provider is Provider { + return PROVIDERS.includes(provider as Provider); +} +export async function get_k8s_username() { + const users = await connectToUserCollection(); + let k8s_username = nanoid(); + let len = 5; + while ((await users.findOne({ k8s_users: { name: k8s_username } })) && len--) { + k8s_username = nanoid(); + } + if (len < 0) { + return Promise.reject('user are too many to be created'); + } + return k8s_username; +} +export async function removeUser({ id, provider }: { id: string; provider: Provider }) { + const users = await connectToUserCollection(); + if (!verifyProvider(provider)) return Promise.reject('provider error'); + return await users.deleteOne({ [provider]: id }); +} diff --git a/service/license/src/services/backend/db/verifyCode.ts b/service/license/src/services/backend/db/verifyCode.ts new file mode 100644 index 00000000000..24ca81e9220 --- /dev/null +++ b/service/license/src/services/backend/db/verifyCode.ts @@ -0,0 +1,61 @@ +import { connectToDatabase } from './mongodb'; + +type TVerification_Codes = { + phone: string; + code: string; + createdTime: number; +}; + +async function connectToUserCollection() { + const client = await connectToDatabase(); + const collection = client.db().collection('verification_codes'); + await collection.createIndex({ createdTime: 1 }, { expireAfterSeconds: 60 * 5 }); + return collection; +} + +// addOrUpdateCode +export async function addOrUpdateCode({ phone, code }: { phone: string; code: string }) { + const codes = await connectToUserCollection(); + const result = await codes.updateOne( + { + phone + }, + { + $set: { + code, + createdTime: new Date().getTime() + } + }, + { + upsert: true + } + ); + return result; +} + +// checkCode +export async function checkSendable({ phone }: { phone: string }) { + const codes = await connectToUserCollection(); + const result = await codes.findOne({ + phone, + createdTime: { + // 在区间范围内找到就是已经发送过了,不能再发了 + $gt: new Date().getTime() - 60 * 1000, + $lt: new Date().getTime() + } + }); + return !result; +} +// checkCode +export async function checkCode({ phone, code }: { phone: string; code: string }) { + const codes = await connectToUserCollection(); + const result = await codes.findOne({ + phone, + code, + createdTime: { + // 5分钟内有效 + $gt: new Date().getTime() - 5 * 60 * 1000 + } + }); + return !!result; +} diff --git a/service/license/src/services/backend/oauth.ts b/service/license/src/services/backend/oauth.ts new file mode 100644 index 00000000000..926d343f2d8 --- /dev/null +++ b/service/license/src/services/backend/oauth.ts @@ -0,0 +1,193 @@ +import { Session } from '@/types'; +import { generateJWT } from './auth'; +import { addK8sUser, createUser, queryUser, removeUser, updateUser } from './db/user'; +import { Provider, User } from '@/types/user'; +import { getUserKubeconfig, getUserKubeconfigByuid } from './kubernetes/admin'; +import { hashPassword, verifyPassword } from '@/utils/crypto'; +import { createNS, queryNS } from './db/namespace'; +import { GetUserDefaultNameSpace } from './kubernetes/user'; +import { WithId } from 'mongodb'; +import { v4 as uuid } from 'uuid'; +import { createUTN, queryUTN } from './db/userToNamespace'; +import { InvitedStatus, NSType, UserRole } from '@/types/team'; + +export const getOauthRes = async ({ + provider, + id, + name, + avatar_url, + password +}: { + provider: Provider; + id: string; + name: string; + avatar_url: string; + password?: string; +}): Promise => { + if (provider === 'password_user' && !password) { + throw new Error('password is required'); + } + // 翻查一下 ns 和user + const _user = await queryUser({ id, provider }); + let signResult = null; + if (!_user) { + signResult = await signUp({ + provider, + id, + name, + avatar_url, + password + }); + } else { + signResult = await signIn({ + userResult: _user, + provider, + id, + password + }); + } + if (!signResult) throw new Error('Failed to edit db'); + const { k8s_user, namespace, user } = signResult; + const k8s_username = k8s_user.name; + // 登录和注册都需要对k8suser.namespace列做校检 + if (namespace.nstype !== NSType.Private) return Promise.reject('Faild to get private namespace'); + const kubeconfig = await getUserKubeconfig(user.uid, k8s_username); + if (!kubeconfig) { + throw new Error('Failed to get user config'); + } + const token = generateJWT({ + user: { k8s_username, uid: user.uid, nsid: namespace.id, ns_uid: namespace.uid }, + kubeconfig + }); + return { + token, + user: { + name: user.name, + k8s_username, + avatar: user.avatar_url, + nsid: namespace.id, + ns_uid: namespace.uid, + userId: user.uid + }, + kubeconfig + }; +}; +async function signIn({ + userResult: _user, + provider, + id, + password +}: { + provider: Provider; + id: string; + password?: string; + userResult: WithId; +}) { + if (provider === 'password_user') { + if (!_user.password || !password || !verifyPassword(password, _user.password)) { + throw new Error('password error'); + } + } + const k8s_users = _user.k8s_users || []; + const uid = _user.uid; + let k8s_user = null; + // 迁移用户 + if (k8s_users.length === 0) { + const k8s_username = await getUserKubeconfigByuid(uid); + if (!!k8s_username) { + const result = await addK8sUser({ + id: '' + id, + provider, + k8s_user: { + name: k8s_username + } + }); + if (!result) return Promise.reject('Faild to add k8s user'); + k8s_users.push(result); + } + } + k8s_user = k8s_users[0]; + const k8s_username = k8s_user.name; + // 迁移namespace + let namespace = await queryNS({ id: GetUserDefaultNameSpace(k8s_username) }); + if (!namespace) { + namespace = await createNS({ + namespace: GetUserDefaultNameSpace(k8s_username), + nstype: NSType.Private, + teamName: 'private team' + }); + if (!namespace) return Promise.reject('Faild to create namespace'); + } + // 迁移utn + let utn = await queryUTN({ userId: uid, k8s_username, namespaceId: namespace.uid }); + if (!utn) + utn = await createUTN({ + userId: _user.uid, + k8s_username, + namespaceId: namespace.uid, + status: InvitedStatus.Accepted, + role: UserRole.Owner + }); + if (!utn) return Promise.reject('Faild to add namesapce'); + const user: User = { + ..._user, + k8s_users + }; + return { + user, + k8s_user, + namespace + }; +} +// 注册 +async function signUp({ + provider, + id, + name, + avatar_url, + password +}: { + provider: Provider; + id: string; + name: string; + avatar_url: string; + password?: string; +}) { + const ns_uid = uuid(); + const user = await createUser({ id, provider, name, avatar_url }); + if (provider === 'password_user') { + await updateUser({ + id, + provider: 'password_user', + data: { password: hashPassword(password!) } + }).catch(async (_) => { + await removeUser({ id: '' + id, provider: 'password_user' }); + throw new Error('Failed to create user by password'); + }); + } + const k8s_users = user.k8s_users || []; + const userId = user.uid; + if (!k8s_users) return null; + const k8s_user = k8s_users[0]; + const k8s_username = k8s_user.name; + const namespace = await createNS({ + namespace: GetUserDefaultNameSpace(k8s_username), + nstype: NSType.Private, + teamName: 'private team', + uid: ns_uid + }); + if (!namespace) return null; + const utn = await createUTN({ + namespaceId: namespace.uid, + k8s_username: k8s_user.name, + userId, + status: InvitedStatus.Accepted, + role: UserRole.Owner + }); + if (!utn) return null; + return { + user, + k8s_user, + namespace + }; +} diff --git a/service/license/src/services/backend/response.ts b/service/license/src/services/backend/response.ts new file mode 100644 index 00000000000..582b804b3ad --- /dev/null +++ b/service/license/src/services/backend/response.ts @@ -0,0 +1,30 @@ +import { NextApiResponse } from 'next'; + +export const jsonRes = ( + res: NextApiResponse, + props?: { + code?: number; + message?: string; + data?: T; + error?: any; + } +) => { + const { code = 200, message = '', data = null, error } = props || {}; + + // another error + let msg = message; + if ((code < 200 || code >= 400) && !message) { + msg = error?.body?.message || error?.message || '请求错误'; + if (typeof error === 'string') { + msg = error; + } + console.error('===jsonRes error===\n ', error); + } + + res.json({ + code, + statusText: '', + message: msg, + data: data || error || null + }); +}; diff --git a/service/license/src/services/enable.ts b/service/license/src/services/enable.ts new file mode 100644 index 00000000000..322f9e35ae4 --- /dev/null +++ b/service/license/src/services/enable.ts @@ -0,0 +1,32 @@ +// for service +export const enablePassword = () => + process.env.PASSWORD_ENABLED === 'true' && !!process.env.PASSWORD_SALT; +export const enableGithub = () => + process.env.GITHUB_ENABLED === 'true' && + !!process.env.GITHUB_CLIENT_ID && + !!process.env.GITHUB_CLIENT_SECRET; +export const enableSms = () => + process.env.SMS_ENABLED === 'true' && + !!process.env.ALI_ACCESS_KEY_ID && + !!process.env.ALI_ACCESS_KEY_SECRET && + !!process.env.ALI_SIGN_NAME && + !!process.env.ALI_TEMPLATE_CODE; +export const enableWechat = () => + process.env.WECHAT_ENABLED === 'true' && + !!process.env.WECHAT_CLIENT_ID && + !!process.env.WECHAT_CLIENT_SECRET; +export const enableGoogle = () => + process.env.GOOGLE_ENABLED === 'true' && + !!process.env.GOOGLE_CLIENT_ID && + !!process.env.GOOGLE_CLIENT_SECRET; +export const enableRecharge = () => { + return process.env.RECHARGE_ENABLED === 'true'; +}; +// costcenter +export const enableStripe = () => + process.env['STRIPE_ENABLED'] === 'true' && !!process.env['STRIPE_PUB']; +export const enableWechatRecharge = () => process.env['WECHAT_ENABLED'] === 'true'; +// license +export const enableLicense = () => { + return process.env.LICENSE_ENABLED === 'true'; +}; diff --git a/service/license/src/services/request.ts b/service/license/src/services/request.ts new file mode 100644 index 00000000000..04de9f37452 --- /dev/null +++ b/service/license/src/services/request.ts @@ -0,0 +1,136 @@ +import useSessionStore from '@/stores/session'; +import { ApiResp } from '@/types'; +import axios, { + InternalAxiosRequestConfig, + AxiosHeaders, + AxiosResponse, + AxiosRequestConfig +} from 'axios'; + +const showStatus = (status: number) => { + let message = ''; + switch (status) { + case 400: + message = '请求错误(400)'; + break; + case 401: + message = '未授权,请重新登录(401)'; + break; + case 403: + message = '拒绝访问(403)'; + break; + case 404: + message = '请求出错(404)'; + break; + case 408: + message = '请求超时(408)'; + break; + case 500: + message = '服务器错误(500)'; + break; + case 501: + message = '服务未实现(501)'; + break; + case 502: + message = '网络错误(502)'; + break; + case 503: + message = '服务不可用(503)'; + break; + case 504: + message = '网络超时(504)'; + break; + case 505: + message = 'HTTP版本不受支持(505)'; + break; + default: + message = `连接出错(${status})!`; + } + return `${message},请检查网络或联系管理员!`; +}; + +const request = axios.create({ + baseURL: '/', + withCredentials: true, + timeout: 30000 +}); + +// request interceptor +request.interceptors.request.use( + (config: InternalAxiosRequestConfig) => { + let _headers: AxiosHeaders = config.headers || {}; + + const session = useSessionStore.getState().session; + _headers['Authorization'] = encodeURIComponent(session.token); + + if (!config.headers || config.headers['Content-Type'] === '') { + _headers['Content-Type'] = 'application/json'; + } + + config.headers = _headers; + return config; + }, + (error: any) => { + error.data = {}; + error.data.msg = '服务器异常,请联系管理员!'; + return Promise.resolve(error); + } +); + +// response interceptor +request.interceptors.response.use( + (response: AxiosResponse) => { + const { status, data } = response; + if (status < 200 || status >= 300) { + return Promise.reject( + status + ':' + showStatus(status) + ', ' + typeof data === 'string' ? data : String(data) + ); + } + + const apiResp = data as ApiResp; + if (apiResp.code < 200 || apiResp.code >= 400) { + return Promise.reject(apiResp); + } + + response.data = apiResp.data; + return response.data; + }, + (error: any) => { + if (axios.isCancel(error)) { + return Promise.reject('cancel request' + String(error)); + } else { + error.errMessage = '请求超时或服务器异常,请检查网络或联系管理员!'; + } + return Promise.reject(error); + } +); + +export function GET( + url: string, + data?: { [key: string]: any }, + config?: AxiosRequestConfig +): Promise { + return request.get(url, { + params: data, + ...config + }); +} + +export function POST( + url: string, + data?: { [key: string]: any }, + config?: AxiosRequestConfig +): Promise { + return request.post(url, data, config); +} + +export function DELETE( + url: string, + data?: { [key: string]: any }, + config?: AxiosRequestConfig +): Promise { + return request.get(url, { + params: data, + ...config + }); +} diff --git a/service/license/src/stores/session.ts b/service/license/src/stores/session.ts new file mode 100644 index 00000000000..28b87be50f5 --- /dev/null +++ b/service/license/src/stores/session.ts @@ -0,0 +1,58 @@ +import { Session, sessionKey } from '@/types'; +import { OauthProvider } from '@/types/user'; +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import { immer } from 'zustand/middleware/immer'; + +type SessionState = { + session: Session; + provider?: OauthProvider; + oauth_state: string; + setSession: (ss: Session) => void; + setSessionProp: (key: T, value: Session[T]) => void; + getSession: () => Session; + delSession: () => void; + isUserLogin: () => boolean; + generateState: () => string; + compareState: (state: string) => boolean; + setProvider: (provider?: OauthProvider) => void; +}; + +const useSessionStore = create()( + persist( + immer((set, get) => ({ + session: {} as Session, + provider: undefined, + oauth_state: '', + setSession: (ss: Session) => set({ session: ss }), + setSessionProp: (key: keyof Session, value: any) => { + set((state) => { + state.session[key] = value; + }); + }, + getSession: () => get().session, + delSession: () => { + set({ session: undefined }); + }, + isUserLogin: () => !!get().session?.user, + generateState: () => { + const state = new Date().getTime().toString(); + set({ oauth_state: state }); + return state; + }, + compareState: (state: string) => { + let result = state === get().oauth_state; + set({ oauth_state: undefined }); + return result; + }, + setProvider: (provider?: OauthProvider) => { + set({ provider }); + } + })), + { + name: sessionKey + } + ) +); + +export default useSessionStore; diff --git a/service/license/src/styles/globals.css b/service/license/src/styles/globals.css new file mode 100644 index 00000000000..0b422cf8dc0 --- /dev/null +++ b/service/license/src/styles/globals.css @@ -0,0 +1,69 @@ +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +html, +body, +#__next { + width: 100vw; + height: 100vh; + overflow: hidden; +} + +iframe { + border: none; +} + +::-webkit-scrollbar, +::-webkit-scrollbar { + width: 8px; + height: 8px; + border-radius: 8px; +} +::-webkit-scrollbar-track, +::-webkit-scrollbar-track { + background: transparent; + border-radius: 6px; +} +::-webkit-scrollbar-thumb, +::-webkit-scrollbar-thumb { + background: #6a6969; + border-radius: 6px; +} +::-webkit-scrollbar-thumb:hover, +::-webkit-scrollbar-thumb:hover { + background: #999; +} + +::-webkit-scrollbar-corner { + background-color: transparent; +} + +.icon { + width: 16px; + height: 16px; + vertical-align: -0.15em; + fill: currentColor; + overflow: hidden; +} + +div { + &::-webkit-scrollbar-thumb, + &::-webkit-scrollbar-thumb { + background: transparent !important; + border-radius: 10px; + transition: 1s; + } + &:hover { + &::-webkit-scrollbar-thumb, + &::-webkit-scrollbar-thumb { + background: rgba(189, 193, 197, 0.5) !important; + } + &::-webkit-scrollbar-thumb:hover, + &::-webkit-scrollbar-thumb:hover { + background: rgba(189, 193, 197, 1) !important; + } + } +} diff --git a/service/license/src/styles/theme.ts b/service/license/src/styles/theme.ts new file mode 100644 index 00000000000..17073e21deb --- /dev/null +++ b/service/license/src/styles/theme.ts @@ -0,0 +1,52 @@ +import { defineStyleConfig, extendTheme } from '@chakra-ui/react'; + +const Button = defineStyleConfig({ + baseStyle: { + borderRadius: '4px' + }, + sizes: { + sm: {}, + md: {}, + primary: { + width: '215px', + height: '36px' + } + }, + variants: { + primary: { + bg: '#3E3B3B', + _hover: { + bg: '#3E3B3B', + _disabled: { + bg: '#3E3B3B' + } + }, + color: '#FEFEFE' + } + } +}); + +const Input = defineStyleConfig({}); + +const Select = defineStyleConfig({ + variants: { + filled: { + field: { + backgroundColor: '#F4F6F8' + } + } + }, + defaultProps: { + size: 'md', + variant: 'filled' + } +}); + +export const theme = extendTheme({ + initialColorMode: 'light', + components: { + Button, + Input, + Select + } +}); diff --git a/service/license/src/types/api.ts b/service/license/src/types/api.ts new file mode 100644 index 00000000000..1d870a4ce85 --- /dev/null +++ b/service/license/src/types/api.ts @@ -0,0 +1,8 @@ +export interface ApiResp { + code: number; + message: string; + data?: T; +} + +export const INVITE_LIMIT = 5; +export const TEAM_LIMIT = 5; diff --git a/service/license/src/types/index.ts b/service/license/src/types/index.ts new file mode 100644 index 00000000000..ba2a9d1aac0 --- /dev/null +++ b/service/license/src/types/index.ts @@ -0,0 +1,12 @@ +import { type MongoClient } from 'mongodb'; +export * from './api'; +export * from './session'; +export * from './payment'; +export * from './system'; +export * from './login'; +export * from './valuation'; +export * from './license'; + +declare global { + var mongodb: MongoClient | null; +} diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts new file mode 100644 index 00000000000..69d699c2f71 --- /dev/null +++ b/service/license/src/types/license.ts @@ -0,0 +1,63 @@ +export type LicenseCrd = { + apiVersion: 'infostream.sealos.io/v1'; + kind: 'Payment'; + metadata: { + name: string; + namespace: string; + }; + spec: { + userID: string; + amount: number; + paymentMethod: 'wechat' | 'stripe'; + service: { + amt: number; + objType: string; // 'external,internal' + }; + }; + status: { + tradeNO: string; + codeURL: string; + status: 'Created' | 'Completed'; + token: string; + }; +}; + +export type LicensePaymentForm = { + paymentName: string; + namespace: string; + userId: string; + amount: number; + paymentMethod: 'wechat' | 'stripe'; + hashID: string; + quota: number; +}; + +export type LicensePayStatus = { + tradeNO: string; + codeURL: string; + status: 'Created' | 'Completed'; + token: string; +}; + +export type LicenseRecord = { + _id?: string; + uid: string; // user id + token: string; // license token + orderID: string; // order number + paymentMethod: 'wechat' | 'stripe'; + service: { + quota: number; // 额度 + }; + iat: number; // 签发日期 + exp: number; // 有效期 + amount: number; // 消费金额 +}; + +export type LicensePayload = { + uid: string; + amount: number; + token: string; + orderID: string; + quota: number; + paymentMethod: 'wechat' | 'stripe'; +}; diff --git a/service/license/src/types/login.ts b/service/license/src/types/login.ts new file mode 100644 index 00000000000..fbaa3ff620c --- /dev/null +++ b/service/license/src/types/login.ts @@ -0,0 +1,5 @@ +export enum LoginType { + SMS, + PASSWORD, + NONE +} diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts new file mode 100644 index 00000000000..a62800b453e --- /dev/null +++ b/service/license/src/types/payment.ts @@ -0,0 +1,58 @@ +import * as yaml from 'js-yaml'; +import { CRDMeta } from './crd'; + +export type PaymentForm = { + paymentName: string; + namespace: string; + userId: string; + amount: string; +}; + +export const paymentMeta: CRDMeta = { + group: 'account.sealos.io', + version: 'v1', + namespace: 'sealos-system', + plural: 'payments' +}; + +export type Payment = { + paymentName: string; + extra: { + apiVersion: 'account.sealos.io/v1'; + kind: 'Payment'; + metadata: unknown; + spec: { + amount: number; + paymentMethod: string; + userID: string; + }; + }; +}; +export type Pay = { + codeURL: string; + status?: 'Created' | 'SUCCESS'; + tradeNO: string; +}; + +export const generatePaymentCrd = (form: PaymentForm) => { + const paymentCrd = { + apiVersion: 'account.sealos.io/v1', + kind: 'Payment', + metadata: { + name: form.paymentName, + namespace: form.namespace + }, + spec: { + userID: form.userId, + amount: form.amount, + paymentMethod: 'wechat' + } + }; + + try { + const result = yaml.dump(paymentCrd); + return result; + } catch (error) { + return ''; + } +}; diff --git a/service/license/src/types/session.ts b/service/license/src/types/session.ts new file mode 100644 index 00000000000..e8c3cd86477 --- /dev/null +++ b/service/license/src/types/session.ts @@ -0,0 +1,32 @@ +export type OAuthToken = { + readonly access_token: string; + readonly token_type: string; + readonly refresh_token: string; + readonly expiry: string; +}; + +export type UserInfo = { + readonly k8s_username: string; + readonly name: string; + readonly avatar: string; + readonly nsid: string; + readonly ns_uid: string; + readonly userId: string; +}; + +export type KubeConfig = string; + +export type Session = { + token: string; // jwt token + // 提供一些简单的信息 + user: UserInfo; + // 帮忙导出用的 + kubeconfig: KubeConfig; +}; + +export type JWTPayload = { + kubeconfig: KubeConfig; + user: Record<'uid' | 'nsid' | 'k8s_username' | 'ns_uid', string>; +}; + +export const sessionKey = 'session'; diff --git a/service/license/src/types/system.ts b/service/license/src/types/system.ts new file mode 100644 index 00000000000..3fa09f8bbba --- /dev/null +++ b/service/license/src/types/system.ts @@ -0,0 +1,29 @@ +export type SystemConfigType = { + scripts: ScriptConfig[]; +}; + +export type ScriptConfig = { + src: string; + 'data-website-id'?: string; +}; + +export type LoginProps = { + wechat_client_id: string; + github_client_id: string; + google_client_id: string; + callback_url: string; + service_protocol: string; + private_protocol: string; + needPassword: boolean; + needSms: boolean; + needGithub: boolean; + needWechat: boolean; + needGoogle: boolean; +}; + +export type SystemEnv = { + SEALOS_CLOUD_DOMAIN: string; + stripeEnabled: boolean; + wechatEnabledRecharge: boolean; + licenseEnabled: boolean; +} & LoginProps; diff --git a/service/license/src/types/user.ts b/service/license/src/types/user.ts new file mode 100644 index 00000000000..2a7880422e5 --- /dev/null +++ b/service/license/src/types/user.ts @@ -0,0 +1,93 @@ +export type TgithubToken = { + access_token: string; + expires_in: number; + refresh_token: string; + refresh_token_expires_in: number; + token_type: 'bearer'; + scope: string; +}; + +export type TWechatToken = { + access_token: string; + expires_in: number; + refresh_token: string; + openid: string; + scope: string; + is_snapshotuser: 1; + unionid: string; +}; +export type TWechatUser = { + openid: string; + nickname: string; + sex: number; + province: string; + city: string; + country: string; + headimgurl: string; + privilege: string[]; + unionid: string; +}; +export type TgithubUser = { + login: string; + id: number; + node_id: string; + avatar_url: string; + gravatar_id: string; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: 'User'; + site_admin: false; + name: string; + company: string; + blog: string; + location: string; + email: string; + hireable: string; + bio: string; + twitter_username: string; + public_repos: number; + public_gists: number; + followers: number; + following: number; + created_at: string; + updated_at: string; +}; +// if default, uid +export const PROVIDERS = ['github', 'wechat', 'phone', 'uid', 'password_user', 'google'] as const; +export type Provider = (typeof PROVIDERS)[number]; +export type OauthProvider = Exclude; +export type TUserExist = { user: string; exist: boolean }; + +export type K8s_user = { + name: string; +}; +export type User = { + uid: string; + avatar_url: string; + name: string; + github?: string; + wechat?: string; + google?: string; + phone?: string; + k8s_users?: K8s_user[]; + created_time: string; + password?: string; + password_user?: string; +}; + +export type UserDto = { + uid: string; + avatarUrl: string; + name: string; + k8s_username: string; + createdTime: string; +}; diff --git a/service/license/src/types/valuation.ts b/service/license/src/types/valuation.ts new file mode 100644 index 00000000000..da4244ceb53 --- /dev/null +++ b/service/license/src/types/valuation.ts @@ -0,0 +1,18 @@ +export type ValuationStandard = { + name: string; + unit: string; + price: string; +}; +export type ValuationBillingRecord = { + price: number; + resourceType: string; +}; +export type ValuationData = { + apiVersion: 'account.sealos.io/v1'; + kind: 'PriceQuery'; + metadata: any; + spec: {}; + status: { + billingRecords: ValuationBillingRecord[]; + }; +}; diff --git a/service/license/src/utils/cookieUtils.ts b/service/license/src/utils/cookieUtils.ts new file mode 100644 index 00000000000..89c9c5aac5b --- /dev/null +++ b/service/license/src/utils/cookieUtils.ts @@ -0,0 +1,13 @@ +import Cookies, { CookieAttributes } from 'js-cookie'; + +export const setCookie = (key: string, value: string, options?: CookieAttributes) => { + Cookies.set(key, value, options); +}; + +export const getCookie = (key: string) => { + return Cookies.get(key); +}; + +export const removeCookie = (key: string) => { + Cookies.remove(key); +}; diff --git a/service/license/src/utils/crypto.ts b/service/license/src/utils/crypto.ts new file mode 100644 index 00000000000..40f2bcb9c33 --- /dev/null +++ b/service/license/src/utils/crypto.ts @@ -0,0 +1,15 @@ +import * as crypto from 'crypto'; + +// use sha256 to hash the password +export function hashPassword(password: string): string { + const hash = crypto.createHash('sha256'); + hash.update(password + process.env.PASSWORD_SALT); + return hash.digest('hex'); +} + +export const verifyPassword = (password: string, hash: string): boolean => + hashPassword(password) === hash; + +export const strongPassword = (password: string): boolean => /^(?=.*\S).{8,}$/.test(password); + +export const strongUsername = (username: string): boolean => /^[a-zA-Z0-9_-]{3,16}$/.test(username); diff --git a/service/license/src/utils/downloadFIle.ts b/service/license/src/utils/downloadFIle.ts new file mode 100644 index 00000000000..f0837599ae2 --- /dev/null +++ b/service/license/src/utils/downloadFIle.ts @@ -0,0 +1,14 @@ +function download(filename: string, text: string) { + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); +} + +export default download; diff --git a/service/license/src/utils/format.ts b/service/license/src/utils/format.ts new file mode 100644 index 00000000000..5f24f135ef4 --- /dev/null +++ b/service/license/src/utils/format.ts @@ -0,0 +1,54 @@ +import dayjs from 'dayjs'; + +export const formatTime = (time: string | number | Date, format = 'YYYY-MM-DD HH:mm:ss') => { + return dayjs(time).format(format); +}; +export const k8sFormatTime = (time: string | number | Date) => { + return dayjs(time).format('TYYMM-DDTHH-mm-ss'); +}; +// 1¥=10000 +export const formatMoney = (mone: number) => { + return mone / 1000000; +}; +export const deFormatMoney = (money: number) => money * 1000000; + +export function formatUrl(url: string, query: Record) { + const urlObj = new URL(url); + // 添加新的查询参数 + for (const key in query) { + urlObj.searchParams.append(key, query[key]); + } + return urlObj.toString(); +} +export const parseOpenappQuery = (openapp: string) => { + let param = decodeURIComponent(openapp); + const firstQuestionMarkIndex = param.indexOf('?'); + let appkey = ''; + let appQuery = ''; + if (firstQuestionMarkIndex === -1) { + appkey = param; + } else { + appkey = param.substring(0, firstQuestionMarkIndex); + appQuery = param.substring(firstQuestionMarkIndex + 1); + } + return { + appkey, + appQuery + }; +}; + +export const getRemainingTime = (expirationTime: number) => { + const currentTime = Math.floor(Date.now() / 1000); + + if (currentTime >= expirationTime) { + return 'expired'; + } + + const remainingTimeInSeconds = expirationTime - currentTime; + const hours = Math.floor(remainingTimeInSeconds / 3600); + const minutes = Math.floor((remainingTimeInSeconds % 3600) / 60); + const seconds = remainingTimeInSeconds % 60; + + const formattedTime = `${hours}小时${minutes}分钟`; + return formattedTime; +}; diff --git a/service/license/src/utils/tools.ts b/service/license/src/utils/tools.ts new file mode 100644 index 00000000000..d76567495c6 --- /dev/null +++ b/service/license/src/utils/tools.ts @@ -0,0 +1,66 @@ +import dayjs from 'dayjs'; + +export const formatTime = (time: string | number | Date, format = 'YYYY-MM-DD HH:mm:ss') => { + return dayjs(time).format(format); +}; + +// 1¥=10000 +export const formatMoney = (money: number) => { + return (money / 10000).toFixed(2); +}; + +export function appWaitSeconds(ms: number) { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, ms); + }); +} +export async function getBase64FromRemote(url: string) { + try { + const res = await fetch(url); + const blob = await res.blob(); + const blobToBase64 = (blob: Blob) => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(blob); + reader.onload = () => { + const dataUrl = reader.result; + resolve(dataUrl); + }; + reader.onerror = (error) => { + reject(error); + }; + }); + + return await blobToBase64(blob); + } catch { + return ''; + } +} + +export const getFavorable = + (steps: number[] = [], ratios: number[] = []) => + (amount: number) => { + let ratio = 0; + + const step = [...steps].reverse().findIndex((step) => amount >= step); + if (ratios.length > step && step > -1) ratio = [...ratios].reverse()[step]; + return Math.floor((amount * ratio) / 100); + }; +export const retrySerially = (fn: () => Promise, times: number) => + new Promise((res, rej) => { + let retries = 0; + const attempt = () => { + fn() + .then((_res) => { + res(_res); + }) + .catch((error) => { + retries++; + console.log(`Attempt ${retries} failed: ${error}`); + retries < times ? attempt() : rej(error); + }); + }; + attempt(); + }); diff --git a/service/license/tsconfig.json b/service/license/tsconfig.json new file mode 100644 index 00000000000..3ca6a9a50cb --- /dev/null +++ b/service/license/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} From d7c1ca53e0f57bf506a719e51fb262182c17c636 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Tue, 17 Oct 2023 14:44:30 +0800 Subject: [PATCH 02/17] done --- service/license/.dockerignore | 12 ++ service/license/Dockerfile | 72 ++++++++ service/license/public/images/empty.svg | 5 - service/license/src/api/license.ts | 1 - service/license/src/api/system.ts | 5 +- service/license/src/api/user.ts | 11 ++ .../license/src/components/account/index.tsx | 86 ++++++++++ .../src/components/icons/CodeDoneIcon.tsx | 17 ++ .../components/icons/DownloadIcon copy 2.tsx | 14 -- .../src/components/icons/SignOutIcon.tsx | 14 ++ .../src/components/icons/VectorIcon.tsx | 8 + service/license/src/components/icons/index.ts | 3 + .../components/signin/auth/useAuthList.tsx | 1 - .../components/signin/auth/useCustomError.tsx | 2 +- .../components/signin/auth/usePassword.tsx | 44 +---- .../src/components/signin/auth/useSms.tsx | 25 +-- .../license/src/components/signin/index.tsx | 15 +- service/license/src/pages/404.tsx | 6 +- service/license/src/pages/_app.tsx | 3 +- .../src/pages/api/auth/oauth/wechat/index.ts | 1 + .../src/pages/api/auth/password/index.ts | 2 +- .../src/pages/api/auth/phone/verify.ts | 1 + .../pages/api/license/createLicenseRecord.ts | 2 +- .../src/pages/api/license/getLicense.ts | 31 ++++ .../src/pages/api/license/getLicenseRecord.ts | 5 +- service/license/src/pages/api/license/pay.ts | 154 +++++++++--------- service/license/src/pages/api/price/bonus.ts | 25 +++ service/license/src/pages/callback.tsx | 42 +++++ service/license/src/pages/index.tsx | 23 +-- .../pages/license/components/Pagination.tsx | 4 + service/license/src/pages/license/index.tsx | 2 + service/license/src/services/backend/auth.ts | 30 ++-- .../license/src/services/backend/db/user.ts | 102 +++--------- service/license/src/services/backend/oauth.ts | 139 +++------------- .../license/src/services/backend/response.ts | 2 +- service/license/src/services/request.ts | 12 +- .../src/styles/{theme.ts => chakraTheme.ts} | 0 service/license/src/types/index.ts | 1 - service/license/src/types/payment.ts | 58 +++---- service/license/src/types/session.ts | 20 +-- service/license/src/types/user.ts | 32 ++-- service/license/src/types/valuation.ts | 18 -- service/license/src/utils/cookieUtils.ts | 4 +- 43 files changed, 562 insertions(+), 492 deletions(-) create mode 100644 service/license/.dockerignore create mode 100644 service/license/Dockerfile delete mode 100644 service/license/public/images/empty.svg create mode 100644 service/license/src/components/account/index.tsx create mode 100644 service/license/src/components/icons/CodeDoneIcon.tsx delete mode 100644 service/license/src/components/icons/DownloadIcon copy 2.tsx create mode 100644 service/license/src/components/icons/SignOutIcon.tsx create mode 100644 service/license/src/components/icons/VectorIcon.tsx create mode 100644 service/license/src/pages/api/license/getLicense.ts create mode 100644 service/license/src/pages/api/price/bonus.ts create mode 100644 service/license/src/pages/callback.tsx rename service/license/src/styles/{theme.ts => chakraTheme.ts} (100%) delete mode 100644 service/license/src/types/valuation.ts diff --git a/service/license/.dockerignore b/service/license/.dockerignore new file mode 100644 index 00000000000..4094b29f24c --- /dev/null +++ b/service/license/.dockerignore @@ -0,0 +1,12 @@ +Dockerfile +.dockerignore +node_modules +npm-debug.log +README.md +.next +.git +.env.local +config.yaml + +.yalc/ +yalc.lock \ No newline at end of file diff --git a/service/license/Dockerfile b/service/license/Dockerfile new file mode 100644 index 00000000000..32e15899dcc --- /dev/null +++ b/service/license/Dockerfile @@ -0,0 +1,72 @@ +# Copyright © 2022 sealos. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Install dependencies only when needed +FROM node:current-alpine AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat && npm install -g pnpm +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json pnpm-lock.yaml* ./ +RUN \ + [ -f pnpm-lock.yaml ] && pnpm install || \ + (echo "Lockfile not found." && exit 1) + +# Rebuild the source code only when needed +FROM node:current-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry during the build. +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN npm install -g pnpm && pnpm run build + +# Production image, copy all the files and run next +FROM node:current-alpine AS runner +WORKDIR /app + +ENV NODE_ENV production +# Uncomment the following line in case you want to disable telemetry during runtime. +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +RUN sed -i 's/https/http/' /etc/apk/repositories +RUN apk add curl \ + && apk add ca-certificates \ + && update-ca-certificates + +# You only need to copy next.config.js if you are NOT using the default configuration +# COPY --from=builder /app/next.config.js ./ +COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +CMD ["node", "server.js"] diff --git a/service/license/public/images/empty.svg b/service/license/public/images/empty.svg deleted file mode 100644 index f213a801161..00000000000 --- a/service/license/public/images/empty.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/service/license/src/api/license.ts b/service/license/src/api/license.ts index 6b67abba7fb..be5c8ec6568 100644 --- a/service/license/src/api/license.ts +++ b/service/license/src/api/license.ts @@ -1,6 +1,5 @@ import { GET, POST } from '@/services/request'; import { LicensePayStatus, LicensePayload, LicenseRecord, Payment } from '@/types'; -import { number } from 'react-i18next/icu.macro'; export const licensePay = ({ amount, diff --git a/service/license/src/api/system.ts b/service/license/src/api/system.ts index 016af92c008..34799395b8f 100644 --- a/service/license/src/api/system.ts +++ b/service/license/src/api/system.ts @@ -1,7 +1,10 @@ import { GET } from '@/services/request'; import { SystemEnv } from '@/types'; -export const getSystemEnv = () => GET('/api/platform/getEnv'); +export const getSystemEnv = (): Promise => + fetch('/api/platform/getEnv') + .then((res) => res.json()) + .then((res) => res.data); export const getPriceBonus = () => GET<{ diff --git a/service/license/src/api/user.ts b/service/license/src/api/user.ts index c5a7cd4e108..04717288df7 100644 --- a/service/license/src/api/user.ts +++ b/service/license/src/api/user.ts @@ -8,6 +8,17 @@ export const signInByPhone = (phoneNumbers: string, code: string) => code: code }); +export const signInByPassword = (username: string, password: string) => + POST('/api/auth/password', { + user: username, + password: password + }); + +export const signInByProvider = (provider: string, code: string | string[]) => + POST(`/api/auth/oauth/${provider}`, { + code + }); + export const sendCodeByPhone = (phoneNumbers: string) => POST('/api/auth/phone/sms', { phoneNumbers: phoneNumbers diff --git a/service/license/src/components/account/index.tsx b/service/license/src/components/account/index.tsx new file mode 100644 index 00000000000..2414dc6f4eb --- /dev/null +++ b/service/license/src/components/account/index.tsx @@ -0,0 +1,86 @@ +import useSessionStore from '@/stores/session'; +import { Box, Flex, Image, useDisclosure, Text, Divider } from '@chakra-ui/react'; +import { SignOutIcon } from '../icons'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; + +export default function Account() { + const { t } = useTranslation(); + const router = useRouter(); + const { delSession, getSession } = useSessionStore(); + const userInfo = getSession(); + const accountDisclosure = useDisclosure(); + + const logout = (e: React.MouseEvent) => { + e.preventDefault(); + delSession(); + router.replace('/signin'); + }; + + return ( + + user avator + {accountDisclosure.isOpen && ( + <> + { + e.stopPropagation(); + accountDisclosure.onClose(); + }} + > + + + + user avator + {userInfo?.user?.name} + + + + + + {t('Log Out')} + + + + + )} + + ); +} diff --git a/service/license/src/components/icons/CodeDoneIcon.tsx b/service/license/src/components/icons/CodeDoneIcon.tsx new file mode 100644 index 00000000000..efc1e958cb3 --- /dev/null +++ b/service/license/src/components/icons/CodeDoneIcon.tsx @@ -0,0 +1,17 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const CodeDoneIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/DownloadIcon copy 2.tsx b/service/license/src/components/icons/DownloadIcon copy 2.tsx deleted file mode 100644 index b37347364f8..00000000000 --- a/service/license/src/components/icons/DownloadIcon copy 2.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Icon, IconProps } from '@chakra-ui/react'; -export const DownloadIcon = (props: IconProps) => { - return ( - - - - ); -}; diff --git a/service/license/src/components/icons/SignOutIcon.tsx b/service/license/src/components/icons/SignOutIcon.tsx new file mode 100644 index 00000000000..deb50f6737e --- /dev/null +++ b/service/license/src/components/icons/SignOutIcon.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const SignOutIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/VectorIcon.tsx b/service/license/src/components/icons/VectorIcon.tsx new file mode 100644 index 00000000000..1d1b37e309d --- /dev/null +++ b/service/license/src/components/icons/VectorIcon.tsx @@ -0,0 +1,8 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const VectorIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/index.ts b/service/license/src/components/icons/index.ts index f19aaf2c4c6..3f3ea119952 100644 --- a/service/license/src/components/icons/index.ts +++ b/service/license/src/components/icons/index.ts @@ -21,3 +21,6 @@ export * from './EmptyIcon'; export * from './LicenseIcon'; export * from './DownloadIcon'; export * from './TokenIcon'; +export * from './CodeDoneIcon'; +export * from './VectorIcon'; +export * from './SignOutIcon'; diff --git a/service/license/src/components/signin/auth/useAuthList.tsx b/service/license/src/components/signin/auth/useAuthList.tsx index cdf87532ee6..f5aaf5d245c 100644 --- a/service/license/src/components/signin/auth/useAuthList.tsx +++ b/service/license/src/components/signin/auth/useAuthList.tsx @@ -1,7 +1,6 @@ import { getSystemEnv } from '@/api/system'; import { GithubIcon, GoogleIcon, WechatIcon } from '@/components/icons'; import useSessionStore from '@/stores/session'; -import { ApiResp, SystemEnv } from '@/types'; import { OauthProvider } from '@/types/user'; import { Button, Flex, Icon } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; diff --git a/service/license/src/components/signin/auth/useCustomError.tsx b/service/license/src/components/signin/auth/useCustomError.tsx index 54234ac6da5..d525de0eb81 100644 --- a/service/license/src/components/signin/auth/useCustomError.tsx +++ b/service/license/src/components/signin/auth/useCustomError.tsx @@ -26,7 +26,7 @@ const useCustomError = () => { }, 5000); // 默认 5000 毫秒(5秒)后自动关闭错误消息 return () => clearTimeout(timeout); } - }, [error]); + }, []); return error ? ( >('/api/auth/password', { - user: data.username, - password: data.password - }); - setSession(result.data!); - router.replace('/'); - return; - } - if (result?.code === 201) { - setUserExist(!!result?.data?.exist); - setPageState(1); - if (!!data?.confimPassword) { - if (data?.password !== data?.confimPassword) { - showError('password not match'); - } else { - const result = await request.post>('/api/auth/password', { - user: data.username, - password: data.password - }); - setSession(result.data!); - router.replace('/'); - } - } - } + const result = await signInByPassword(data.username, data.password); + setSession(result); + router.replace('/'); } catch (error: any) { console.log(error); showError(t('Invalid username or password')); @@ -173,9 +147,8 @@ export default function usePassword({ return ( <> - Vector setPageState(0)} /> {t('Verify password')} diff --git a/service/license/src/components/signin/auth/useSms.tsx b/service/license/src/components/signin/auth/useSms.tsx index ea02daa16b8..23cb7ba8825 100644 --- a/service/license/src/components/signin/auth/useSms.tsx +++ b/service/license/src/components/signin/auth/useSms.tsx @@ -1,16 +1,7 @@ import { sendCodeByPhone, signInByPhone } from '@/api/user'; -import { SafetyIcon } from '@/components/icons'; +import { CodeDoneIcon, SafetyIcon } from '@/components/icons'; import useSessionStore from '@/stores/session'; -import { ApiResp, Session } from '@/types'; -import { - Image, - Input, - InputGroup, - InputLeftAddon, - InputRightAddon, - Link, - Text -} from '@chakra-ui/react'; +import { Input, InputGroup, InputLeftAddon, InputRightAddon, Link, Text } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import NextLink from 'next/link'; import { useRouter } from 'next/router'; @@ -47,9 +38,10 @@ export default function useSms({ try { setIsLoading(true); const result = await signInByPhone(data.phoneNumber, data.verifyCode); - setSession(result.data!); + setSession(result); router.replace('/'); } catch (error) { + console.log(error); showError(t('Invalid verification code') || 'Invalid verification code'); } finally { setIsLoading(false); @@ -83,10 +75,7 @@ export default function useSms({ _remainTime.current = 60; try { - const res = await sendCodeByPhone(getValues('phoneNumber')); - if (res.code !== 200 || res.message !== 'successfully') { - throw new Error('Get code failed'); - } + await sendCodeByPhone(getValues('phoneNumber')); } catch (err) { showError(t('Get code failed') || 'Get code failed'); setRemainTime(0); @@ -184,9 +173,7 @@ export default function useSms({ })} /> - {getValues('verifyCode')?.length === 6 && ( - material-symbols_update - )} + {getValues('verifyCode')?.length === 6 && } diff --git a/service/license/src/components/signin/index.tsx b/service/license/src/components/signin/index.tsx index ade5b1a3e2b..b768618a6d2 100644 --- a/service/license/src/components/signin/index.tsx +++ b/service/license/src/components/signin/index.tsx @@ -6,7 +6,7 @@ import usePassword from '@/components/signin/auth/usePassword'; import useProtocol from '@/components/signin/auth/useProtocol'; import useSms from '@/components/signin/auth/useSms'; import useSessionStore from '@/stores/session'; -import { ApiResp, LoginType, SystemEnv } from '@/types'; +import { LoginType } from '@/types'; import { Box, Button, @@ -28,7 +28,6 @@ import { useEffect, useMemo, useState } from 'react'; export default function SigninComponent() { const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); - console.log(platformEnv); const { service_protocol = '', @@ -56,11 +55,13 @@ export default function SigninComponent() { const isLoading = useMemo(() => passwordLoading || smsLoading, [passwordLoading, smsLoading]); const isSignIn = useSessionStore((s) => s.isUserLogin); const router = useRouter(); - // useEffect(() => { - // if (isSignIn()) { - // router.replace('/'); - // } - // }, []); + + useEffect(() => { + if (isSignIn()) { + router.push('/license'); + } + }, [isSignIn, router]); + const { AuthList } = useAuthList(); const loginConfig = useMemo(() => { diff --git a/service/license/src/pages/404.tsx b/service/license/src/pages/404.tsx index 07e8393085a..aa2904849d7 100644 --- a/service/license/src/pages/404.tsx +++ b/service/license/src/pages/404.tsx @@ -3,9 +3,9 @@ import { useRouter } from 'next/router'; const NonePage = () => { const router = useRouter(); - // useEffect(() => { - // router.push('/'); - // }, [router]); + useEffect(() => { + router.push('/signin'); + }, [router]); return
; }; diff --git a/service/license/src/pages/_app.tsx b/service/license/src/pages/_app.tsx index 26dfe665967..af80e6c4141 100644 --- a/service/license/src/pages/_app.tsx +++ b/service/license/src/pages/_app.tsx @@ -6,6 +6,7 @@ import type { AppProps } from 'next/app'; import Router from 'next/router'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; +import { theme } from '@/styles/chakraTheme'; const queryClient = new QueryClient({ defaultOptions: { @@ -23,7 +24,7 @@ Router.events.on('routeChangeError', () => NProgress.done()); const App = ({ Component, pageProps }: AppProps) => { return ( - + diff --git a/service/license/src/pages/api/auth/oauth/wechat/index.ts b/service/license/src/pages/api/auth/oauth/wechat/index.ts index 338b7621582..90fc819e154 100644 --- a/service/license/src/pages/api/auth/oauth/wechat/index.ts +++ b/service/license/src/pages/api/auth/oauth/wechat/index.ts @@ -8,6 +8,7 @@ import { Session } from '@/types/session'; import { getBase64FromRemote } from '@/utils/tools'; import { getOauthRes } from '@/services/backend/oauth'; import { enableWechat } from '@/services/enable'; + export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { if (!enableWechat()) { diff --git a/service/license/src/pages/api/auth/password/index.ts b/service/license/src/pages/api/auth/password/index.ts index c6447a85d3f..e6f001b1c88 100644 --- a/service/license/src/pages/api/auth/password/index.ts +++ b/service/license/src/pages/api/auth/password/index.ts @@ -1,10 +1,10 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/services/backend/response'; - import { Session } from '@/types/session'; import { getOauthRes } from '@/services/backend/oauth'; import { strongPassword } from '@/utils/crypto'; import { enablePassword } from '@/services/enable'; + export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { if (!enablePassword()) { diff --git a/service/license/src/pages/api/auth/phone/verify.ts b/service/license/src/pages/api/auth/phone/verify.ts index 74d6860ecb5..1a3358bec18 100644 --- a/service/license/src/pages/api/auth/phone/verify.ts +++ b/service/license/src/pages/api/auth/phone/verify.ts @@ -23,6 +23,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) name: phoneNumbers, avatar_url: '' }); + return jsonRes(res, { data, code: 200, diff --git a/service/license/src/pages/api/license/createLicenseRecord.ts b/service/license/src/pages/api/license/createLicenseRecord.ts index 86aa73f8a32..58a7f0412e6 100644 --- a/service/license/src/pages/api/license/createLicenseRecord.ts +++ b/service/license/src/pages/api/license/createLicenseRecord.ts @@ -12,7 +12,7 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse const { token, orderID, amount, quota, paymentMethod } = req.body as LicensePayload; const record = { - uid: payload.user.nsid, + uid: payload.uid, amount: amount, token: token, orderID: orderID, diff --git a/service/license/src/pages/api/license/getLicense.ts b/service/license/src/pages/api/license/getLicense.ts new file mode 100644 index 00000000000..58a7f0412e6 --- /dev/null +++ b/service/license/src/pages/api/license/getLicense.ts @@ -0,0 +1,31 @@ +import { authSession } from '@/services/backend/auth'; +import { createLicenseRecord } from '@/services/backend/db/license'; +import { jsonRes } from '@/services/backend/response'; +import { LicensePayload } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const payload = await authSession(req.headers); + if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + + const { token, orderID, amount, quota, paymentMethod } = req.body as LicensePayload; + + const record = { + uid: payload.uid, + amount: amount, + token: token, + orderID: orderID, + quota: quota, + paymentMethod: paymentMethod + }; + + const result = await createLicenseRecord(record); + + return jsonRes(resp, { + data: result + }); + } catch (error) { + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/getLicenseRecord.ts b/service/license/src/pages/api/license/getLicenseRecord.ts index cf18b889010..510ddc12f5a 100644 --- a/service/license/src/pages/api/license/getLicenseRecord.ts +++ b/service/license/src/pages/api/license/getLicenseRecord.ts @@ -1,7 +1,6 @@ import { authSession } from '@/services/backend/auth'; -import { createLicenseRecord, getLicenseRecordsByUid } from '@/services/backend/db/license'; +import { getLicenseRecordsByUid } from '@/services/backend/db/license'; import { jsonRes } from '@/services/backend/response'; -import { LicensePayload } from '@/types'; import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, resp: NextApiResponse) { @@ -15,7 +14,7 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse }; const result = await getLicenseRecordsByUid({ - uid: payload.user.nsid, + uid: payload.uid, page: page, pageSize: pageSize }); diff --git a/service/license/src/pages/api/license/pay.ts b/service/license/src/pages/api/license/pay.ts index ad6a127550c..1366ccb4a13 100644 --- a/service/license/src/pages/api/license/pay.ts +++ b/service/license/src/pages/api/license/pay.ts @@ -1,84 +1,82 @@ -import { authSession } from '@/services/backend/auth'; -import { ApplyYaml } from '@/services/backend/kubernetes/user'; -import { jsonRes } from '@/services/backend/response'; -import { LicensePaymentForm } from '@/types'; -import yaml from 'js-yaml'; -import type { NextApiRequest, NextApiResponse } from 'next'; +// import { authSession } from '@/services/backend/auth'; +// import { jsonRes } from '@/services/backend/response'; +// import { LicensePaymentForm } from '@/types'; +// import type { NextApiRequest, NextApiResponse } from 'next'; -export const generateLicenseCrd = (form: LicensePaymentForm) => { - const paymentCrd = { - apiVersion: 'infostream.sealos.io/v1', - kind: 'Payment', - metadata: { - name: form.paymentName, - namespace: form.namespace - }, - spec: { - userID: form.userId, - amount: form.amount, // weixin - paymentMethod: form.paymentMethod, - service: { - amt: form.quota, // Actual value - hid: form.hashID, - typ: 'account' - } - } - }; - try { - const result = yaml.dump(paymentCrd); - return result; - } catch (error) { - throw error; - } -}; +// export const generateLicenseCrd = (form: LicensePaymentForm) => { +// const paymentCrd = { +// apiVersion: 'infostream.sealos.io/v1', +// kind: 'Payment', +// metadata: { +// name: form.paymentName, +// namespace: form.namespace +// }, +// spec: { +// userID: form.userId, +// amount: form.amount, // weixin +// paymentMethod: form.paymentMethod, +// service: { +// amt: form.quota, // Actual value +// hid: form.hashID, +// typ: 'account' +// } +// } +// }; +// try { +// const result = yaml.dump(paymentCrd); +// return result; +// } catch (error) { +// throw error; +// } +// }; -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - const payload = await authSession(req.headers); - if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); +// export default async function handler(req: NextApiRequest, resp: NextApiResponse) { +// try { +// const payload = await authSession(req.headers); +// if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); - const { amount, paymentMethod, hid, quota } = req.body as { - amount: number; - paymentMethod: 'wechat' | 'stripe'; - hid: string; - quota: number; - }; - console.log(amount, quota, paymentMethod, hid); - if (!hid) { - return jsonRes(resp, { - code: 400, - message: 'Missing hid parameter' - }); - } - if (amount <= 0) { - return jsonRes(resp, { - code: 400, - message: 'Amount cannot be less than 0' - }); - } +// const { amount, paymentMethod, hid, quota } = req.body as { +// amount: number; +// paymentMethod: 'wechat' | 'stripe'; +// hid: string; +// quota: number; +// }; +// console.log(amount, quota, paymentMethod, hid); +// if (!hid) { +// return jsonRes(resp, { +// code: 400, +// message: 'Missing hid parameter' +// }); +// } +// if (amount <= 0) { +// return jsonRes(resp, { +// code: 400, +// message: 'Amount cannot be less than 0' +// }); +// } - const paymentName = crypto.randomUUID(); - const form: LicensePaymentForm = { - namespace: payload.user.nsid, - paymentName: paymentName, - userId: payload.user.k8s_username, - amount: amount, - quota: quota, - paymentMethod: paymentMethod, - hashID: hid - }; +// const paymentName = crypto.randomUUID(); +// const form: LicensePaymentForm = { +// namespace: payload.user.nsid, +// paymentName: paymentName, +// userId: payload.user.k8s_username, +// amount: amount, +// quota: quota, +// paymentMethod: paymentMethod, +// hashID: hid +// }; - const LicenseCrd = generateLicenseCrd(form); +// const LicenseCrd = generateLicenseCrd(form); - const res = await ApplyYaml(payload.kc, LicenseCrd); - return jsonRes(resp, { - data: { - paymentName: paymentName, - extra: res[0] - } - }); - } catch (error) { - console.log(error); - jsonRes(resp, { code: 500, data: error }); - } -} +// const res = await ApplyYaml(payload.kc, LicenseCrd); +// return jsonRes(resp, { +// data: { +// paymentName: paymentName, +// extra: res[0] +// } +// }); +// } catch (error) { +// console.log(error); +// jsonRes(resp, { code: 500, data: error }); +// } +// } diff --git a/service/license/src/pages/api/price/bonus.ts b/service/license/src/pages/api/price/bonus.ts new file mode 100644 index 00000000000..6f1467e2791 --- /dev/null +++ b/service/license/src/pages/api/price/bonus.ts @@ -0,0 +1,25 @@ +import { authSession } from '@/services/backend/auth'; + +import { jsonRes } from '@/services/backend/response'; +import { enableRecharge } from '@/services/enable'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const payload = await authSession(req.headers); + if (!payload) { + return jsonRes(resp, { code: 401, message: 'token verify error' }); + } + + return jsonRes(resp, { + code: 200, + data: { + ratios: '10,15,20,25,30', + steps: '299,599,1999,4999,19999' + } + }); + } catch (error) { + console.log(error); + jsonRes(resp, { code: 500, message: 'get price bonus error' }); + } +} diff --git a/service/license/src/pages/callback.tsx b/service/license/src/pages/callback.tsx new file mode 100644 index 00000000000..75401bd1a98 --- /dev/null +++ b/service/license/src/pages/callback.tsx @@ -0,0 +1,42 @@ +import { signInByProvider } from '@/api/user'; +import useSessionStore from '@/stores/session'; +import { Flex, Spinner } from '@chakra-ui/react'; +import type { NextPage } from 'next'; +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; + +const Callback: NextPage = () => { + const router = useRouter(); + const { provider, setSession, compareState } = useSessionStore(); + + useEffect(() => { + if (!router.isReady) return; + + (async () => { + try { + if (!provider || !['github', 'wechat', 'google'].includes(provider)) { + throw new Error('provider error'); + } + + const { code, state } = router.query; + + if (!code || !state || !compareState(state as string)) { + throw new Error('failed to get code and state'); + } + + const data = await signInByProvider(provider, code); + setSession(data); + router.replace('/'); + } catch (error) { + router.replace('/signin'); + } + })(); + }, [compareState, provider, router, setSession]); + + return ( + + + + ); +}; +export default Callback; diff --git a/service/license/src/pages/index.tsx b/service/license/src/pages/index.tsx index f51b9e8ab2a..a8f2290b31d 100644 --- a/service/license/src/pages/index.tsx +++ b/service/license/src/pages/index.tsx @@ -1,23 +1,14 @@ -import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import React, { useEffect } from 'react'; import { useRouter } from 'next/router'; -import { useEffect } from 'react'; -export default function IndexPage() { +const NonePage = () => { const router = useRouter(); + useEffect(() => { - router.push('/signin'); - }, []); + router.push('/license'); + }, [router]); return
; -} - -export async function getServerSideProps({ req, res, locales }: any) { - const lang: string = req?.headers?.['accept-language'] || 'zh'; - const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; +}; - return { - props: { - ...(await serverSideTranslations(local, undefined, null, locales || [])) - } - }; -} +export default NonePage; diff --git a/service/license/src/pages/license/components/Pagination.tsx b/service/license/src/pages/license/components/Pagination.tsx index f5c3e54c430..a2aaaa36c22 100644 --- a/service/license/src/pages/license/components/Pagination.tsx +++ b/service/license/src/pages/license/components/Pagination.tsx @@ -33,6 +33,10 @@ export default function Pagination({ totalItems, itemsPerPage, onPageChange }: P borderRadius: '50%' }; + if (totalPage === 0) { + return <>; + } + return ( Total: diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx index 0ae86428de7..ea3da06f332 100644 --- a/service/license/src/pages/license/index.tsx +++ b/service/license/src/pages/license/index.tsx @@ -7,6 +7,7 @@ import LicenseRecord from './components/Record'; import { useRouter } from 'next/router'; import { useQuery } from '@tanstack/react-query'; import { ApiResp, SystemEnv } from '@/types'; +import Account from '@/components/account'; export default function LicensePage() { const { t } = useTranslation(); @@ -41,6 +42,7 @@ export default function LicensePage() { | {t('License Buy')} + diff --git a/service/license/src/services/backend/auth.ts b/service/license/src/services/backend/auth.ts index e5248badd08..aa08f271efc 100644 --- a/service/license/src/services/backend/auth.ts +++ b/service/license/src/services/backend/auth.ts @@ -6,26 +6,15 @@ const jwtSecret = (process.env.JWT_SECRET as string) || '123456789'; export const authSession = async (header: IncomingHttpHeaders) => { try { - // if (!header?.authorization) { - // throw new Error('缺少凭证'); - // } - // const token = decodeURIComponent(header.authorization); - // const payload = await verifyJWT(token); - // if ( - // !payload || - // !payload.kubeconfig || - // !payload?.user?.uid || - // !payload?.user?.nsid || - // !payload?.user?.ns_uid || - // !payload?.user?.k8s_username - // ) - // throw new Error('token is null'); - // console.log('jwt:', payload.kubeconfig) - // const kc = K8sApi(payload.kubeconfig); - // const username = kc.getCurrentUser()?.name; - // const user = payload.user; - // if (!username || user.k8s_username !== username) throw new Error('user is invaild'); - // return Promise.resolve({ kc, user }); + if (!header?.authorization) { + throw new Error('缺少凭证'); + } + const token = decodeURIComponent(header.authorization); + const payload = await verifyJWT(token); + if (!payload) { + throw new Error('token is null'); + } + return Promise.resolve(payload); } catch (err) { console.error(err, '==='); return Promise.resolve(null); @@ -46,6 +35,7 @@ export const verifyJWT: (token: string) => Promise = (token: } }); }); + export const generateJWT = (props: JWTPayload) => { console.log('jwt: ', props); return sign(props, jwtSecret, { diff --git a/service/license/src/services/backend/db/user.ts b/service/license/src/services/backend/db/user.ts index e8693c03864..caa9fb66a0f 100644 --- a/service/license/src/services/backend/db/user.ts +++ b/service/license/src/services/backend/db/user.ts @@ -1,127 +1,73 @@ import { connectToDatabase } from './mongodb'; -import { K8s_user, PROVIDERS, Provider, User } from '@/types/user'; -import { customAlphabet } from 'nanoid'; +import { AUTH_PROVIDERS, AuthProvider, User } from '@/types/user'; +import { hashPassword } from '@/utils/crypto'; import { v4 as uuid } from 'uuid'; -const LetterBytes = 'abcdefghijklmnopqrstuvwxyz0123456789'; -const HostnameLength = 8; - -const nanoid = customAlphabet(LetterBytes, HostnameLength); async function connectToUserCollection() { const client = await connectToDatabase(); const collection = client.db().collection('user'); await collection.createIndex({ uid: 1 }, { unique: true }); - await collection.createIndex({ 'k8s_users.name': 1 }, { unique: true, sparse: true }); - await collection.createIndex({ password_user: 1 }, { unique: true, sparse: true }); return collection; } -export async function queryUser({ id, provider }: { id: string; provider: Provider }) { +export async function queryUser({ id, provider }: { id: string; provider: AuthProvider }) { const users = await connectToUserCollection(); if (!verifyProvider(provider)) return Promise.reject('provider error'); return await users.findOne({ [provider]: id }); } -export async function queryUserByk8sUser(k8s_useranme: string) { - const users = await connectToUserCollection(); - return await users.findOne({ 'k8s_users.name': k8s_useranme }); -} + export async function createUser({ id, provider, name, - avatar_url + avatar_url, + password }: { id: string; - provider: Provider; + provider: AuthProvider; name: string; avatar_url: string; + password?: string; }) { + if (!verifyProvider(provider)) return Promise.reject('provider error'); const users = await connectToUserCollection(); + const uid = uuid(); - let uid = uuid(); - const k8s_username = await get_k8s_username(); - let user: User = { + const user: User = { uid, avatar_url, name, created_time: new Date().toISOString(), - k8s_users: [ - { - name: k8s_username - } - ] + [provider]: id }; - if (!verifyProvider(provider)) return Promise.reject('provider error'); - user[provider] = id; + + if (password) { + user.password = hashPassword(password); + } + await users.insertOne(user); return user; } + export async function updateUser({ id, provider, data }: { id: string; - provider: Provider; - data: Partial>; + provider: AuthProvider; + data: Partial; }) { const users = await connectToUserCollection(); if (!verifyProvider(provider)) return Promise.reject('provider error'); return await users.updateOne({ [provider]: id }, { $set: data }); } -export async function addK8sUser({ - id, - provider, - k8s_user -}: { - id: string; - provider: Provider; - k8s_user: K8s_user; -}) { - const users = await connectToUserCollection(); - if (!verifyProvider(provider)) return Promise.reject('provider error'); - const result = await users.findOneAndUpdate( - { [provider]: id }, - { $addToSet: { k8s_users: k8s_user } } - ); - if (!result.ok) { - return null; - } - return result.value; -} -export async function removeK8sUser({ - id, - provider, - k8s_username -}: { - id: string; - provider: Provider; - k8s_username: string; -}) { - const users = await connectToUserCollection(); - if (!verifyProvider(provider)) return Promise.reject('provider error'); - return await users.updateOne( - { [provider]: id }, - { $pull: { k8s_users: { name: k8s_username } } } - ); -} -function verifyProvider(provider: string): provider is Provider { - return PROVIDERS.includes(provider as Provider); -} -export async function get_k8s_username() { - const users = await connectToUserCollection(); - let k8s_username = nanoid(); - let len = 5; - while ((await users.findOne({ k8s_users: { name: k8s_username } })) && len--) { - k8s_username = nanoid(); - } - if (len < 0) { - return Promise.reject('user are too many to be created'); - } - return k8s_username; +function verifyProvider(provider: string): provider is AuthProvider { + return AUTH_PROVIDERS.includes(provider as AuthProvider); } -export async function removeUser({ id, provider }: { id: string; provider: Provider }) { + +export async function removeUser({ id, provider }: { id: string; provider: AuthProvider }) { const users = await connectToUserCollection(); if (!verifyProvider(provider)) return Promise.reject('provider error'); return await users.deleteOne({ [provider]: id }); diff --git a/service/license/src/services/backend/oauth.ts b/service/license/src/services/backend/oauth.ts index 926d343f2d8..fc82157324e 100644 --- a/service/license/src/services/backend/oauth.ts +++ b/service/license/src/services/backend/oauth.ts @@ -1,15 +1,9 @@ import { Session } from '@/types'; -import { generateJWT } from './auth'; -import { addK8sUser, createUser, queryUser, removeUser, updateUser } from './db/user'; -import { Provider, User } from '@/types/user'; -import { getUserKubeconfig, getUserKubeconfigByuid } from './kubernetes/admin'; -import { hashPassword, verifyPassword } from '@/utils/crypto'; -import { createNS, queryNS } from './db/namespace'; -import { GetUserDefaultNameSpace } from './kubernetes/user'; +import { AuthProvider, User } from '@/types/user'; +import { verifyPassword } from '@/utils/crypto'; import { WithId } from 'mongodb'; -import { v4 as uuid } from 'uuid'; -import { createUTN, queryUTN } from './db/userToNamespace'; -import { InvitedStatus, NSType, UserRole } from '@/types/team'; +import { generateJWT } from './auth'; +import { createUser, queryUser } from './db/user'; export const getOauthRes = async ({ provider, @@ -18,7 +12,7 @@ export const getOauthRes = async ({ avatar_url, password }: { - provider: Provider; + provider: AuthProvider; id: string; name: string; avatar_url: string; @@ -27,7 +21,7 @@ export const getOauthRes = async ({ if (provider === 'password_user' && !password) { throw new Error('password is required'); } - // 翻查一下 ns 和user + const _user = await queryUser({ id, provider }); let signResult = null; if (!_user) { @@ -47,38 +41,29 @@ export const getOauthRes = async ({ }); } if (!signResult) throw new Error('Failed to edit db'); - const { k8s_user, namespace, user } = signResult; - const k8s_username = k8s_user.name; - // 登录和注册都需要对k8suser.namespace列做校检 - if (namespace.nstype !== NSType.Private) return Promise.reject('Faild to get private namespace'); - const kubeconfig = await getUserKubeconfig(user.uid, k8s_username); - if (!kubeconfig) { - throw new Error('Failed to get user config'); - } + const { user } = signResult; + const token = generateJWT({ - user: { k8s_username, uid: user.uid, nsid: namespace.id, ns_uid: namespace.uid }, - kubeconfig + uid: user.uid, + [provider]: id }); + return { token, user: { name: user.name, - k8s_username, - avatar: user.avatar_url, - nsid: namespace.id, - ns_uid: namespace.uid, - userId: user.uid - }, - kubeconfig + avatar: user.avatar_url + } }; }; + async function signIn({ userResult: _user, provider, id, password }: { - provider: Provider; + provider: AuthProvider; id: string; password?: string; userResult: WithId; @@ -88,58 +73,9 @@ async function signIn({ throw new Error('password error'); } } - const k8s_users = _user.k8s_users || []; - const uid = _user.uid; - let k8s_user = null; - // 迁移用户 - if (k8s_users.length === 0) { - const k8s_username = await getUserKubeconfigByuid(uid); - if (!!k8s_username) { - const result = await addK8sUser({ - id: '' + id, - provider, - k8s_user: { - name: k8s_username - } - }); - if (!result) return Promise.reject('Faild to add k8s user'); - k8s_users.push(result); - } - } - k8s_user = k8s_users[0]; - const k8s_username = k8s_user.name; - // 迁移namespace - let namespace = await queryNS({ id: GetUserDefaultNameSpace(k8s_username) }); - if (!namespace) { - namespace = await createNS({ - namespace: GetUserDefaultNameSpace(k8s_username), - nstype: NSType.Private, - teamName: 'private team' - }); - if (!namespace) return Promise.reject('Faild to create namespace'); - } - // 迁移utn - let utn = await queryUTN({ userId: uid, k8s_username, namespaceId: namespace.uid }); - if (!utn) - utn = await createUTN({ - userId: _user.uid, - k8s_username, - namespaceId: namespace.uid, - status: InvitedStatus.Accepted, - role: UserRole.Owner - }); - if (!utn) return Promise.reject('Faild to add namesapce'); - const user: User = { - ..._user, - k8s_users - }; - return { - user, - k8s_user, - namespace - }; + return { user: _user }; } -// 注册 + async function signUp({ provider, id, @@ -147,47 +83,12 @@ async function signUp({ avatar_url, password }: { - provider: Provider; + provider: AuthProvider; id: string; name: string; avatar_url: string; password?: string; }) { - const ns_uid = uuid(); - const user = await createUser({ id, provider, name, avatar_url }); - if (provider === 'password_user') { - await updateUser({ - id, - provider: 'password_user', - data: { password: hashPassword(password!) } - }).catch(async (_) => { - await removeUser({ id: '' + id, provider: 'password_user' }); - throw new Error('Failed to create user by password'); - }); - } - const k8s_users = user.k8s_users || []; - const userId = user.uid; - if (!k8s_users) return null; - const k8s_user = k8s_users[0]; - const k8s_username = k8s_user.name; - const namespace = await createNS({ - namespace: GetUserDefaultNameSpace(k8s_username), - nstype: NSType.Private, - teamName: 'private team', - uid: ns_uid - }); - if (!namespace) return null; - const utn = await createUTN({ - namespaceId: namespace.uid, - k8s_username: k8s_user.name, - userId, - status: InvitedStatus.Accepted, - role: UserRole.Owner - }); - if (!utn) return null; - return { - user, - k8s_user, - namespace - }; + const user = await createUser({ id, provider, name, avatar_url, password }); + return { user }; } diff --git a/service/license/src/services/backend/response.ts b/service/license/src/services/backend/response.ts index 582b804b3ad..4ea07c48270 100644 --- a/service/license/src/services/backend/response.ts +++ b/service/license/src/services/backend/response.ts @@ -18,7 +18,7 @@ export const jsonRes = ( if (typeof error === 'string') { msg = error; } - console.error('===jsonRes error===\n ', error); + console.error('===jsonRes error===\n', error); } res.json({ diff --git a/service/license/src/services/request.ts b/service/license/src/services/request.ts index 04de9f37452..3023937b866 100644 --- a/service/license/src/services/request.ts +++ b/service/license/src/services/request.ts @@ -61,7 +61,10 @@ request.interceptors.request.use( let _headers: AxiosHeaders = config.headers || {}; const session = useSessionStore.getState().session; - _headers['Authorization'] = encodeURIComponent(session.token); + + if (session?.token && config.url && config.url?.startsWith('/api/')) { + _headers['Authorization'] = encodeURIComponent(session.token); + } if (!config.headers || config.headers['Content-Type'] === '') { _headers['Content-Type'] = 'application/json'; @@ -81,6 +84,13 @@ request.interceptors.request.use( request.interceptors.response.use( (response: AxiosResponse) => { const { status, data } = response; + + if (data.code === 401) { + console.log('鉴权失败'); + useSessionStore.getState().delSession(); + return window.location.replace('/signin'); + } + if (status < 200 || status >= 300) { return Promise.reject( status + ':' + showStatus(status) + ', ' + typeof data === 'string' ? data : String(data) diff --git a/service/license/src/styles/theme.ts b/service/license/src/styles/chakraTheme.ts similarity index 100% rename from service/license/src/styles/theme.ts rename to service/license/src/styles/chakraTheme.ts diff --git a/service/license/src/types/index.ts b/service/license/src/types/index.ts index ba2a9d1aac0..0904b1e287b 100644 --- a/service/license/src/types/index.ts +++ b/service/license/src/types/index.ts @@ -4,7 +4,6 @@ export * from './session'; export * from './payment'; export * from './system'; export * from './login'; -export * from './valuation'; export * from './license'; declare global { diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index a62800b453e..9746447735f 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -1,5 +1,5 @@ -import * as yaml from 'js-yaml'; -import { CRDMeta } from './crd'; +// import * as yaml from 'js-yaml'; +// import { CRDMeta } from './crd'; export type PaymentForm = { paymentName: string; @@ -8,12 +8,12 @@ export type PaymentForm = { amount: string; }; -export const paymentMeta: CRDMeta = { - group: 'account.sealos.io', - version: 'v1', - namespace: 'sealos-system', - plural: 'payments' -}; +// export const paymentMeta: CRDMeta = { +// group: 'account.sealos.io', +// version: 'v1', +// namespace: 'sealos-system', +// plural: 'payments' +// }; export type Payment = { paymentName: string; @@ -34,25 +34,25 @@ export type Pay = { tradeNO: string; }; -export const generatePaymentCrd = (form: PaymentForm) => { - const paymentCrd = { - apiVersion: 'account.sealos.io/v1', - kind: 'Payment', - metadata: { - name: form.paymentName, - namespace: form.namespace - }, - spec: { - userID: form.userId, - amount: form.amount, - paymentMethod: 'wechat' - } - }; +// export const generatePaymentCrd = (form: PaymentForm) => { +// const paymentCrd = { +// apiVersion: 'account.sealos.io/v1', +// kind: 'Payment', +// metadata: { +// name: form.paymentName, +// namespace: form.namespace +// }, +// spec: { +// userID: form.userId, +// amount: form.amount, +// paymentMethod: 'wechat' +// } +// }; - try { - const result = yaml.dump(paymentCrd); - return result; - } catch (error) { - return ''; - } -}; +// try { +// const result = yaml.dump(paymentCrd); +// return result; +// } catch (error) { +// return ''; +// } +// }; diff --git a/service/license/src/types/session.ts b/service/license/src/types/session.ts index e8c3cd86477..2c0169d00c0 100644 --- a/service/license/src/types/session.ts +++ b/service/license/src/types/session.ts @@ -1,3 +1,5 @@ +import { UserSignInType } from './user'; + export type OAuthToken = { readonly access_token: string; readonly token_type: string; @@ -6,27 +8,17 @@ export type OAuthToken = { }; export type UserInfo = { - readonly k8s_username: string; readonly name: string; readonly avatar: string; - readonly nsid: string; - readonly ns_uid: string; - readonly userId: string; -}; - -export type KubeConfig = string; +} & UserSignInType; export type Session = { - token: string; // jwt token - // 提供一些简单的信息 + token: string; user: UserInfo; - // 帮忙导出用的 - kubeconfig: KubeConfig; }; export type JWTPayload = { - kubeconfig: KubeConfig; - user: Record<'uid' | 'nsid' | 'k8s_username' | 'ns_uid', string>; -}; + uid: string; +} & UserSignInType; export const sessionKey = 'session'; diff --git a/service/license/src/types/user.ts b/service/license/src/types/user.ts index 2a7880422e5..1ee27a59dc8 100644 --- a/service/license/src/types/user.ts +++ b/service/license/src/types/user.ts @@ -16,6 +16,7 @@ export type TWechatToken = { is_snapshotuser: 1; unionid: string; }; + export type TWechatUser = { openid: string; nickname: string; @@ -27,6 +28,7 @@ export type TWechatUser = { privilege: string[]; unionid: string; }; + export type TgithubUser = { login: string; id: number; @@ -61,33 +63,21 @@ export type TgithubUser = { created_at: string; updated_at: string; }; -// if default, uid -export const PROVIDERS = ['github', 'wechat', 'phone', 'uid', 'password_user', 'google'] as const; -export type Provider = (typeof PROVIDERS)[number]; -export type OauthProvider = Exclude; + +export const AUTH_PROVIDERS = ['github', 'wechat', 'phone', 'password_user', 'google'] as const; + +export type AuthProvider = (typeof AUTH_PROVIDERS)[number]; + +export type OauthProvider = Exclude; + export type TUserExist = { user: string; exist: boolean }; -export type K8s_user = { - name: string; -}; export type User = { uid: string; avatar_url: string; name: string; - github?: string; - wechat?: string; - google?: string; - phone?: string; - k8s_users?: K8s_user[]; created_time: string; password?: string; - password_user?: string; -}; +} & UserSignInType; -export type UserDto = { - uid: string; - avatarUrl: string; - name: string; - k8s_username: string; - createdTime: string; -}; +export type UserSignInType = { [key in AuthProvider]?: string }; diff --git a/service/license/src/types/valuation.ts b/service/license/src/types/valuation.ts deleted file mode 100644 index da4244ceb53..00000000000 --- a/service/license/src/types/valuation.ts +++ /dev/null @@ -1,18 +0,0 @@ -export type ValuationStandard = { - name: string; - unit: string; - price: string; -}; -export type ValuationBillingRecord = { - price: number; - resourceType: string; -}; -export type ValuationData = { - apiVersion: 'account.sealos.io/v1'; - kind: 'PriceQuery'; - metadata: any; - spec: {}; - status: { - billingRecords: ValuationBillingRecord[]; - }; -}; diff --git a/service/license/src/utils/cookieUtils.ts b/service/license/src/utils/cookieUtils.ts index 89c9c5aac5b..a134ea5862d 100644 --- a/service/license/src/utils/cookieUtils.ts +++ b/service/license/src/utils/cookieUtils.ts @@ -1,6 +1,6 @@ -import Cookies, { CookieAttributes } from 'js-cookie'; +import Cookies from 'js-cookie'; -export const setCookie = (key: string, value: string, options?: CookieAttributes) => { +export const setCookie = (key: string, value: string, options?: any) => { Cookies.set(key, value, options); }; From 959fbe75e1da3bd6db2cc84ef459c748f616037c Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Wed, 18 Oct 2023 11:59:37 +0800 Subject: [PATCH 03/17] tempalte Signed-off-by: jingyang <3161362058@qq.com> --- service/license/package.json | 2 +- service/license/pnpm-lock.yaml | 98 ++++++++-------- .../license/src/components/account/index.tsx | 10 +- .../components/icons/DownloadIcon copy 4.tsx | 14 --- .../src/components/icons/StripeIcon.tsx | 14 +++ service/license/src/components/icons/index.ts | 1 + service/license/src/hooks/useBonusBox.tsx | 35 +++++- .../src/pages/api/license/getLicense.ts | 31 ----- service/license/src/pages/api/license/pay.ts | 111 +++++------------- .../license/src/pages/api/license/result.ts | 55 ++++----- .../license/src/pages/api/platform/getEnv.ts | 12 +- service/license/src/pages/api/price/bonus.ts | 2 - .../src/pages/license/components/Recharge.tsx | 37 +++--- .../src/services/backend/db/license.ts | 24 +++- service/license/src/services/enable.ts | 9 +- service/license/src/services/pay.ts | 13 ++ service/license/src/services/request.ts | 2 +- service/license/src/types/license.ts | 84 +++++++------ service/license/src/types/payment.ts | 74 ++++-------- service/license/src/types/system.ts | 1 - 20 files changed, 293 insertions(+), 336 deletions(-) delete mode 100644 service/license/src/components/icons/DownloadIcon copy 4.tsx create mode 100644 service/license/src/components/icons/StripeIcon.tsx delete mode 100644 service/license/src/pages/api/license/getLicense.ts create mode 100644 service/license/src/services/pay.ts diff --git a/service/license/package.json b/service/license/package.json index 3cb73cf852d..def8483e361 100644 --- a/service/license/package.json +++ b/service/license/package.json @@ -26,7 +26,7 @@ "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "mongodb": "^6.1.0", - "next": "13.5.4", + "next": "13.5.5", "next-i18next": "^14.0.3", "nprogress": "^0.2.0", "qrcode.react": "^3.1.0", diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml index c0b8a6b03b9..11b238131e7 100644 --- a/service/license/pnpm-lock.yaml +++ b/service/license/pnpm-lock.yaml @@ -57,11 +57,11 @@ dependencies: specifier: ^6.1.0 version: registry.npmmirror.com/mongodb@6.1.0 next: - specifier: 13.5.4 - version: registry.npmmirror.com/next@13.5.4(react-dom@18.0.0)(react@18.0.0) + specifier: 13.5.5 + version: registry.npmmirror.com/next@13.5.5(react-dom@18.0.0)(react@18.0.0) next-i18next: specifier: ^14.0.3 - version: registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.4)(react-i18next@13.3.0)(react@18.0.0) + version: registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.5)(react-i18next@13.3.0)(react@18.0.0) nprogress: specifier: ^0.2.0 version: registry.npmmirror.com/nprogress@0.2.0 @@ -1853,10 +1853,10 @@ packages: sparse-bitfield: registry.npmmirror.com/sparse-bitfield@3.0.3 dev: false - registry.npmmirror.com/@next/env@13.5.4: - resolution: {integrity: sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/env/-/env-13.5.4.tgz} + registry.npmmirror.com/@next/env@13.5.5: + resolution: {integrity: sha512-agvIhYWp+ilbScg81s/sLueZo8CNEYLjNOqhISxheLmD/AQI4/VxV7bV76i/KzxH4iHy/va0YS9z0AOwGnw4Fg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/env/-/env-13.5.5.tgz} name: '@next/env' - version: 13.5.4 + version: 13.5.5 dev: false registry.npmmirror.com/@next/eslint-plugin-next@13.5.4: @@ -1867,10 +1867,10 @@ packages: glob: registry.npmmirror.com/glob@7.1.7 dev: true - registry.npmmirror.com/@next/swc-darwin-arm64@13.5.4: - resolution: {integrity: sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz} + registry.npmmirror.com/@next/swc-darwin-arm64@13.5.5: + resolution: {integrity: sha512-FvTdcJdTA7H1FGY8dKPPbf/O0oDC041/znHZwXA7liiGUhgw5hOQ+9z8tWvuz0M5a/SDjY/IRPBAb5FIFogYww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.5.tgz} name: '@next/swc-darwin-arm64' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1878,10 +1878,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-darwin-x64@13.5.4: - resolution: {integrity: sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz} + registry.npmmirror.com/@next/swc-darwin-x64@13.5.5: + resolution: {integrity: sha512-mTqNIecaojmyia7appVO2QggBe1Z2fdzxgn6jb3x9qlAk8yY2sy4MAcsj71kC9RlenCqDmr9vtC/ESFf110TPA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.5.tgz} name: '@next/swc-darwin-x64' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1889,10 +1889,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.4: - resolution: {integrity: sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz} + registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.5: + resolution: {integrity: sha512-U9e+kNkfvwh/T8yo+xcslvNXgyMzPPX1IbwCwnHHFmX5ckb1Uc3XZSInNjFQEQR5xhJpB5sFdal+IiBIiLYkZA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.5.tgz} name: '@next/swc-linux-arm64-gnu' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1901,10 +1901,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.4: - resolution: {integrity: sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz} + registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.5: + resolution: {integrity: sha512-h7b58eIoNCSmKVC5fr167U0HWZ/yGLbkKD9wIller0nGdyl5zfTji0SsPKJvrG8jvKPFt2xOkVBmXlFOtuKynw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.5.tgz} name: '@next/swc-linux-arm64-musl' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1913,10 +1913,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.4: - resolution: {integrity: sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz} + registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.5: + resolution: {integrity: sha512-6U4y21T1J6FfcpM9uqzBJicxycpB5gJKLyQ3g6KOfBzT8H1sMwfHTRrvHKB09GIn1BCRy5YJHrA1G26DzqR46w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.5.tgz} name: '@next/swc-linux-x64-gnu' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1925,10 +1925,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.4: - resolution: {integrity: sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz} + registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.5: + resolution: {integrity: sha512-OuqWSAQHJQM2EsapPFTSU/FLQ0wKm7UeRNatiR/jLeCe1V02aB9xmzuWYo2Neaxxag4rss3S8fj+lvMLzwDaFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.5.tgz} name: '@next/swc-linux-x64-musl' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1937,10 +1937,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.4: - resolution: {integrity: sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz} + registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.5: + resolution: {integrity: sha512-+yLrOZIIZDY4uGn9bLOc0wTgs+M8RuOUFSUK3BhmcLav9e+tcAj0jyBHD4aXv2qWhppUeuYMsyBo1I58/eE6Dg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.5.tgz} name: '@next/swc-win32-arm64-msvc' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1948,10 +1948,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.4: - resolution: {integrity: sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz} + registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.5: + resolution: {integrity: sha512-SyMxXyJtf9ScMH0Dh87THJMXNFvfkRAk841xyW9SeOX3KxM1buXX3hN7vof4kMGk0Yg996OGsX+7C9ueS8ugsw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.5.tgz} name: '@next/swc-win32-ia32-msvc' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -1959,10 +1959,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.4: - resolution: {integrity: sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz} + registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.5: + resolution: {integrity: sha512-n5KVf2Ok0BbLwofAaHiiKf+BQCj1M8WmTujiER4/qzYAVngnsNSjqEWvJ03raeN9eURqxDO+yL5VRoDrR33H9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.5.tgz} name: '@next/swc-win32-x64-msvc' - version: 13.5.4 + version: 13.5.5 engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -4379,7 +4379,7 @@ packages: version: 1.4.0 dev: true - registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.4)(react-i18next@13.3.0)(react@18.0.0): + registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.5)(react-i18next@13.3.0)(react@18.0.0): resolution: {integrity: sha512-FtnjRMfhlamk8YyeyWqd+pndNL+3er83iMZnH4M4mhiGA93l0+vtBUvuObgOAMHDJGLLB2SS2xOOZq69oiJh7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next-i18next/-/next-i18next-14.0.3.tgz} id: registry.npmmirror.com/next-i18next/14.0.3 name: next-i18next @@ -4397,16 +4397,16 @@ packages: hoist-non-react-statics: registry.npmmirror.com/hoist-non-react-statics@3.3.2 i18next: registry.npmmirror.com/i18next@23.5.1 i18next-fs-backend: registry.npmmirror.com/i18next-fs-backend@2.2.0 - next: registry.npmmirror.com/next@13.5.4(react-dom@18.0.0)(react@18.0.0) + next: registry.npmmirror.com/next@13.5.5(react-dom@18.0.0)(react@18.0.0) react: registry.npmmirror.com/react@18.0.0 react-i18next: registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0) dev: false - registry.npmmirror.com/next@13.5.4(react-dom@18.0.0)(react@18.0.0): - resolution: {integrity: sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next/-/next-13.5.4.tgz} - id: registry.npmmirror.com/next/13.5.4 + registry.npmmirror.com/next@13.5.5(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-LddFJjpfrtrMMw8Q9VLhIURuSidiCNcMQjRqcPtrKd+Fx07MsG7hYndJb/f2d3I+mTbTotsTJfCnn0eZ/YPk8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next/-/next-13.5.5.tgz} + id: registry.npmmirror.com/next/13.5.5 name: next - version: 13.5.4 + version: 13.5.5 engines: {node: '>=16.14.0'} hasBin: true peerDependencies: @@ -4420,7 +4420,7 @@ packages: sass: optional: true dependencies: - '@next/env': registry.npmmirror.com/@next/env@13.5.4 + '@next/env': registry.npmmirror.com/@next/env@13.5.5 '@swc/helpers': registry.npmmirror.com/@swc/helpers@0.5.2 busboy: registry.npmmirror.com/busboy@1.6.0 caniuse-lite: registry.npmmirror.com/caniuse-lite@1.0.30001549 @@ -4430,15 +4430,15 @@ packages: styled-jsx: registry.npmmirror.com/styled-jsx@5.1.1(react@18.0.0) watchpack: registry.npmmirror.com/watchpack@2.4.0 optionalDependencies: - '@next/swc-darwin-arm64': registry.npmmirror.com/@next/swc-darwin-arm64@13.5.4 - '@next/swc-darwin-x64': registry.npmmirror.com/@next/swc-darwin-x64@13.5.4 - '@next/swc-linux-arm64-gnu': registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.4 - '@next/swc-linux-arm64-musl': registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.4 - '@next/swc-linux-x64-gnu': registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.4 - '@next/swc-linux-x64-musl': registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.4 - '@next/swc-win32-arm64-msvc': registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.4 - '@next/swc-win32-ia32-msvc': registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.4 - '@next/swc-win32-x64-msvc': registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.4 + '@next/swc-darwin-arm64': registry.npmmirror.com/@next/swc-darwin-arm64@13.5.5 + '@next/swc-darwin-x64': registry.npmmirror.com/@next/swc-darwin-x64@13.5.5 + '@next/swc-linux-arm64-gnu': registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.5 + '@next/swc-linux-arm64-musl': registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.5 + '@next/swc-linux-x64-gnu': registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.5 + '@next/swc-linux-x64-musl': registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.5 + '@next/swc-win32-arm64-msvc': registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.5 + '@next/swc-win32-ia32-msvc': registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.5 + '@next/swc-win32-x64-msvc': registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros diff --git a/service/license/src/components/account/index.tsx b/service/license/src/components/account/index.tsx index 2414dc6f4eb..00d41572028 100644 --- a/service/license/src/components/account/index.tsx +++ b/service/license/src/components/account/index.tsx @@ -72,9 +72,15 @@ export default function Account() { {userInfo?.user?.name} - + - + {t('Log Out')} diff --git a/service/license/src/components/icons/DownloadIcon copy 4.tsx b/service/license/src/components/icons/DownloadIcon copy 4.tsx deleted file mode 100644 index b37347364f8..00000000000 --- a/service/license/src/components/icons/DownloadIcon copy 4.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Icon, IconProps } from '@chakra-ui/react'; -export const DownloadIcon = (props: IconProps) => { - return ( - - - - ); -}; diff --git a/service/license/src/components/icons/StripeIcon.tsx b/service/license/src/components/icons/StripeIcon.tsx new file mode 100644 index 00000000000..fdd6f22aa89 --- /dev/null +++ b/service/license/src/components/icons/StripeIcon.tsx @@ -0,0 +1,14 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const StripeIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/index.ts b/service/license/src/components/icons/index.ts index 3f3ea119952..ab672079855 100644 --- a/service/license/src/components/icons/index.ts +++ b/service/license/src/components/icons/index.ts @@ -24,3 +24,4 @@ export * from './TokenIcon'; export * from './CodeDoneIcon'; export * from './VectorIcon'; export * from './SignOutIcon'; +export * from './StripeIcon'; diff --git a/service/license/src/hooks/useBonusBox.tsx b/service/license/src/hooks/useBonusBox.tsx index e2bd9ab0dae..9309146ae09 100644 --- a/service/license/src/hooks/useBonusBox.tsx +++ b/service/license/src/hooks/useBonusBox.tsx @@ -1,15 +1,16 @@ -import { ApiResp } from '@/types'; +import { getPriceBonus } from '@/api/system'; +import { getFavorable } from '@/utils/tools'; import { Flex, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; import { useCallback, useMemo, useState } from 'react'; import CurrencySymbol from '../pages/license/components/CurrencySymbol'; -import { getPriceBonus } from '@/api/system'; export default function useBonusBox() { - const [selectAmountIndex, setSelectAmountIndex] = useState(0); + const { t } = useTranslation(); + const [selectAmountIndex, setSelectAmountIndex] = useState(0); const { data: bonuses, isSuccess } = useQuery(['bonus'], getPriceBonus); - const { ratios, steps } = useMemo(() => { return { ratios: (bonuses?.ratios || '').split(',').map((v) => +v), @@ -17,6 +18,15 @@ export default function useBonusBox() { }; }, [bonuses]); + const getBonus = useCallback( + (amount: number) => { + if (isSuccess && ratios && steps && ratios.length === steps.length) + return getFavorable(steps, ratios)(amount); + else return 0; + }, + [isSuccess, ratios, steps] + ); + const BonusBox = useCallback( () => ( @@ -45,6 +55,23 @@ export default function useBonusBox() { setSelectAmountIndex(index); }} > + {/* + {t('Bonus')} {getBonus(amount)} + */} diff --git a/service/license/src/pages/api/license/getLicense.ts b/service/license/src/pages/api/license/getLicense.ts deleted file mode 100644 index 58a7f0412e6..00000000000 --- a/service/license/src/pages/api/license/getLicense.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { authSession } from '@/services/backend/auth'; -import { createLicenseRecord } from '@/services/backend/db/license'; -import { jsonRes } from '@/services/backend/response'; -import { LicensePayload } from '@/types'; -import type { NextApiRequest, NextApiResponse } from 'next'; - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - const payload = await authSession(req.headers); - if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); - - const { token, orderID, amount, quota, paymentMethod } = req.body as LicensePayload; - - const record = { - uid: payload.uid, - amount: amount, - token: token, - orderID: orderID, - quota: quota, - paymentMethod: paymentMethod - }; - - const result = await createLicenseRecord(record); - - return jsonRes(resp, { - data: result - }); - } catch (error) { - jsonRes(resp, { code: 500, data: error }); - } -} diff --git a/service/license/src/pages/api/license/pay.ts b/service/license/src/pages/api/license/pay.ts index 1366ccb4a13..fa5f64ec786 100644 --- a/service/license/src/pages/api/license/pay.ts +++ b/service/license/src/pages/api/license/pay.ts @@ -1,82 +1,35 @@ -// import { authSession } from '@/services/backend/auth'; -// import { jsonRes } from '@/services/backend/response'; -// import { LicensePaymentForm } from '@/types'; -// import type { NextApiRequest, NextApiResponse } from 'next'; +import { authSession } from '@/services/backend/auth'; +import { jsonRes } from '@/services/backend/response'; +import { enableSealosPay } from '@/services/enable'; +import { getSealosPay } from '@/services/pay'; +import { GET } from '@/services/request'; +import { PaymentParams } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; -// export const generateLicenseCrd = (form: LicensePaymentForm) => { -// const paymentCrd = { -// apiVersion: 'infostream.sealos.io/v1', -// kind: 'Payment', -// metadata: { -// name: form.paymentName, -// namespace: form.namespace -// }, -// spec: { -// userID: form.userId, -// amount: form.amount, // weixin -// paymentMethod: form.paymentMethod, -// service: { -// amt: form.quota, // Actual value -// hid: form.hashID, -// typ: 'account' -// } -// } -// }; -// try { -// const result = yaml.dump(paymentCrd); -// return result; -// } catch (error) { -// throw error; -// } -// }; +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const { amount, payMethod } = req.body as PaymentParams; + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(resp, { code: 401, message: 'token verify error' }); + } + const { SEALOS_PAY_UEL, SEALOS_PAY_ID, SEALOS_PAY_KEY } = getSealosPay(); -// export default async function handler(req: NextApiRequest, resp: NextApiResponse) { -// try { -// const payload = await authSession(req.headers); -// if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + const result = await GET(SEALOS_PAY_UEL, { + appID: SEALOS_PAY_ID, + sign: SEALOS_PAY_KEY, + amount: '199', + currency: 'CNY', + user: userInfo.uid, + payMethod: 'stripe' + }); + console.log(result); -// const { amount, paymentMethod, hid, quota } = req.body as { -// amount: number; -// paymentMethod: 'wechat' | 'stripe'; -// hid: string; -// quota: number; -// }; -// console.log(amount, quota, paymentMethod, hid); -// if (!hid) { -// return jsonRes(resp, { -// code: 400, -// message: 'Missing hid parameter' -// }); -// } -// if (amount <= 0) { -// return jsonRes(resp, { -// code: 400, -// message: 'Amount cannot be less than 0' -// }); -// } - -// const paymentName = crypto.randomUUID(); -// const form: LicensePaymentForm = { -// namespace: payload.user.nsid, -// paymentName: paymentName, -// userId: payload.user.k8s_username, -// amount: amount, -// quota: quota, -// paymentMethod: paymentMethod, -// hashID: hid -// }; - -// const LicenseCrd = generateLicenseCrd(form); - -// const res = await ApplyYaml(payload.kc, LicenseCrd); -// return jsonRes(resp, { -// data: { -// paymentName: paymentName, -// extra: res[0] -// } -// }); -// } catch (error) { -// console.log(error); -// jsonRes(resp, { code: 500, data: error }); -// } -// } + return jsonRes(resp, { + data: 123 + }); + } catch (error) { + console.log(error); + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/result.ts b/service/license/src/pages/api/license/result.ts index 1bab777d5e8..479825d837a 100644 --- a/service/license/src/pages/api/license/result.ts +++ b/service/license/src/pages/api/license/result.ts @@ -1,32 +1,29 @@ -// import { authSession } from '@/services/backend/auth'; -// import { GetCRD } from '@/services/backend/kubernetes/user'; -// import { jsonRes } from '@/services/backend/response'; -// import type { NextApiRequest, NextApiResponse } from 'next'; +import { authSession } from '@/services/backend/auth'; +import { jsonRes } from '@/services/backend/response'; +import { GET } from '@/services/request'; +import { PaymentParams } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; -// export default async function handler(req: NextApiRequest, resp: NextApiResponse) { -// try { -// const payload = await authSession(req.headers); -// if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const { amount, payMethod } = req.body as PaymentParams; + const userInfo = await authSession(req.headers); + if (!userInfo) return jsonRes(resp, { code: 401, message: 'token verify error' }); -// const { paymentName } = req.query as { -// paymentName: string; -// }; + const result = await GET('http://localhost:2303/v1alpha1/pay/bill', { + appID: 45141910007488120, + sign: '076f82f8e996d7', + orderID: 'iGP0mHMJfxfamCBqeA', + payMethod: 'stripe', + user: 'jiahui', + sessionID: 'cs_test_a1UH60aWlJpnbi6c1LA287ymXv0mWDYdT6oonpRduTs9zzSF6OU87WSXa2' + }); -// if (typeof paymentName !== 'string' || paymentName === '') { -// return jsonRes(resp, { code: 400, message: 'payment name cannot be empty' }); -// } - -// const paymentM = { -// group: 'infostream.sealos.io', -// version: 'v1', -// namespace: payload.user.nsid, -// plural: 'payments' -// }; -// const paymentDesc = await GetCRD(payload.kc, paymentM, paymentName); -// console.log(paymentDesc?.body?.status, 'payment'); -// return jsonRes(resp, { data: paymentDesc?.body?.status }); -// } catch (error) { -// console.log(error); -// jsonRes(resp, { code: 500, data: error }); -// } -// } + return jsonRes(resp, { + data: 123 + }); + } catch (error) { + console.log(error); + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/platform/getEnv.ts b/service/license/src/pages/api/platform/getEnv.ts index 455c83e8e0f..4cadf3efc77 100644 --- a/service/license/src/pages/api/platform/getEnv.ts +++ b/service/license/src/pages/api/platform/getEnv.ts @@ -7,9 +7,9 @@ import { enableSms, enableGoogle, enableStripe, - enableWechatRecharge, - enableLicense + enableWechatRecharge } from '@/services/enable'; +import { SystemEnv } from '@/types'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const wechat_client_id = process.env.WECHAT_CLIENT_ID || ''; @@ -22,12 +22,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const needPassword = enablePassword(); const needSms = enableSms(); const needGoogle = enableGoogle(); - const callback_url = process.env.CALLBACK_URL; + const callback_url = process.env.CALLBACK_URL || ''; const stripeEnabled = enableStripe(); const wechatEnabledRecharge = enableWechatRecharge(); - const licenseEnabled = enableLicense(); - jsonRes(res, { + jsonRes(res, { data: { SEALOS_CLOUD_DOMAIN: process.env.SEALOS_CLOUD_DOMAIN || 'cloud.sealos.io', wechat_client_id, @@ -42,8 +41,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) needWechat, needGoogle, stripeEnabled, - wechatEnabledRecharge, - licenseEnabled + wechatEnabledRecharge } }); } diff --git a/service/license/src/pages/api/price/bonus.ts b/service/license/src/pages/api/price/bonus.ts index 6f1467e2791..8e3369d77df 100644 --- a/service/license/src/pages/api/price/bonus.ts +++ b/service/license/src/pages/api/price/bonus.ts @@ -1,7 +1,5 @@ import { authSession } from '@/services/backend/auth'; - import { jsonRes } from '@/services/backend/response'; -import { enableRecharge } from '@/services/enable'; import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, resp: NextApiResponse) { diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index 3484738c796..09c145bb3d7 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -1,6 +1,6 @@ import { getLicenseResult, licensePay, createLicenseRecord } from '@/api/license'; import { getSystemEnv } from '@/api/system'; -import { WechatIcon } from '@/components/icons'; +import { StripeIcon, WechatIcon } from '@/components/icons'; import useBonusBox from '@/hooks/useBonusBox'; import { useCustomToast } from '@/hooks/useCustomToast'; import { LicensePayload } from '@/types'; @@ -213,33 +213,34 @@ export default function RechargeComponent() { {/* */} - {/* {platformEnv?.data?.stripeEnabled && ( + {platformEnv?.stripeEnabled && ( - )} */} + )} - + {platformEnv?.wechatEnabledRecharge && ( + + )} 充值金额 - diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts index 89a59485170..e8cfcc407d9 100644 --- a/service/license/src/services/backend/db/license.ts +++ b/service/license/src/services/backend/db/license.ts @@ -1,9 +1,10 @@ -import { LicensePayload, LicenseRecord } from '@/types'; +import { LicensePayload, LicenseRecord, LicenseToken } from '@/types'; +import { sign } from 'jsonwebtoken'; import { connectToDatabase } from './mongodb'; async function connectLicenseRecordCollection() { const client = await connectToDatabase(); - const collection = client.db().collection('licenseRecord'); + const collection = client.db().collection('license'); return collection; } @@ -70,3 +71,22 @@ export async function getLicenseRecordsByUid({ return result; } + +export function generateLicenseToken(payload: LicenseToken) { + const privateKey = process.env.LICENSE_PRIVATE_KEY; + if (!privateKey) { + throw new Error('PRIVATE KEY is missing'); + } + const nowInSeconds = Math.floor(Date.now() / 1000); + const expirationTime = nowInSeconds + 3 * 24 * 60 * 60; + + const _payload = { + iss: 'Sealos', + iat: nowInSeconds, + exp: expirationTime, + ...payload + }; + + const token = sign(_payload, privateKey, { algorithm: 'RS256' }); + return token; +} diff --git a/service/license/src/services/enable.ts b/service/license/src/services/enable.ts index 322f9e35ae4..bd8ac7ea11a 100644 --- a/service/license/src/services/enable.ts +++ b/service/license/src/services/enable.ts @@ -22,11 +22,10 @@ export const enableGoogle = () => export const enableRecharge = () => { return process.env.RECHARGE_ENABLED === 'true'; }; -// costcenter +// pay type export const enableStripe = () => process.env['STRIPE_ENABLED'] === 'true' && !!process.env['STRIPE_PUB']; export const enableWechatRecharge = () => process.env['WECHAT_ENABLED'] === 'true'; -// license -export const enableLicense = () => { - return process.env.LICENSE_ENABLED === 'true'; -}; +// sealos pay +export const enableSealosPay = () => + process.env.SEALOS_PAY_ID && process.env.SEALOS_PAY_KEY && process.env.SEALOS_PAY_UEL; diff --git a/service/license/src/services/pay.ts b/service/license/src/services/pay.ts new file mode 100644 index 00000000000..1a93ea71516 --- /dev/null +++ b/service/license/src/services/pay.ts @@ -0,0 +1,13 @@ +import { enableSealosPay } from './enable'; + +export const getSealosPay = () => { + if (!process.env.SEALOS_PAY_UEL || !process.env.SEALOS_PAY_ID || !process.env.SEALOS_PAY_KEY) { + throw new Error('sealos payment has not been activated'); + } + + return { + SEALOS_PAY_UEL: process.env.SEALOS_PAY_UEL, + SEALOS_PAY_ID: process.env.SEALOS_PAY_ID, + SEALOS_PAY_KEY: process.env.SEALOS_PAY_KEY + }; +}; diff --git a/service/license/src/services/request.ts b/service/license/src/services/request.ts index 3023937b866..703986c6685 100644 --- a/service/license/src/services/request.ts +++ b/service/license/src/services/request.ts @@ -52,7 +52,7 @@ const showStatus = (status: number) => { const request = axios.create({ baseURL: '/', withCredentials: true, - timeout: 30000 + timeout: 20 * 1000 }); // request interceptor diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts index 69d699c2f71..b4bcb7ebb03 100644 --- a/service/license/src/types/license.ts +++ b/service/license/src/types/license.ts @@ -1,43 +1,43 @@ -export type LicenseCrd = { - apiVersion: 'infostream.sealos.io/v1'; - kind: 'Payment'; - metadata: { - name: string; - namespace: string; - }; - spec: { - userID: string; - amount: number; - paymentMethod: 'wechat' | 'stripe'; - service: { - amt: number; - objType: string; // 'external,internal' - }; - }; - status: { - tradeNO: string; - codeURL: string; - status: 'Created' | 'Completed'; - token: string; - }; -}; +// export type LicenseCrd = { +// apiVersion: 'infostream.sealos.io/v1'; +// kind: 'Payment'; +// metadata: { +// name: string; +// namespace: string; +// }; +// spec: { +// userID: string; +// amount: number; +// paymentMethod: 'wechat' | 'stripe'; +// service: { +// amt: number; +// objType: string; // 'external,internal' +// }; +// }; +// status: { +// tradeNO: string; +// codeURL: string; +// status: 'Created' | 'Completed'; +// token: string; +// }; +// }; -export type LicensePaymentForm = { - paymentName: string; - namespace: string; - userId: string; - amount: number; - paymentMethod: 'wechat' | 'stripe'; - hashID: string; - quota: number; -}; +// export type LicensePaymentForm = { +// paymentName: string; +// namespace: string; +// userId: string; +// amount: number; +// paymentMethod: 'wechat' | 'stripe'; +// hashID: string; +// quota: number; +// }; -export type LicensePayStatus = { - tradeNO: string; - codeURL: string; - status: 'Created' | 'Completed'; - token: string; -}; +// export type LicensePayStatus = { +// tradeNO: string; +// codeURL: string; +// status: 'Created' | 'Completed'; +// token: string; +// }; export type LicenseRecord = { _id?: string; @@ -61,3 +61,11 @@ export type LicensePayload = { quota: number; paymentMethod: 'wechat' | 'stripe'; }; + +// new +export type LicenseToken = { + type: 'Account' | 'Cluster'; + data: { + amount: number; + }; +}; diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index 9746447735f..39da16ff047 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -1,58 +1,26 @@ -// import * as yaml from 'js-yaml'; -// import { CRDMeta } from './crd'; +export enum PaymentStatus { + PaymentNotPaid = 'notpaid', // 未支付 + PaymentProcessing = 'processing', // 支付中 + PaymentFailed = 'failed', // 支付失败 + PaymentExpired = 'expired', // 支付过期 + PaymentSuccess = 'success', // 支付成功 + PaymentUnknown = 'unknown' // 未知 +} -export type PaymentForm = { - paymentName: string; - namespace: string; - userId: string; +export type PaymentParams = { + // appID: number; + // sign: string; amount: string; + currency: string; + // user: string; + payMethod: 'stripe' | 'wechat'; }; -// export const paymentMeta: CRDMeta = { -// group: 'account.sealos.io', -// version: 'v1', -// namespace: 'sealos-system', -// plural: 'payments' -// }; - -export type Payment = { - paymentName: string; - extra: { - apiVersion: 'account.sealos.io/v1'; - kind: 'Payment'; - metadata: unknown; - spec: { - amount: number; - paymentMethod: string; - userID: string; - }; - }; -}; -export type Pay = { - codeURL: string; - status?: 'Created' | 'SUCCESS'; - tradeNO: string; +export type PaymentRequest = { + appID: number; + sign: string; + orderID: string; + payMethod: string; + user: string; + sessionID: string; }; - -// export const generatePaymentCrd = (form: PaymentForm) => { -// const paymentCrd = { -// apiVersion: 'account.sealos.io/v1', -// kind: 'Payment', -// metadata: { -// name: form.paymentName, -// namespace: form.namespace -// }, -// spec: { -// userID: form.userId, -// amount: form.amount, -// paymentMethod: 'wechat' -// } -// }; - -// try { -// const result = yaml.dump(paymentCrd); -// return result; -// } catch (error) { -// return ''; -// } -// }; diff --git a/service/license/src/types/system.ts b/service/license/src/types/system.ts index 3fa09f8bbba..a7064092aaf 100644 --- a/service/license/src/types/system.ts +++ b/service/license/src/types/system.ts @@ -25,5 +25,4 @@ export type SystemEnv = { SEALOS_CLOUD_DOMAIN: string; stripeEnabled: boolean; wechatEnabledRecharge: boolean; - licenseEnabled: boolean; } & LoginProps; From 5d0e36ba48918326c9d7e0ec72455c978b81ce8c Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Wed, 18 Oct 2023 22:07:50 +0800 Subject: [PATCH 04/17] done Signed-off-by: jingyang <3161362058@qq.com> --- service/license/package.json | 3 +- service/license/pnpm-lock.yaml | 19 +++- service/license/src/api/license.ts | 25 +---- service/license/src/api/payment.ts | 8 ++ service/license/src/hooks/useCustomToast.ts | 13 --- service/license/src/pages/_app.tsx | 1 + .../pages/api/license/createLicenseRecord.ts | 8 +- service/license/src/pages/api/license/pay.ts | 35 ------ .../license/src/pages/api/license/result.ts | 29 ----- .../license/src/pages/api/payment/create.ts | 51 +++++++++ .../license/src/pages/api/payment/result.ts | 34 ++++++ .../license/src/pages/api/platform/getEnv.ts | 4 +- .../src/pages/license/components/Recharge.tsx | 103 ++++++++++-------- service/license/src/pages/license/index.tsx | 52 ++++++++- .../src/services/backend/db/license.ts | 3 +- service/license/src/services/pay.ts | 8 +- service/license/src/types/license.ts | 64 ++--------- service/license/src/types/payment.ts | 31 ++++-- service/license/src/types/system.ts | 1 + service/license/src/utils/tools.ts | 13 +++ 20 files changed, 277 insertions(+), 228 deletions(-) create mode 100644 service/license/src/api/payment.ts delete mode 100644 service/license/src/hooks/useCustomToast.ts delete mode 100644 service/license/src/pages/api/license/pay.ts delete mode 100644 service/license/src/pages/api/license/result.ts create mode 100644 service/license/src/pages/api/payment/create.ts create mode 100644 service/license/src/pages/api/payment/result.ts diff --git a/service/license/package.json b/service/license/package.json index def8483e361..ed0a9384efa 100644 --- a/service/license/package.json +++ b/service/license/package.json @@ -15,6 +15,7 @@ "@chakra-ui/react": "^2.8.1", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", + "@stripe/stripe-js": "^2.1.9", "@tanstack/react-query": "^4.36.1", "axios": "^1.5.1", "clsx": "^2.0.0", @@ -39,7 +40,7 @@ }, "devDependencies": { "@types/js-cookie": "^3.0.4", - "@types/jsonwebtoken": "^9.0.3", + "@types/jsonwebtoken": "^9.0.4", "@types/lodash": "^4.14.199", "@types/node": "^20", "@types/nprogress": "^0.2.1", diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml index 11b238131e7..bf342891b07 100644 --- a/service/license/pnpm-lock.yaml +++ b/service/license/pnpm-lock.yaml @@ -23,6 +23,9 @@ dependencies: '@emotion/styled': specifier: ^11.11.0 version: registry.npmmirror.com/@emotion/styled@11.11.0(@emotion/react@11.11.1)(@types/react@18.0.0)(react@18.0.0) + '@stripe/stripe-js': + specifier: ^2.1.9 + version: registry.npmmirror.com/@stripe/stripe-js@2.1.9 '@tanstack/react-query': specifier: ^4.36.1 version: registry.npmmirror.com/@tanstack/react-query@4.36.1(react-dom@18.0.0)(react@18.0.0) @@ -92,8 +95,8 @@ devDependencies: specifier: ^3.0.4 version: registry.npmmirror.com/@types/js-cookie@3.0.4 '@types/jsonwebtoken': - specifier: ^9.0.3 - version: registry.npmmirror.com/@types/jsonwebtoken@9.0.3 + specifier: ^9.0.4 + version: registry.npmmirror.com/@types/jsonwebtoken@9.0.4 '@types/lodash': specifier: ^4.14.199 version: registry.npmmirror.com/@types/lodash@4.14.199 @@ -2009,6 +2012,12 @@ packages: version: 1.5.1 dev: true + registry.npmmirror.com/@stripe/stripe-js@2.1.9: + resolution: {integrity: sha512-0RSvCJrzEVx52e8hbSAcZ2vv6OzoFj5fe5XC50GSrcev1Y4t2XDE6W5CIhR/Y6l3CPgO/P4luqoLWuvpUkBhig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@stripe/stripe-js/-/stripe-js-2.1.9.tgz} + name: '@stripe/stripe-js' + version: 2.1.9 + dev: false + registry.npmmirror.com/@swc/helpers@0.5.2: resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.2.tgz} name: '@swc/helpers' @@ -2065,10 +2074,10 @@ packages: version: 0.0.29 dev: true - registry.npmmirror.com/@types/jsonwebtoken@9.0.3: - resolution: {integrity: sha512-b0jGiOgHtZ2jqdPgPnP6WLCXZk1T8p06A/vPGzUvxpFGgKMbjXJDjC5m52ErqBnIuWZFgGoIJyRdeG5AyreJjA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz} + registry.npmmirror.com/@types/jsonwebtoken@9.0.4: + resolution: {integrity: sha512-8UYapdmR0QlxgvJmyE8lP7guxD0UGVMfknsdtCFZh4ovShdBl3iOI4zdvqBHrB/IS+xUj3PSx73Qkey1fhWz+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.4.tgz} name: '@types/jsonwebtoken' - version: 9.0.3 + version: 9.0.4 dependencies: '@types/node': registry.npmmirror.com/@types/node@20.0.0 dev: true diff --git a/service/license/src/api/license.ts b/service/license/src/api/license.ts index be5c8ec6568..38ffcc8f641 100644 --- a/service/license/src/api/license.ts +++ b/service/license/src/api/license.ts @@ -1,32 +1,9 @@ import { GET, POST } from '@/services/request'; -import { LicensePayStatus, LicensePayload, LicenseRecord, Payment } from '@/types'; - -export const licensePay = ({ - amount, - quota, - paymentMethod, - hid -}: { - amount: number; - quota: number; - paymentMethod: 'wechat' | 'stripe'; - hid: string; -}) => - POST('/api/license/pay', { - amount, - quota, - paymentMethod, - hid - }); +import { LicensePayload, LicenseRecord } from '@/types'; export const createLicenseRecord = (payload: LicensePayload) => POST('/api/license/createLicenseRecord', payload); -export const getLicenseResult = (paymentName: string) => - GET('/api/license/result', { - paymentName: paymentName - }); - export const getLicenseRecord = ({ page, pageSize }: { page: number; pageSize: number }) => POST<{ total: number; records: LicenseRecord[] }>('/api/license/getLicenseRecord', { page, diff --git a/service/license/src/api/payment.ts b/service/license/src/api/payment.ts new file mode 100644 index 00000000000..de7a7e63001 --- /dev/null +++ b/service/license/src/api/payment.ts @@ -0,0 +1,8 @@ +import { GET, POST } from '@/services/request'; +import { PaymentParams, PaymentResultParams, StripePaymentData, WechatPaymentData } from '@/types'; + +export const createPayment = (payload: PaymentParams) => + POST('/api/payment/create', payload); + +export const getPaymentResult = (payload: PaymentResultParams) => + POST('/api/payment/result', payload); diff --git a/service/license/src/hooks/useCustomToast.ts b/service/license/src/hooks/useCustomToast.ts deleted file mode 100644 index 4e495239b2b..00000000000 --- a/service/license/src/hooks/useCustomToast.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useToast as uToast, UseToastOptions } from '@chakra-ui/react'; - -export const useCustomToast = (props?: UseToastOptions) => { - const toast = uToast({ - position: 'top', - duration: 2000, - ...props - }); - - return { - toast - }; -}; diff --git a/service/license/src/pages/_app.tsx b/service/license/src/pages/_app.tsx index af80e6c4141..e34ebdebe6e 100644 --- a/service/license/src/pages/_app.tsx +++ b/service/license/src/pages/_app.tsx @@ -7,6 +7,7 @@ import Router from 'next/router'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; import { theme } from '@/styles/chakraTheme'; +import '@stripe/stripe-js'; const queryClient = new QueryClient({ defaultOptions: { diff --git a/service/license/src/pages/api/license/createLicenseRecord.ts b/service/license/src/pages/api/license/createLicenseRecord.ts index 58a7f0412e6..2d19826440c 100644 --- a/service/license/src/pages/api/license/createLicenseRecord.ts +++ b/service/license/src/pages/api/license/createLicenseRecord.ts @@ -1,5 +1,5 @@ import { authSession } from '@/services/backend/auth'; -import { createLicenseRecord } from '@/services/backend/db/license'; +import { createLicenseRecord, generateLicenseToken } from '@/services/backend/db/license'; import { jsonRes } from '@/services/backend/response'; import { LicensePayload } from '@/types'; import type { NextApiRequest, NextApiResponse } from 'next'; @@ -9,12 +9,14 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse const payload = await authSession(req.headers); if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); - const { token, orderID, amount, quota, paymentMethod } = req.body as LicensePayload; + const { orderID, amount, quota, paymentMethod } = req.body as LicensePayload; + + const _token = generateLicenseToken({ type: 'Account', data: { amount: quota } }); const record = { uid: payload.uid, amount: amount, - token: token, + token: _token, orderID: orderID, quota: quota, paymentMethod: paymentMethod diff --git a/service/license/src/pages/api/license/pay.ts b/service/license/src/pages/api/license/pay.ts deleted file mode 100644 index fa5f64ec786..00000000000 --- a/service/license/src/pages/api/license/pay.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { authSession } from '@/services/backend/auth'; -import { jsonRes } from '@/services/backend/response'; -import { enableSealosPay } from '@/services/enable'; -import { getSealosPay } from '@/services/pay'; -import { GET } from '@/services/request'; -import { PaymentParams } from '@/types'; -import type { NextApiRequest, NextApiResponse } from 'next'; - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - const { amount, payMethod } = req.body as PaymentParams; - const userInfo = await authSession(req.headers); - if (!userInfo) { - return jsonRes(resp, { code: 401, message: 'token verify error' }); - } - const { SEALOS_PAY_UEL, SEALOS_PAY_ID, SEALOS_PAY_KEY } = getSealosPay(); - - const result = await GET(SEALOS_PAY_UEL, { - appID: SEALOS_PAY_ID, - sign: SEALOS_PAY_KEY, - amount: '199', - currency: 'CNY', - user: userInfo.uid, - payMethod: 'stripe' - }); - console.log(result); - - return jsonRes(resp, { - data: 123 - }); - } catch (error) { - console.log(error); - jsonRes(resp, { code: 500, data: error }); - } -} diff --git a/service/license/src/pages/api/license/result.ts b/service/license/src/pages/api/license/result.ts deleted file mode 100644 index 479825d837a..00000000000 --- a/service/license/src/pages/api/license/result.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { authSession } from '@/services/backend/auth'; -import { jsonRes } from '@/services/backend/response'; -import { GET } from '@/services/request'; -import { PaymentParams } from '@/types'; -import type { NextApiRequest, NextApiResponse } from 'next'; - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - const { amount, payMethod } = req.body as PaymentParams; - const userInfo = await authSession(req.headers); - if (!userInfo) return jsonRes(resp, { code: 401, message: 'token verify error' }); - - const result = await GET('http://localhost:2303/v1alpha1/pay/bill', { - appID: 45141910007488120, - sign: '076f82f8e996d7', - orderID: 'iGP0mHMJfxfamCBqeA', - payMethod: 'stripe', - user: 'jiahui', - sessionID: 'cs_test_a1UH60aWlJpnbi6c1LA287ymXv0mWDYdT6oonpRduTs9zzSF6OU87WSXa2' - }); - - return jsonRes(resp, { - data: 123 - }); - } catch (error) { - console.log(error); - jsonRes(resp, { code: 500, data: error }); - } -} diff --git a/service/license/src/pages/api/payment/create.ts b/service/license/src/pages/api/payment/create.ts new file mode 100644 index 00000000000..0ac304df499 --- /dev/null +++ b/service/license/src/pages/api/payment/create.ts @@ -0,0 +1,51 @@ +import { authSession, verifyJWT } from '@/services/backend/auth'; +import { generateLicenseToken } from '@/services/backend/db/license'; +import { jsonRes } from '@/services/backend/response'; +import { getSealosPay } from '@/services/pay'; +import { PaymentParams } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; +import { sign, verify } from 'jsonwebtoken'; +import { base64Decode } from '@/utils/tools'; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const { amount, currency = 'CNY', payMethod = 'wechat' } = req.body as PaymentParams; + + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(resp, { code: 401, message: 'token verify error' }); + } + const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); + + const result = await fetch(`${sealosPayUrl}/v1alpha1/pay/session`, { + method: 'POST', + body: JSON.stringify({ + appID: +sealosPayID, + sign: sealosPayKey, + amount: '1688', + currency: 'CNY', + user: 'jiahui', + payMethod: payMethod + }) + }).then((res) => res.json()); + + // const res = generateLicenseToken({ type: 'Account', data: { amount: 19999 } }); + // console.log(res); + // verify( + // res, + // base64Decode( + // 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFvbFBTSzB0UjFKeDZtb25lL2ppeApSWGN6UGlxcU5SSXRmdW1mdWNyNGMxc2dqdlJha0NwcWtDU21lMTR1akJkU0x6QlZzRjkvUWl0UnFNb2NvaEN1CkJ6R25EQ29hWnZXbWVHeE96NEZSejVTeUg1QTlDa3dnbUEzYnFnMWxKSEZTMlZyVjVHVFhFWnphZTZtRmhHOVcKenJMTnpZMlptYTMzOVE1WTNJSDZ6RXIrcTRQbTZDOXBHVGpsSnVodlRvb0dSY2w0bmpZRXc2eHB6ZHZrdi9uSApmZmxsWGZVNDNyRGdQaGkwZDRjWnNuTUJlazUxQkNiRFRuSHlNVFdGT1RoTjc1VVM0bzJxRm9JSEhsM0N0RzE4ClZIZEdRSE1IR0dYcGN3bVhhck1EQndwVWFOSk9kMkhjTTB5dlZEY2xDZzRITkIwVUFWeFNweFlRV3BwNWJzN2gKbHdJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==' + // ), + // function (err, decoded) { + // console.log(decoded); + // } + // ); + + return jsonRes(resp, { + data: result + }); + } catch (error) { + console.log(error); + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts new file mode 100644 index 00000000000..8ad9354b373 --- /dev/null +++ b/service/license/src/pages/api/payment/result.ts @@ -0,0 +1,34 @@ +import { authSession } from '@/services/backend/auth'; +import { jsonRes } from '@/services/backend/response'; +import { getSealosPay } from '@/services/pay'; +import { PaymentParams, PaymentResultParams } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, resp: NextApiResponse) { + try { + const { payMethod, sessionID, orderID } = req.body as PaymentResultParams; + const userInfo = await authSession(req.headers); + if (!userInfo) return jsonRes(resp, { code: 401, message: 'token verify error' }); + + const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); + + const result = await fetch(`${sealosPayUrl}/v1alpha1/pay/status`, { + method: 'POST', + body: JSON.stringify({ + appID: 45141910007488120, + sign: '076f82f8e996d7', + orderID: orderID, + payMethod: 'stripe', + user: 'jiahui', + sessionID: 'cs_test_a1UH60aWlJpnbi6c1LA287ymXv0mWDYdT6oonpRduTs9zzSF6OU87WSXa2' + }) + }); + + return jsonRes(resp, { + data: result + }); + } catch (error) { + console.log(error); + jsonRes(resp, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/platform/getEnv.ts b/service/license/src/pages/api/platform/getEnv.ts index 4cadf3efc77..e12ba13f215 100644 --- a/service/license/src/pages/api/platform/getEnv.ts +++ b/service/license/src/pages/api/platform/getEnv.ts @@ -25,6 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const callback_url = process.env.CALLBACK_URL || ''; const stripeEnabled = enableStripe(); const wechatEnabledRecharge = enableWechatRecharge(); + const stripePub = process.env.STRIPE_PUB || ''; jsonRes(res, { data: { @@ -41,7 +42,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) needWechat, needGoogle, stripeEnabled, - wechatEnabledRecharge + wechatEnabledRecharge, + stripePub } }); } diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index 09c145bb3d7..dca5e3efdd9 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -1,9 +1,8 @@ -import { getLicenseResult, licensePay, createLicenseRecord } from '@/api/license'; +import { createLicenseRecord } from '@/api/license'; import { getSystemEnv } from '@/api/system'; import { StripeIcon, WechatIcon } from '@/components/icons'; import useBonusBox from '@/hooks/useBonusBox'; -import { useCustomToast } from '@/hooks/useCustomToast'; -import { LicensePayload } from '@/types'; +import { LicensePayload, StripePaymentData } from '@/types'; import { deFormatMoney } from '@/utils/format'; import { Button, @@ -16,16 +15,20 @@ import { ModalHeader, ModalOverlay, Text, - useDisclosure + useDisclosure, + useToast } from '@chakra-ui/react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; import { useState } from 'react'; import WechatPayment from './WechatPayment'; +import { createPayment, getPaymentResult } from '@/api/payment'; +import { loadStripe } from '@stripe/stripe-js'; export default function RechargeComponent() { const { t } = useTranslation(); + const queryClient = useQueryClient(); const [isAgree, setIsAgree] = useState(false); const [isInvalid, setIsInvalid] = useState(false); const { BonusBox, selectAmount } = useBonusBox(); @@ -35,35 +38,32 @@ export default function RechargeComponent() { // 0 是微信,1 是stripe const [payType, setPayType] = useState<'wechat' | 'stripe'>('wechat'); const [paymentName, setPaymentName] = useState(''); - const queryClient = useQueryClient(); - const { toast } = useCustomToast(); - const { query } = useRouter(); - const [hid, setHid] = useState(''); // license key + const toast = useToast({ position: 'top', duration: 2000 }); + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); - // handle hid - // useEffect(() => { - // if (query?.hid && typeof query.hid === 'string') { - // const decodedHid = decodeURIComponent(query.hid); - // setHid(decodedHid); - // } else { - // toast({ - // status: 'error', - // title: 'Purchase Link Error', - // isClosable: true, - // position: 'top' - // }); - // } - // }, []); + console.log(selectAmount, '11111'); const onModalClose = () => { setComplete(0); onClose(); }; + const handleStripeConfirm = () => { + setPayType('stripe'); + if (selectAmount < 10) { + return toast({ + status: 'error', + title: t('Pay Minimum Tips') + }); + } + setComplete(1); + paymentMutation.mutate(); + }; + const handleWechatConfirm = () => { if (isAgree) { setComplete(1); - createPaymentLicense.mutate(); + paymentMutation.mutate(); onOpen(); } else { toast({ @@ -75,21 +75,24 @@ export default function RechargeComponent() { } }; - const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); - - const createPaymentLicense = useMutation( + const paymentMutation = useMutation( () => - licensePay({ - amount: deFormatMoney(selectAmount), - quota: selectAmount, - paymentMethod: payType, - hid: hid + createPayment({ + amount: deFormatMoney(selectAmount).toString(), + payMethod: payType, + currency: 'CNY' }), - { - onSuccess(data) { - console.log(data); - setPaymentName((data?.paymentName as string).trim()); + async onSuccess(data) { + console.log(data, '======='); + if (payType === 'stripe' && platformEnv?.stripePub && data?.sessionID) { + const stripe = await loadStripe(platformEnv?.stripePub); + stripe?.redirectToCheckout({ + sessionId: data.sessionID + }); + } else if (payType === 'wechat') { + } + // setPaymentName((data?.paymentName as string).trim()); setComplete(2); }, onError(err: any) { @@ -119,13 +122,14 @@ export default function RechargeComponent() { const { data } = useQuery( ['getLicenseResult', paymentName], - () => getLicenseResult(paymentName), + () => getPaymentResult({ orderID }), { refetchInterval: complete === 2 ? 1000 : false, enabled: complete === 2 && !!paymentName, cacheTime: 0, staleTime: 0, onSuccess(data) { + console.log(data); if (data?.status === 'Completed') { onModalClose(); toast({ @@ -134,14 +138,14 @@ export default function RechargeComponent() { isClosable: true, position: 'top' }); - licenseRecordMutation.mutate({ - uid: '', - amount: deFormatMoney(selectAmount), - quota: selectAmount, - token: data?.token, - orderID: data?.tradeNO, - paymentMethod: 'wechat' - }); + // licenseRecordMutation.mutate({ + // uid: '', + // amount: deFormatMoney(selectAmount), + // quota: selectAmount, + // token: data?.token, + // orderID: data?.tradeNO, + // paymentMethod: 'wechat' + // }); } } } @@ -214,7 +218,16 @@ export default function RechargeComponent() { {platformEnv?.stripeEnabled && ( - diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx index ea3da06f332..c964dbf42cd 100644 --- a/service/license/src/pages/license/index.tsx +++ b/service/license/src/pages/license/index.tsx @@ -1,18 +1,59 @@ import LangSelectSimple from '@/components/LangSelect'; -import { Flex, Image, Text } from '@chakra-ui/react'; +import { Flex, Image, Text, useToast } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import RechargeComponent from './components/Recharge'; import LicenseRecord from './components/Record'; import { useRouter } from 'next/router'; -import { useQuery } from '@tanstack/react-query'; -import { ApiResp, SystemEnv } from '@/types'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { ApiResp, LicensePayload, SystemEnv } from '@/types'; import Account from '@/components/account'; +import { useEffect } from 'react'; +import { createLicenseRecord } from '@/api/license'; +import { setCookie } from '@/utils/cookieUtils'; export default function LicensePage() { const { t } = useTranslation(); const router = useRouter(); const goHome = () => router.replace('/'); + const totast = useToast(); + // const queryClient = useQueryClient(); + + // const licenseRecordMutation = useMutation( + // (payload: LicensePayload) => createLicenseRecord(payload), + // { + // onSuccess(data) { + // console.log(data); + // queryClient.invalidateQueries(['getLicenseActive']); + // }, + // onError(err: any) { + // console.log(err); + // } + // } + // ); + + // useEffect(() => { + // const { stripeState } = router.query; + // if (stripeState === 'success') { + // totast({ + // status: 'success', + // duration: 3000, + // title: t('Stripe Success'), + // isClosable: true, + // position: 'top' + // }); + // licenseRecordMutation.mutate(); + // } else if (stripeState === 'error') { + // totast({ + // status: 'error', + // duration: 3000, + // title: t('Stripe Cancel'), + // isClosable: true, + // position: 'top' + // }); + // } + // !!stripeState && router.replace(router.pathname); + // }, []); return ( @@ -53,7 +94,10 @@ export default function LicensePage() { } export async function getServerSideProps({ req, res, locales }: any) { - const local = req?.cookies?.NEXT_LOCALE || 'en'; + const lang: string = req?.headers?.['accept-language'] || 'zh'; + const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; + console.log(local); + // setCookie() return { props: { diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts index e8cfcc407d9..ef35d01a6f1 100644 --- a/service/license/src/services/backend/db/license.ts +++ b/service/license/src/services/backend/db/license.ts @@ -1,6 +1,7 @@ import { LicensePayload, LicenseRecord, LicenseToken } from '@/types'; import { sign } from 'jsonwebtoken'; import { connectToDatabase } from './mongodb'; +import { base64Decode } from '@/utils/tools'; async function connectLicenseRecordCollection() { const client = await connectToDatabase(); @@ -87,6 +88,6 @@ export function generateLicenseToken(payload: LicenseToken) { ...payload }; - const token = sign(_payload, privateKey, { algorithm: 'RS256' }); + const token = sign(_payload, base64Decode(privateKey), { algorithm: 'RS256' }); return token; } diff --git a/service/license/src/services/pay.ts b/service/license/src/services/pay.ts index 1a93ea71516..ce3a44f13f1 100644 --- a/service/license/src/services/pay.ts +++ b/service/license/src/services/pay.ts @@ -1,13 +1,11 @@ -import { enableSealosPay } from './enable'; - export const getSealosPay = () => { if (!process.env.SEALOS_PAY_UEL || !process.env.SEALOS_PAY_ID || !process.env.SEALOS_PAY_KEY) { throw new Error('sealos payment has not been activated'); } return { - SEALOS_PAY_UEL: process.env.SEALOS_PAY_UEL, - SEALOS_PAY_ID: process.env.SEALOS_PAY_ID, - SEALOS_PAY_KEY: process.env.SEALOS_PAY_KEY + sealosPayUrl: process.env.SEALOS_PAY_UEL, + sealosPayID: process.env.SEALOS_PAY_ID, + sealosPayKey: process.env.SEALOS_PAY_KEY }; }; diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts index b4bcb7ebb03..f544467dfb6 100644 --- a/service/license/src/types/license.ts +++ b/service/license/src/types/license.ts @@ -1,62 +1,20 @@ -// export type LicenseCrd = { -// apiVersion: 'infostream.sealos.io/v1'; -// kind: 'Payment'; -// metadata: { -// name: string; -// namespace: string; -// }; -// spec: { -// userID: string; -// amount: number; -// paymentMethod: 'wechat' | 'stripe'; -// service: { -// amt: number; -// objType: string; // 'external,internal' -// }; -// }; -// status: { -// tradeNO: string; -// codeURL: string; -// status: 'Created' | 'Completed'; -// token: string; -// }; -// }; - -// export type LicensePaymentForm = { -// paymentName: string; -// namespace: string; -// userId: string; -// amount: number; +// export type LicenseRecord = { +// _id?: string; +// uid: string; // user id +// token: string; // license token +// orderID: string; // order number // paymentMethod: 'wechat' | 'stripe'; -// hashID: string; -// quota: number; -// }; - -// export type LicensePayStatus = { -// tradeNO: string; -// codeURL: string; -// status: 'Created' | 'Completed'; -// token: string; +// service: { +// quota: number; // 额度 +// }; +// iat: number; // 签发日期 +// exp: number; // 有效期 +// amount: number; // 消费金额 // }; -export type LicenseRecord = { - _id?: string; - uid: string; // user id - token: string; // license token - orderID: string; // order number - paymentMethod: 'wechat' | 'stripe'; - service: { - quota: number; // 额度 - }; - iat: number; // 签发日期 - exp: number; // 有效期 - amount: number; // 消费金额 -}; - export type LicensePayload = { uid: string; amount: number; - token: string; orderID: string; quota: number; paymentMethod: 'wechat' | 'stripe'; diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index 39da16ff047..872bd1d3a92 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -8,19 +8,32 @@ export enum PaymentStatus { } export type PaymentParams = { - // appID: number; - // sign: string; amount: string; - currency: string; - // user: string; + currency: 'CNY'; payMethod: 'stripe' | 'wechat'; }; -export type PaymentRequest = { - appID: number; - sign: string; +export type StripePaymentData = { + amount: string; + currency: string; + message: string; orderID: string; - payMethod: string; - user: string; sessionID: string; + user: string; +}; + +export type WechatPaymentData = { + amount: string; + codeURL: string; + currency: string; + message: string; + orderID: string; + tradeNO: string; + user: string; +}; + +export type PaymentResultParams = { + orderID: string; + payMethod: 'stripe' | 'wechat'; + sessionID?: string; }; diff --git a/service/license/src/types/system.ts b/service/license/src/types/system.ts index a7064092aaf..03a95d3ce47 100644 --- a/service/license/src/types/system.ts +++ b/service/license/src/types/system.ts @@ -25,4 +25,5 @@ export type SystemEnv = { SEALOS_CLOUD_DOMAIN: string; stripeEnabled: boolean; wechatEnabledRecharge: boolean; + stripePub: string; } & LoginProps; diff --git a/service/license/src/utils/tools.ts b/service/license/src/utils/tools.ts index d76567495c6..d308ca021e7 100644 --- a/service/license/src/utils/tools.ts +++ b/service/license/src/utils/tools.ts @@ -48,6 +48,7 @@ export const getFavorable = if (ratios.length > step && step > -1) ratio = [...ratios].reverse()[step]; return Math.floor((amount * ratio) / 100); }; + export const retrySerially = (fn: () => Promise, times: number) => new Promise((res, rej) => { let retries = 0; @@ -64,3 +65,15 @@ export const retrySerially = (fn: () => Promise, times: number) => }; attempt(); }); + +// Base64 编码函数 +export function base64Encode(str: string) { + const encodedBuffer = Buffer.from(str, 'binary').toString('base64'); + return encodedBuffer; +} + +// Base64 解码函数 +export function base64Decode(str: string) { + const decodedBuffer = Buffer.from(str, 'base64').toString('binary'); + return decodedBuffer; +} From 180f4675814f28a1f15e0c316e4cd3b869b4e6c9 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Fri, 20 Oct 2023 12:58:50 +0800 Subject: [PATCH 05/17] done Signed-off-by: jingyang <3161362058@qq.com> --- service/license/.prettierrc.js | 2 +- service/license/next-i18next.config.js | 2 +- service/license/next.config.js | 2 +- service/license/package.json | 3 +- service/license/pnpm-lock.yaml | 447 +++++++++++++++--- service/license/public/images/bg.svg | 152 ++++++ service/license/public/images/pay_wechat.svg | 1 + service/license/src/api/license.ts | 4 +- service/license/src/api/payment.ts | 8 +- .../src/components/icons/CodeDoneIcon.tsx | 4 +- .../components/icons/DownloadIcon copy 3.tsx | 4 +- .../src/components/icons/DownloadIcon.tsx | 4 +- .../src/components/icons/ExchangeIcon.tsx | 4 +- .../src/components/icons/GithubIcon.tsx | 4 +- .../src/components/icons/GoogleIcon.tsx | 4 +- .../license/src/components/icons/GroupAdd.tsx | 4 +- .../src/components/icons/LicenseIcon.tsx | 13 +- .../src/components/icons/RightArrow.tsx | 4 +- .../src/components/icons/TokenIcon.tsx | 10 +- .../src/components/icons/WechatIcon.tsx | 4 +- .../license/src/components/signin/index.tsx | 12 +- service/license/src/hooks/useBonusBox.tsx | 5 +- .../pages/api/license/createLicenseRecord.ts | 4 +- .../src/pages/api/payment/checkWechat.ts | 46 ++ .../license/src/pages/api/payment/create.ts | 59 ++- .../license/src/pages/api/payment/result.ts | 79 +++- service/license/src/pages/api/price/bonus.ts | 4 +- .../src/pages/license/components/Recharge.tsx | 166 +++---- .../src/pages/license/components/Record.tsx | 16 +- .../license/components/WechatPayment.tsx | 2 +- service/license/src/pages/license/index.tsx | 52 +- service/license/src/pages/signin.tsx | 1 + .../src/services/backend/db/license.ts | 33 +- .../src/services/backend/db/payment.ts | 107 +++++ service/license/src/stores/payment.ts | 19 + service/license/src/types/license.ts | 40 +- service/license/src/types/payment.ts | 41 +- service/license/src/types/session.ts | 2 +- service/license/src/utils/format.ts | 54 --- service/license/src/utils/tools.ts | 25 +- service/license/tsconfig.json | 22 +- 41 files changed, 1089 insertions(+), 380 deletions(-) create mode 100644 service/license/public/images/bg.svg create mode 100644 service/license/public/images/pay_wechat.svg create mode 100644 service/license/src/pages/api/payment/checkWechat.ts create mode 100644 service/license/src/services/backend/db/payment.ts create mode 100644 service/license/src/stores/payment.ts delete mode 100644 service/license/src/utils/format.ts diff --git a/service/license/.prettierrc.js b/service/license/.prettierrc.js index 8bc336a3674..b48f2c3caef 100644 --- a/service/license/.prettierrc.js +++ b/service/license/.prettierrc.js @@ -17,4 +17,4 @@ module.exports = { proseWrap: 'preserve', htmlWhitespaceSensitivity: 'css', endOfLine: 'lf' -}; +} diff --git a/service/license/next-i18next.config.js b/service/license/next-i18next.config.js index 14df1ec905a..f13f0dbdba2 100644 --- a/service/license/next-i18next.config.js +++ b/service/license/next-i18next.config.js @@ -4,7 +4,7 @@ module.exports = { i18n: { - defaultLocale: 'en', + defaultLocale: 'zh', locales: ['en', 'zh'], localeDetection: false } diff --git a/service/license/next.config.js b/service/license/next.config.js index d3a20495ae0..16b8755ea21 100644 --- a/service/license/next.config.js +++ b/service/license/next.config.js @@ -7,7 +7,7 @@ const nextConfig = { i18n, reactStrictMode: false, swcMinify: isProduction, - output: 'standalone', + output: 'standalone' } module.exports = nextConfig diff --git a/service/license/package.json b/service/license/package.json index ed0a9384efa..1f02920e489 100644 --- a/service/license/package.json +++ b/service/license/package.json @@ -27,7 +27,7 @@ "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "mongodb": "^6.1.0", - "next": "13.5.5", + "next": "13.5.6", "next-i18next": "^14.0.3", "nprogress": "^0.2.0", "qrcode.react": "^3.1.0", @@ -35,6 +35,7 @@ "react-dom": "^18", "react-hook-form": "^7.47.0", "react-i18next": "^13.3.0", + "sharp": "^0.32.6", "uuid": "^9.0.1", "zustand": "^4.4.3" }, diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml index bf342891b07..6ae20149140 100644 --- a/service/license/pnpm-lock.yaml +++ b/service/license/pnpm-lock.yaml @@ -60,11 +60,11 @@ dependencies: specifier: ^6.1.0 version: registry.npmmirror.com/mongodb@6.1.0 next: - specifier: 13.5.5 - version: registry.npmmirror.com/next@13.5.5(react-dom@18.0.0)(react@18.0.0) + specifier: 13.5.6 + version: registry.npmmirror.com/next@13.5.6(react-dom@18.0.0)(react@18.0.0) next-i18next: specifier: ^14.0.3 - version: registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.5)(react-i18next@13.3.0)(react@18.0.0) + version: registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.6)(react-i18next@13.3.0)(react@18.0.0) nprogress: specifier: ^0.2.0 version: registry.npmmirror.com/nprogress@0.2.0 @@ -83,6 +83,9 @@ dependencies: react-i18next: specifier: ^13.3.0 version: registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0) + sharp: + specifier: ^0.32.6 + version: registry.npmmirror.com/sharp@0.32.6 uuid: specifier: ^9.0.1 version: registry.npmmirror.com/uuid@9.0.1 @@ -1856,10 +1859,10 @@ packages: sparse-bitfield: registry.npmmirror.com/sparse-bitfield@3.0.3 dev: false - registry.npmmirror.com/@next/env@13.5.5: - resolution: {integrity: sha512-agvIhYWp+ilbScg81s/sLueZo8CNEYLjNOqhISxheLmD/AQI4/VxV7bV76i/KzxH4iHy/va0YS9z0AOwGnw4Fg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/env/-/env-13.5.5.tgz} + registry.npmmirror.com/@next/env@13.5.6: + resolution: {integrity: sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/env/-/env-13.5.6.tgz} name: '@next/env' - version: 13.5.5 + version: 13.5.6 dev: false registry.npmmirror.com/@next/eslint-plugin-next@13.5.4: @@ -1870,10 +1873,10 @@ packages: glob: registry.npmmirror.com/glob@7.1.7 dev: true - registry.npmmirror.com/@next/swc-darwin-arm64@13.5.5: - resolution: {integrity: sha512-FvTdcJdTA7H1FGY8dKPPbf/O0oDC041/znHZwXA7liiGUhgw5hOQ+9z8tWvuz0M5a/SDjY/IRPBAb5FIFogYww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.5.tgz} + registry.npmmirror.com/@next/swc-darwin-arm64@13.5.6: + resolution: {integrity: sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz} name: '@next/swc-darwin-arm64' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -1881,10 +1884,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-darwin-x64@13.5.5: - resolution: {integrity: sha512-mTqNIecaojmyia7appVO2QggBe1Z2fdzxgn6jb3x9qlAk8yY2sy4MAcsj71kC9RlenCqDmr9vtC/ESFf110TPA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.5.tgz} + registry.npmmirror.com/@next/swc-darwin-x64@13.5.6: + resolution: {integrity: sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz} name: '@next/swc-darwin-x64' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -1892,10 +1895,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.5: - resolution: {integrity: sha512-U9e+kNkfvwh/T8yo+xcslvNXgyMzPPX1IbwCwnHHFmX5ckb1Uc3XZSInNjFQEQR5xhJpB5sFdal+IiBIiLYkZA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.5.tgz} + registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.6: + resolution: {integrity: sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz} name: '@next/swc-linux-arm64-gnu' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1904,10 +1907,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.5: - resolution: {integrity: sha512-h7b58eIoNCSmKVC5fr167U0HWZ/yGLbkKD9wIller0nGdyl5zfTji0SsPKJvrG8jvKPFt2xOkVBmXlFOtuKynw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.5.tgz} + registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.6: + resolution: {integrity: sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz} name: '@next/swc-linux-arm64-musl' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -1916,10 +1919,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.5: - resolution: {integrity: sha512-6U4y21T1J6FfcpM9uqzBJicxycpB5gJKLyQ3g6KOfBzT8H1sMwfHTRrvHKB09GIn1BCRy5YJHrA1G26DzqR46w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.5.tgz} + registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.6: + resolution: {integrity: sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz} name: '@next/swc-linux-x64-gnu' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1928,10 +1931,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.5: - resolution: {integrity: sha512-OuqWSAQHJQM2EsapPFTSU/FLQ0wKm7UeRNatiR/jLeCe1V02aB9xmzuWYo2Neaxxag4rss3S8fj+lvMLzwDaFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.5.tgz} + registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.6: + resolution: {integrity: sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz} name: '@next/swc-linux-x64-musl' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -1940,10 +1943,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.5: - resolution: {integrity: sha512-+yLrOZIIZDY4uGn9bLOc0wTgs+M8RuOUFSUK3BhmcLav9e+tcAj0jyBHD4aXv2qWhppUeuYMsyBo1I58/eE6Dg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.5.tgz} + registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.6: + resolution: {integrity: sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz} name: '@next/swc-win32-arm64-msvc' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -1951,10 +1954,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.5: - resolution: {integrity: sha512-SyMxXyJtf9ScMH0Dh87THJMXNFvfkRAk841xyW9SeOX3KxM1buXX3hN7vof4kMGk0Yg996OGsX+7C9ueS8ugsw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.5.tgz} + registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.6: + resolution: {integrity: sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz} name: '@next/swc-win32-ia32-msvc' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -1962,10 +1965,10 @@ packages: dev: false optional: true - registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.5: - resolution: {integrity: sha512-n5KVf2Ok0BbLwofAaHiiKf+BQCj1M8WmTujiER4/qzYAVngnsNSjqEWvJ03raeN9eURqxDO+yL5VRoDrR33H9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.5.tgz} + registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.6: + resolution: {integrity: sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz} name: '@next/swc-win32-x64-msvc' - version: 13.5.5 + version: 13.5.6 engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2501,6 +2504,12 @@ packages: dequal: registry.npmmirror.com/dequal@2.0.3 dev: true + registry.npmmirror.com/b4a@1.6.4: + resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/b4a/-/b4a-1.6.4.tgz} + name: b4a + version: 1.6.4 + dev: false + registry.npmmirror.com/babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz} name: babel-plugin-macros @@ -2518,6 +2527,22 @@ packages: version: 1.0.2 dev: true + registry.npmmirror.com/base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz} + name: base64-js + version: 1.5.1 + dev: false + + registry.npmmirror.com/bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz} + name: bl + version: 4.1.0 + dependencies: + buffer: registry.npmmirror.com/buffer@5.7.1 + inherits: registry.npmmirror.com/inherits@2.0.4 + readable-stream: registry.npmmirror.com/readable-stream@3.6.2 + dev: false + registry.npmmirror.com/brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz} name: brace-expansion @@ -2549,6 +2574,15 @@ packages: version: 1.0.1 dev: false + registry.npmmirror.com/buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz} + name: buffer + version: 5.7.1 + dependencies: + base64-js: registry.npmmirror.com/base64-js@1.5.1 + ieee754: registry.npmmirror.com/ieee754@1.2.1 + dev: false + registry.npmmirror.com/busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz} name: busboy @@ -2600,6 +2634,12 @@ packages: supports-color: registry.npmmirror.com/supports-color@7.2.0 dev: true + registry.npmmirror.com/chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz} + name: chownr + version: 1.1.4 + dev: false + registry.npmmirror.com/client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/client-only/-/client-only-0.0.1.tgz} name: client-only @@ -2628,7 +2668,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: registry.npmmirror.com/color-name@1.1.4 - dev: true registry.npmmirror.com/color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz} @@ -2640,7 +2679,15 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz} name: color-name version: 1.1.4 - dev: true + + registry.npmmirror.com/color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz} + name: color-string + version: 1.9.1 + dependencies: + color-name: registry.npmmirror.com/color-name@1.1.4 + simple-swizzle: registry.npmmirror.com/simple-swizzle@0.2.2 + dev: false registry.npmmirror.com/color2k@2.0.2: resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color2k/-/color2k-2.0.2.tgz} @@ -2648,6 +2695,16 @@ packages: version: 2.0.2 dev: false + registry.npmmirror.com/color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/color/-/color-4.2.3.tgz} + name: color + version: 4.2.3 + engines: {node: '>=12.5.0'} + dependencies: + color-convert: registry.npmmirror.com/color-convert@2.0.1 + color-string: registry.npmmirror.com/color-string@1.9.1 + dev: false + registry.npmmirror.com/combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz} name: combined-stream @@ -2765,6 +2822,22 @@ packages: dependencies: ms: registry.npmmirror.com/ms@2.1.2 + registry.npmmirror.com/decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz} + name: decompress-response + version: 6.0.0 + engines: {node: '>=10'} + dependencies: + mimic-response: registry.npmmirror.com/mimic-response@3.1.0 + dev: false + + registry.npmmirror.com/deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz} + name: deep-extend + version: 0.6.0 + engines: {node: '>=4.0.0'} + dev: false + registry.npmmirror.com/deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz} name: deep-is @@ -2807,6 +2880,13 @@ packages: engines: {node: '>=6'} dev: true + registry.npmmirror.com/detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/detect-libc/-/detect-libc-2.0.2.tgz} + name: detect-libc + version: 2.0.2 + engines: {node: '>=8'} + dev: false + registry.npmmirror.com/detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/detect-node-es/-/detect-node-es-1.1.0.tgz} name: detect-node-es @@ -2854,6 +2934,14 @@ packages: version: 9.2.2 dev: true + registry.npmmirror.com/end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz} + name: end-of-stream + version: 1.4.4 + dependencies: + once: registry.npmmirror.com/once@1.4.0 + dev: false + registry.npmmirror.com/enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz} name: enhanced-resolve @@ -3327,12 +3415,25 @@ packages: engines: {node: '>=0.10.0'} dev: true + registry.npmmirror.com/expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz} + name: expand-template + version: 2.0.3 + engines: {node: '>=6'} + dev: false + registry.npmmirror.com/fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz} name: fast-deep-equal version: 3.1.3 dev: true + registry.npmmirror.com/fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-fifo/-/fast-fifo-1.3.2.tgz} + name: fast-fifo + version: 1.3.2 + dev: false + registry.npmmirror.com/fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.1.tgz} name: fast-glob @@ -3476,6 +3577,12 @@ packages: tslib: registry.npmmirror.com/tslib@2.4.0 dev: false + registry.npmmirror.com/fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz} + name: fs-constants + version: 1.0.0 + dev: false + registry.npmmirror.com/fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz} name: fs.realpath @@ -3548,6 +3655,12 @@ packages: resolve-pkg-maps: registry.npmmirror.com/resolve-pkg-maps@1.0.0 dev: true + registry.npmmirror.com/github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz} + name: github-from-package + version: 0.0.0 + dev: false + registry.npmmirror.com/glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz} name: glob-parent @@ -3741,6 +3854,12 @@ packages: '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 dev: false + registry.npmmirror.com/ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz} + name: ieee754 + version: 1.2.1 + dev: false + registry.npmmirror.com/ignore@4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ignore/-/ignore-4.0.6.tgz} name: ignore @@ -3790,7 +3909,6 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz} name: inherits version: 2.0.4 - dev: true registry.npmmirror.com/ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz} @@ -3833,6 +3951,12 @@ packages: version: 0.2.1 dev: false + registry.npmmirror.com/is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz} + name: is-arrayish + version: 0.3.2 + dev: false + registry.npmmirror.com/is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-async-function/-/is-async-function-2.0.0.tgz} name: is-async-function @@ -4307,6 +4431,13 @@ packages: mime-db: registry.npmmirror.com/mime-db@1.52.0 dev: false + registry.npmmirror.com/mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz} + name: mimic-response + version: 3.1.0 + engines: {node: '>=10'} + dev: false + registry.npmmirror.com/minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz} name: minimatch @@ -4319,7 +4450,12 @@ packages: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz} name: minimist version: 1.2.8 - dev: true + + registry.npmmirror.com/mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz} + name: mkdirp-classic + version: 0.5.3 + dev: false registry.npmmirror.com/mongodb-connection-string-url@2.6.0: resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz} @@ -4382,13 +4518,19 @@ packages: hasBin: true dev: false + registry.npmmirror.com/napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz} + name: napi-build-utils + version: 1.0.2 + dev: false + registry.npmmirror.com/natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz} name: natural-compare version: 1.4.0 dev: true - registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.5)(react-i18next@13.3.0)(react@18.0.0): + registry.npmmirror.com/next-i18next@14.0.3(i18next@23.5.1)(next@13.5.6)(react-i18next@13.3.0)(react@18.0.0): resolution: {integrity: sha512-FtnjRMfhlamk8YyeyWqd+pndNL+3er83iMZnH4M4mhiGA93l0+vtBUvuObgOAMHDJGLLB2SS2xOOZq69oiJh7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next-i18next/-/next-i18next-14.0.3.tgz} id: registry.npmmirror.com/next-i18next/14.0.3 name: next-i18next @@ -4406,16 +4548,16 @@ packages: hoist-non-react-statics: registry.npmmirror.com/hoist-non-react-statics@3.3.2 i18next: registry.npmmirror.com/i18next@23.5.1 i18next-fs-backend: registry.npmmirror.com/i18next-fs-backend@2.2.0 - next: registry.npmmirror.com/next@13.5.5(react-dom@18.0.0)(react@18.0.0) + next: registry.npmmirror.com/next@13.5.6(react-dom@18.0.0)(react@18.0.0) react: registry.npmmirror.com/react@18.0.0 react-i18next: registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0) dev: false - registry.npmmirror.com/next@13.5.5(react-dom@18.0.0)(react@18.0.0): - resolution: {integrity: sha512-LddFJjpfrtrMMw8Q9VLhIURuSidiCNcMQjRqcPtrKd+Fx07MsG7hYndJb/f2d3I+mTbTotsTJfCnn0eZ/YPk8w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next/-/next-13.5.5.tgz} - id: registry.npmmirror.com/next/13.5.5 + registry.npmmirror.com/next@13.5.6(react-dom@18.0.0)(react@18.0.0): + resolution: {integrity: sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/next/-/next-13.5.6.tgz} + id: registry.npmmirror.com/next/13.5.6 name: next - version: 13.5.5 + version: 13.5.6 engines: {node: '>=16.14.0'} hasBin: true peerDependencies: @@ -4429,7 +4571,7 @@ packages: sass: optional: true dependencies: - '@next/env': registry.npmmirror.com/@next/env@13.5.5 + '@next/env': registry.npmmirror.com/@next/env@13.5.6 '@swc/helpers': registry.npmmirror.com/@swc/helpers@0.5.2 busboy: registry.npmmirror.com/busboy@1.6.0 caniuse-lite: registry.npmmirror.com/caniuse-lite@1.0.30001549 @@ -4439,20 +4581,35 @@ packages: styled-jsx: registry.npmmirror.com/styled-jsx@5.1.1(react@18.0.0) watchpack: registry.npmmirror.com/watchpack@2.4.0 optionalDependencies: - '@next/swc-darwin-arm64': registry.npmmirror.com/@next/swc-darwin-arm64@13.5.5 - '@next/swc-darwin-x64': registry.npmmirror.com/@next/swc-darwin-x64@13.5.5 - '@next/swc-linux-arm64-gnu': registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.5 - '@next/swc-linux-arm64-musl': registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.5 - '@next/swc-linux-x64-gnu': registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.5 - '@next/swc-linux-x64-musl': registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.5 - '@next/swc-win32-arm64-msvc': registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.5 - '@next/swc-win32-ia32-msvc': registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.5 - '@next/swc-win32-x64-msvc': registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.5 + '@next/swc-darwin-arm64': registry.npmmirror.com/@next/swc-darwin-arm64@13.5.6 + '@next/swc-darwin-x64': registry.npmmirror.com/@next/swc-darwin-x64@13.5.6 + '@next/swc-linux-arm64-gnu': registry.npmmirror.com/@next/swc-linux-arm64-gnu@13.5.6 + '@next/swc-linux-arm64-musl': registry.npmmirror.com/@next/swc-linux-arm64-musl@13.5.6 + '@next/swc-linux-x64-gnu': registry.npmmirror.com/@next/swc-linux-x64-gnu@13.5.6 + '@next/swc-linux-x64-musl': registry.npmmirror.com/@next/swc-linux-x64-musl@13.5.6 + '@next/swc-win32-arm64-msvc': registry.npmmirror.com/@next/swc-win32-arm64-msvc@13.5.6 + '@next/swc-win32-ia32-msvc': registry.npmmirror.com/@next/swc-win32-ia32-msvc@13.5.6 + '@next/swc-win32-x64-msvc': registry.npmmirror.com/@next/swc-win32-x64-msvc@13.5.6 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros dev: false + registry.npmmirror.com/node-abi@3.51.0: + resolution: {integrity: sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/node-abi/-/node-abi-3.51.0.tgz} + name: node-abi + version: 3.51.0 + engines: {node: '>=10'} + dependencies: + semver: registry.npmmirror.com/semver@7.5.4 + dev: false + + registry.npmmirror.com/node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/node-addon-api/-/node-addon-api-6.1.0.tgz} + name: node-addon-api + version: 6.1.0 + dev: false + registry.npmmirror.com/nprogress@0.2.0: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz} name: nprogress @@ -4549,7 +4706,6 @@ packages: version: 1.4.0 dependencies: wrappy: registry.npmmirror.com/wrappy@1.0.2 - dev: true registry.npmmirror.com/optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz} @@ -4634,6 +4790,27 @@ packages: source-map-js: registry.npmmirror.com/source-map-js@1.0.2 dev: false + registry.npmmirror.com/prebuild-install@7.1.1: + resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.1.tgz} + name: prebuild-install + version: 7.1.1 + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: registry.npmmirror.com/detect-libc@2.0.2 + expand-template: registry.npmmirror.com/expand-template@2.0.3 + github-from-package: registry.npmmirror.com/github-from-package@0.0.0 + minimist: registry.npmmirror.com/minimist@1.2.8 + mkdirp-classic: registry.npmmirror.com/mkdirp-classic@0.5.3 + napi-build-utils: registry.npmmirror.com/napi-build-utils@1.0.2 + node-abi: registry.npmmirror.com/node-abi@3.51.0 + pump: registry.npmmirror.com/pump@3.0.0 + rc: registry.npmmirror.com/rc@1.2.8 + simple-get: registry.npmmirror.com/simple-get@4.0.1 + tar-fs: registry.npmmirror.com/tar-fs@2.1.1 + tunnel-agent: registry.npmmirror.com/tunnel-agent@0.6.0 + dev: false + registry.npmmirror.com/prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz} name: prelude-ls @@ -4671,6 +4848,15 @@ packages: version: 1.1.0 dev: false + registry.npmmirror.com/pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz} + name: pump + version: 3.0.0 + dependencies: + end-of-stream: registry.npmmirror.com/end-of-stream@1.4.4 + once: registry.npmmirror.com/once@1.4.0 + dev: false + registry.npmmirror.com/punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz} name: punycode @@ -4694,6 +4880,24 @@ packages: version: 1.2.3 dev: true + registry.npmmirror.com/queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/queue-tick/-/queue-tick-1.0.1.tgz} + name: queue-tick + version: 1.0.1 + dev: false + + registry.npmmirror.com/rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz} + name: rc + version: 1.2.8 + hasBin: true + dependencies: + deep-extend: registry.npmmirror.com/deep-extend@0.6.0 + ini: registry.npmmirror.com/ini@1.3.8 + minimist: registry.npmmirror.com/minimist@1.2.8 + strip-json-comments: registry.npmmirror.com/strip-json-comments@2.0.1 + dev: false + registry.npmmirror.com/react-clientside-effect@1.2.6(react@18.0.0): resolution: {integrity: sha512-XGGGRQAKY+q25Lz9a/4EPqom7WRjz3z9R2k4jhVKA/puQFH/5Nt27vFZYql4m4NVNdUvX8PS3O7r/Zzm7cjUlg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz} id: registry.npmmirror.com/react-clientside-effect/1.2.6 @@ -4857,6 +5061,17 @@ packages: loose-envify: registry.npmmirror.com/loose-envify@1.4.0 dev: false + registry.npmmirror.com/readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz} + name: readable-stream + version: 3.6.2 + engines: {node: '>= 6'} + dependencies: + inherits: registry.npmmirror.com/inherits@2.0.4 + string_decoder: registry.npmmirror.com/string_decoder@1.3.0 + util-deprecate: registry.npmmirror.com/util-deprecate@1.0.2 + dev: false + registry.npmmirror.com/reflect.getprototypeof@1.0.4: resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz} name: reflect.getprototypeof @@ -5020,6 +5235,23 @@ packages: has-property-descriptors: registry.npmmirror.com/has-property-descriptors@1.0.0 dev: true + registry.npmmirror.com/sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sharp/-/sharp-0.32.6.tgz} + name: sharp + version: 0.32.6 + engines: {node: '>=14.15.0'} + requiresBuild: true + dependencies: + color: registry.npmmirror.com/color@4.2.3 + detect-libc: registry.npmmirror.com/detect-libc@2.0.2 + node-addon-api: registry.npmmirror.com/node-addon-api@6.1.0 + prebuild-install: registry.npmmirror.com/prebuild-install@7.1.1 + semver: registry.npmmirror.com/semver@7.5.4 + simple-get: registry.npmmirror.com/simple-get@4.0.1 + tar-fs: registry.npmmirror.com/tar-fs@3.0.4 + tunnel-agent: registry.npmmirror.com/tunnel-agent@0.6.0 + dev: false + registry.npmmirror.com/shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz} name: shebang-command @@ -5046,6 +5278,30 @@ packages: object-inspect: registry.npmmirror.com/object-inspect@1.12.3 dev: true + registry.npmmirror.com/simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz} + name: simple-concat + version: 1.0.1 + dev: false + + registry.npmmirror.com/simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz} + name: simple-get + version: 4.0.1 + dependencies: + decompress-response: registry.npmmirror.com/decompress-response@6.0.0 + once: registry.npmmirror.com/once@1.4.0 + simple-concat: registry.npmmirror.com/simple-concat@1.0.1 + dev: false + + registry.npmmirror.com/simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz} + name: simple-swizzle + version: 0.2.2 + dependencies: + is-arrayish: registry.npmmirror.com/is-arrayish@0.3.2 + dev: false + registry.npmmirror.com/slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz} name: slash @@ -5088,6 +5344,15 @@ packages: engines: {node: '>=10.0.0'} dev: false + registry.npmmirror.com/streamx@2.15.1: + resolution: {integrity: sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/streamx/-/streamx-2.15.1.tgz} + name: streamx + version: 2.15.1 + dependencies: + fast-fifo: registry.npmmirror.com/fast-fifo@1.3.2 + queue-tick: registry.npmmirror.com/queue-tick@1.0.1 + dev: false + registry.npmmirror.com/string.prototype.matchall@4.0.10: resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz} name: string.prototype.matchall @@ -5135,6 +5400,14 @@ packages: es-abstract: registry.npmmirror.com/es-abstract@1.22.2 dev: true + registry.npmmirror.com/string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz} + name: string_decoder + version: 1.3.0 + dependencies: + safe-buffer: registry.npmmirror.com/safe-buffer@5.2.1 + dev: false + registry.npmmirror.com/strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz} name: strip-ansi @@ -5151,6 +5424,13 @@ packages: engines: {node: '>=4'} dev: true + registry.npmmirror.com/strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz} + name: strip-json-comments + version: 2.0.1 + engines: {node: '>=0.10.0'} + dev: false + registry.npmmirror.com/strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz} name: strip-json-comments @@ -5215,6 +5495,50 @@ packages: engines: {node: '>=6'} dev: true + registry.npmmirror.com/tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.1.tgz} + name: tar-fs + version: 2.1.1 + dependencies: + chownr: registry.npmmirror.com/chownr@1.1.4 + mkdirp-classic: registry.npmmirror.com/mkdirp-classic@0.5.3 + pump: registry.npmmirror.com/pump@3.0.0 + tar-stream: registry.npmmirror.com/tar-stream@2.2.0 + dev: false + + registry.npmmirror.com/tar-fs@3.0.4: + resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tar-fs/-/tar-fs-3.0.4.tgz} + name: tar-fs + version: 3.0.4 + dependencies: + mkdirp-classic: registry.npmmirror.com/mkdirp-classic@0.5.3 + pump: registry.npmmirror.com/pump@3.0.0 + tar-stream: registry.npmmirror.com/tar-stream@3.1.6 + dev: false + + registry.npmmirror.com/tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz} + name: tar-stream + version: 2.2.0 + engines: {node: '>=6'} + dependencies: + bl: registry.npmmirror.com/bl@4.1.0 + end-of-stream: registry.npmmirror.com/end-of-stream@1.4.4 + fs-constants: registry.npmmirror.com/fs-constants@1.0.0 + inherits: registry.npmmirror.com/inherits@2.0.4 + readable-stream: registry.npmmirror.com/readable-stream@3.6.2 + dev: false + + registry.npmmirror.com/tar-stream@3.1.6: + resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tar-stream/-/tar-stream-3.1.6.tgz} + name: tar-stream + version: 3.1.6 + dependencies: + b4a: registry.npmmirror.com/b4a@1.6.4 + fast-fifo: registry.npmmirror.com/fast-fifo@1.3.2 + streamx: registry.npmmirror.com/streamx@2.15.1 + dev: false + registry.npmmirror.com/text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz} name: text-table @@ -5293,6 +5617,14 @@ packages: version: 2.6.2 dev: false + registry.npmmirror.com/tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz} + name: tunnel-agent + version: 0.6.0 + dependencies: + safe-buffer: registry.npmmirror.com/safe-buffer@5.2.1 + dev: false + registry.npmmirror.com/type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz} name: type-check @@ -5430,6 +5762,12 @@ packages: react: registry.npmmirror.com/react@18.0.0 dev: false + registry.npmmirror.com/util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz} + name: util-deprecate + version: 1.0.2 + dev: false + registry.npmmirror.com/uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz} name: uuid @@ -5547,7 +5885,6 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz} name: wrappy version: 1.0.2 - dev: true registry.npmmirror.com/xml2js@0.4.23: resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xml2js/-/xml2js-0.4.23.tgz} diff --git a/service/license/public/images/bg.svg b/service/license/public/images/bg.svg new file mode 100644 index 00000000000..8d9fcec31aa --- /dev/null +++ b/service/license/public/images/bg.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/license/public/images/pay_wechat.svg b/service/license/public/images/pay_wechat.svg new file mode 100644 index 00000000000..ecab7b8e6a8 --- /dev/null +++ b/service/license/public/images/pay_wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/service/license/src/api/license.ts b/service/license/src/api/license.ts index 38ffcc8f641..a711c717633 100644 --- a/service/license/src/api/license.ts +++ b/service/license/src/api/license.ts @@ -1,11 +1,11 @@ import { GET, POST } from '@/services/request'; -import { LicensePayload, LicenseRecord } from '@/types'; +import { LicensePayload, LicenseDB } from '@/types'; export const createLicenseRecord = (payload: LicensePayload) => POST('/api/license/createLicenseRecord', payload); export const getLicenseRecord = ({ page, pageSize }: { page: number; pageSize: number }) => - POST<{ total: number; records: LicenseRecord[] }>('/api/license/getLicenseRecord', { + POST<{ total: number; records: LicenseDB[] }>('/api/license/getLicenseRecord', { page, pageSize }); diff --git a/service/license/src/api/payment.ts b/service/license/src/api/payment.ts index de7a7e63001..2f33455650a 100644 --- a/service/license/src/api/payment.ts +++ b/service/license/src/api/payment.ts @@ -1,8 +1,8 @@ import { GET, POST } from '@/services/request'; -import { PaymentParams, PaymentResultParams, StripePaymentData, WechatPaymentData } from '@/types'; +import { PaymentData, PaymentParams, PaymentResult } from '@/types'; export const createPayment = (payload: PaymentParams) => - POST('/api/payment/create', payload); + POST('/api/payment/create', payload); -export const getPaymentResult = (payload: PaymentResultParams) => - POST('/api/payment/result', payload); +export const getPaymentResult = (payload: { orderID: string }) => + POST('/api/payment/result', payload); diff --git a/service/license/src/components/icons/CodeDoneIcon.tsx b/service/license/src/components/icons/CodeDoneIcon.tsx index efc1e958cb3..73de6a609e8 100644 --- a/service/license/src/components/icons/CodeDoneIcon.tsx +++ b/service/license/src/components/icons/CodeDoneIcon.tsx @@ -3,8 +3,8 @@ export const CodeDoneIcon = (props: IconProps) => { return ( diff --git a/service/license/src/components/icons/DownloadIcon copy 3.tsx b/service/license/src/components/icons/DownloadIcon copy 3.tsx index b37347364f8..78e3450c4c1 100644 --- a/service/license/src/components/icons/DownloadIcon copy 3.tsx +++ b/service/license/src/components/icons/DownloadIcon copy 3.tsx @@ -2,8 +2,8 @@ import { Icon, IconProps } from '@chakra-ui/react'; export const DownloadIcon = (props: IconProps) => { return ( { return ( { return ( { return ( { return ( { return ( { return ( - - + + ); }; diff --git a/service/license/src/components/icons/RightArrow.tsx b/service/license/src/components/icons/RightArrow.tsx index 5ccebc75a93..8abf3edb39d 100644 --- a/service/license/src/components/icons/RightArrow.tsx +++ b/service/license/src/components/icons/RightArrow.tsx @@ -3,8 +3,8 @@ import { Icon, IconProps } from '@chakra-ui/react'; export const RightIcon = (props: IconProps) => { return ( { return ( - - + + { return ( sealos Cloud @@ -118,7 +125,8 @@ export default function SigninComponent() { { return { ratios: (bonuses?.ratios || '').split(',').map((v) => +v), - steps: (bonuses?.steps || '').split(',').map((v) => +v) + steps: (bonuses?.steps || '') + .split(',') + .map((v) => +v) + .concat([1]) }; }, [bonuses]); diff --git a/service/license/src/pages/api/license/createLicenseRecord.ts b/service/license/src/pages/api/license/createLicenseRecord.ts index 2d19826440c..13d55dafa27 100644 --- a/service/license/src/pages/api/license/createLicenseRecord.ts +++ b/service/license/src/pages/api/license/createLicenseRecord.ts @@ -9,7 +9,7 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse const payload = await authSession(req.headers); if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); - const { orderID, amount, quota, paymentMethod } = req.body as LicensePayload; + const { orderID, amount, quota, payMethod } = req.body as LicensePayload; const _token = generateLicenseToken({ type: 'Account', data: { amount: quota } }); @@ -19,7 +19,7 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse token: _token, orderID: orderID, quota: quota, - paymentMethod: paymentMethod + payMethod: payMethod }; const result = await createLicenseRecord(record); diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts new file mode 100644 index 00000000000..b462272d9ce --- /dev/null +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -0,0 +1,46 @@ +import { authSession } from '@/services/backend/auth'; +import { createLicenseRecord, generateLicenseToken } from '@/services/backend/db/license'; +import { getPaymentByID, updatePaymentStatus } from '@/services/backend/db/payment'; +import { jsonRes } from '@/services/backend/response'; +import { getSealosPay } from '@/services/pay'; +import { PaymentResult, PaymentStatus } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { orderID } = req.body as { orderID: string }; + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(res, { code: 401, message: 'token verify error' }); + } + const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); + if (!sealosPayUrl) { + return jsonRes(res, { code: 500, message: 'sealos payment has not been activated' }); + } + + const payment = await getPaymentByID({ uid: userInfo.uid, orderID: orderID }); + if (!payment) { + return jsonRes(res, { code: 400, message: 'No order found' }); + } + + const result: PaymentResult = await fetch(`${sealosPayUrl}/v1alpha1/pay/status`, { + method: 'POST', + body: JSON.stringify({ + appID: 45141910007488120, + sign: '076f82f8e996d7', + orderID: payment?.orderID, + payMethod: payment?.payMethod, + tradeNO: payment?.tradeNO, + user: userInfo.uid, + sessionID: payment?.sessionID + }) + }).then((res) => res.json()); + + return jsonRes(res, { + data: result + }); + } catch (error) { + console.error(error, '===payment error===\n'); + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/payment/create.ts b/service/license/src/pages/api/payment/create.ts index 0ac304df499..e3811c2b041 100644 --- a/service/license/src/pages/api/payment/create.ts +++ b/service/license/src/pages/api/payment/create.ts @@ -1,51 +1,50 @@ -import { authSession, verifyJWT } from '@/services/backend/auth'; -import { generateLicenseToken } from '@/services/backend/db/license'; +import { authSession } from '@/services/backend/auth'; +import { createPaymentRecord } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; -import { PaymentParams } from '@/types'; +import { PaymentDB, PaymentData, PaymentParams, PaymentStatus } from '@/types'; +import { formatMoney } from '@/utils/tools'; import type { NextApiRequest, NextApiResponse } from 'next'; -import { sign, verify } from 'jsonwebtoken'; -import { base64Decode } from '@/utils/tools'; -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { +export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { amount, currency = 'CNY', payMethod = 'wechat' } = req.body as PaymentParams; + const { amount, currency, payMethod } = req.body as PaymentParams; const userInfo = await authSession(req.headers); - if (!userInfo) { - return jsonRes(resp, { code: 401, message: 'token verify error' }); - } + if (!userInfo) return jsonRes(res, { code: 401, message: 'token verify error' }); const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); + if (!sealosPayUrl) + return jsonRes(res, { code: 500, message: 'sealos payment has not been activated' }); - const result = await fetch(`${sealosPayUrl}/v1alpha1/pay/session`, { + const result: PaymentData = await fetch(`${sealosPayUrl}/v1alpha1/pay/session`, { method: 'POST', body: JSON.stringify({ - appID: +sealosPayID, - sign: sealosPayKey, - amount: '1688', - currency: 'CNY', - user: 'jiahui', + appID: 45141910007488120, + sign: '076f82f8e996d7', + amount: amount, + currency: currency, + user: userInfo.uid, payMethod: payMethod }) }).then((res) => res.json()); - // const res = generateLicenseToken({ type: 'Account', data: { amount: 19999 } }); - // console.log(res); - // verify( - // res, - // base64Decode( - // 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFvbFBTSzB0UjFKeDZtb25lL2ppeApSWGN6UGlxcU5SSXRmdW1mdWNyNGMxc2dqdlJha0NwcWtDU21lMTR1akJkU0x6QlZzRjkvUWl0UnFNb2NvaEN1CkJ6R25EQ29hWnZXbWVHeE96NEZSejVTeUg1QTlDa3dnbUEzYnFnMWxKSEZTMlZyVjVHVFhFWnphZTZtRmhHOVcKenJMTnpZMlptYTMzOVE1WTNJSDZ6RXIrcTRQbTZDOXBHVGpsSnVodlRvb0dSY2w0bmpZRXc2eHB6ZHZrdi9uSApmZmxsWGZVNDNyRGdQaGkwZDRjWnNuTUJlazUxQkNiRFRuSHlNVFdGT1RoTjc1VVM0bzJxRm9JSEhsM0N0RzE4ClZIZEdRSE1IR0dYcGN3bVhhck1EQndwVWFOSk9kMkhjTTB5dlZEY2xDZzRITkIwVUFWeFNweFlRV3BwNWJzN2gKbHdJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==' - // ), - // function (err, decoded) { - // console.log(decoded); - // } - // ); + let payRecord: PaymentDB = { + ...result, + uid: userInfo.uid, + status: PaymentStatus.PaymentNotPaid, + amount: formatMoney(parseInt(result.amount)), + createdAt: new Date(), + updatedAt: new Date(), + payMethod: payMethod + }; - return jsonRes(resp, { + await createPaymentRecord(payRecord); + + return jsonRes(res, { data: result }); } catch (error) { - console.log(error); - jsonRes(resp, { code: 500, data: error }); + console.error(error); + jsonRes(res, { code: 500, data: error }); } } diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts index 8ad9354b373..f31876b902f 100644 --- a/service/license/src/pages/api/payment/result.ts +++ b/service/license/src/pages/api/payment/result.ts @@ -1,34 +1,85 @@ import { authSession } from '@/services/backend/auth'; +import { + createLicenseRecord, + generateLicenseToken, + hasIssuedLicense +} from '@/services/backend/db/license'; +import { getPaymentByID, updatePaymentStatus } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; -import { PaymentParams, PaymentResultParams } from '@/types'; +import { PaymentResult, PaymentStatus } from '@/types'; import type { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { +export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { payMethod, sessionID, orderID } = req.body as PaymentResultParams; - const userInfo = await authSession(req.headers); - if (!userInfo) return jsonRes(resp, { code: 401, message: 'token verify error' }); + // test + // const _token = generateLicenseToken({ type: 'Account', data: { amount: 299 } }); + const { orderID } = req.body as { orderID: string }; + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(res, { code: 401, message: 'token verify error' }); + } const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); + if (!sealosPayUrl) { + return jsonRes(res, { code: 500, message: 'sealos payment has not been activated' }); + } + + const payment = await getPaymentByID({ uid: userInfo.uid, orderID: orderID }); + console.log(payment); - const result = await fetch(`${sealosPayUrl}/v1alpha1/pay/status`, { + if (!payment) { + return jsonRes(res, { code: 400, message: 'No order found' }); + } + const issuedLicense = await hasIssuedLicense({ uid: userInfo.uid, orderID: orderID }); + if (issuedLicense) { + return jsonRes(res, { code: 400, message: 'orderID cannot be reused' }); + } + + const result: PaymentResult = await fetch(`${sealosPayUrl}/v1alpha1/pay/status`, { method: 'POST', body: JSON.stringify({ appID: 45141910007488120, sign: '076f82f8e996d7', - orderID: orderID, - payMethod: 'stripe', - user: 'jiahui', - sessionID: 'cs_test_a1UH60aWlJpnbi6c1LA287ymXv0mWDYdT6oonpRduTs9zzSF6OU87WSXa2' + orderID: payment?.orderID, + payMethod: payment?.payMethod, + tradeNO: payment?.tradeNO, + user: userInfo.uid, + sessionID: payment?.sessionID }) - }); + }).then((res) => res.json()); + + if (result.status === PaymentStatus.PaymentSuccess) { + await updatePaymentStatus({ + uid: userInfo.uid, + orderID: orderID, + status: result.status + }); + const _token = generateLicenseToken({ type: 'Account', data: { amount: payment.amount } }); + const record = { + uid: userInfo.uid, + amount: payment.amount, + token: _token, + orderID: orderID, + quota: payment.amount, + payMethod: payment.payMethod + }; + await createLicenseRecord(record); + } + + if (result.status === PaymentStatus.PaymentProcessing) { + await updatePaymentStatus({ + uid: userInfo.uid, + orderID: orderID, + status: result.status + }); + } - return jsonRes(resp, { + return jsonRes(res, { data: result }); } catch (error) { - console.log(error); - jsonRes(resp, { code: 500, data: error }); + console.error(error, '===payment error===\n'); + jsonRes(res, { code: 500, data: error }); } } diff --git a/service/license/src/pages/api/price/bonus.ts b/service/license/src/pages/api/price/bonus.ts index 8e3369d77df..eb6d131455b 100644 --- a/service/license/src/pages/api/price/bonus.ts +++ b/service/license/src/pages/api/price/bonus.ts @@ -8,13 +8,13 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse if (!payload) { return jsonRes(resp, { code: 401, message: 'token verify error' }); } - return jsonRes(resp, { code: 200, data: { ratios: '10,15,20,25,30', steps: '299,599,1999,4999,19999' - } + }, + message: 'asdasdasdasd' }); } catch (error) { console.log(error); diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index dca5e3efdd9..27d632b809a 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -1,9 +1,9 @@ -import { createLicenseRecord } from '@/api/license'; +import { createPayment, getPaymentResult } from '@/api/payment'; import { getSystemEnv } from '@/api/system'; import { StripeIcon, WechatIcon } from '@/components/icons'; import useBonusBox from '@/hooks/useBonusBox'; -import { LicensePayload, StripePaymentData } from '@/types'; -import { deFormatMoney } from '@/utils/format'; +import { PaymentStatus, TPayMethod, WechatPaymentData } from '@/types'; +import { deFormatMoney } from '@/utils/tools'; import { Button, Checkbox, @@ -18,61 +18,56 @@ import { useDisclosure, useToast } from '@chakra-ui/react'; +import { loadStripe } from '@stripe/stripe-js'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; -import { useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import WechatPayment from './WechatPayment'; -import { createPayment, getPaymentResult } from '@/api/payment'; -import { loadStripe } from '@stripe/stripe-js'; export default function RechargeComponent() { - const { t } = useTranslation(); + const router = useRouter(); const queryClient = useQueryClient(); - const [isAgree, setIsAgree] = useState(false); + const toast = useToast({ position: 'top', duration: 2000 }); + const { t } = useTranslation(); + const [isAgree, setIsAgree] = useState(true); const [isInvalid, setIsInvalid] = useState(false); const { BonusBox, selectAmount } = useBonusBox(); const { isOpen, onOpen, onClose } = useDisclosure(); // 整个流程跑通需要状态管理, 0 初始态, 1 创建支付单, 2 支付中, 3 支付成功 const [complete, setComplete] = useState<0 | 1 | 2 | 3>(0); - // 0 是微信,1 是stripe - const [payType, setPayType] = useState<'wechat' | 'stripe'>('wechat'); - const [paymentName, setPaymentName] = useState(''); - const toast = useToast({ position: 'top', duration: 2000 }); + const [payType, setPayType] = useState('wechat'); + const [orderID, setOrderID] = useState(''); + const [wechatPaymentData, setWechatPaymentData] = useState(); const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); - console.log(selectAmount, '11111'); - - const onModalClose = () => { + const onClosePayment = useCallback(() => { + setOrderID(''); setComplete(0); onClose(); - }; + }, [onClose]); - const handleStripeConfirm = () => { - setPayType('stripe'); - if (selectAmount < 10) { + const handlePayConfirm = (type: TPayMethod) => { + setPayType(type); + if (!isAgree) { return toast({ - status: 'error', - title: t('Pay Minimum Tips') - }); - } - setComplete(1); - paymentMutation.mutate(); - }; - - const handleWechatConfirm = () => { - if (isAgree) { - setComplete(1); - paymentMutation.mutate(); - onOpen(); - } else { - toast({ status: 'error', title: t('Please read and agree to the agreement'), isClosable: true, position: 'top' }); } + if (type === 'stripe' && selectAmount < 10) { + return toast({ + status: 'error', + title: t('Pay Minimum Tips') + }); + } + if (type === 'wechat') { + onOpen(); + } + setComplete(1); + paymentMutation.mutate(); }; const paymentMutation = useMutation( @@ -84,16 +79,18 @@ export default function RechargeComponent() { }), { async onSuccess(data) { - console.log(data, '======='); - if (payType === 'stripe' && platformEnv?.stripePub && data?.sessionID) { + // setPaymentData({ ...data, payMethod: payType }); + if (payType === 'stripe' && platformEnv && data?.sessionID) { const stripe = await loadStripe(platformEnv?.stripePub); stripe?.redirectToCheckout({ sessionId: data.sessionID }); - } else if (payType === 'wechat') { } - // setPaymentName((data?.paymentName as string).trim()); - setComplete(2); + if (payType === 'wechat' && data?.tradeNO && data?.codeURL) { + setOrderID(data.orderID); + setWechatPaymentData({ tradeNO: data?.tradeNO, codeURL: data?.codeURL }); + setComplete(2); + } }, onError(err: any) { toast({ @@ -107,55 +104,56 @@ export default function RechargeComponent() { } ); - const licenseRecordMutation = useMutation( - (payload: LicensePayload) => createLicenseRecord(payload), - { - onSuccess(data) { - console.log(data); + useQuery(['getLicenseResult', orderID], () => getPaymentResult({ orderID }), { + refetchInterval: complete === 2 ? 3 * 1000 : false, + enabled: complete === 2 && orderID !== undefined, + cacheTime: 0, + staleTime: 0, + onSuccess(data) { + console.log(data, 'xxxxxxxx'); + if (data.status === PaymentStatus.PaymentSuccess) { + onClosePayment(); + toast({ + status: 'success', + title: t('Payment Successful'), // 这里改为license 签发成功 + isClosable: true, + position: 'top' + }); queryClient.invalidateQueries(['getLicenseActive']); - }, - onError(err: any) { - console.log(err); } + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); } - ); + }); - const { data } = useQuery( - ['getLicenseResult', paymentName], - () => getPaymentResult({ orderID }), - { - refetchInterval: complete === 2 ? 1000 : false, - enabled: complete === 2 && !!paymentName, - cacheTime: 0, - staleTime: 0, - onSuccess(data) { - console.log(data); - if (data?.status === 'Completed') { - onModalClose(); - toast({ - status: 'success', - title: t('Payment Successful'), - isClosable: true, - position: 'top' - }); - // licenseRecordMutation.mutate({ - // uid: '', - // amount: deFormatMoney(selectAmount), - // quota: selectAmount, - // token: data?.token, - // orderID: data?.tradeNO, - // paymentMethod: 'wechat' - // }); - } - } + useEffect(() => { + const { stripeState, orderID } = router.query; + if (stripeState === 'success') { + setComplete(2); + setOrderID(orderID as string); + } else if (stripeState === 'error') { + toast({ + status: 'error', + duration: 3000, + title: t('Stripe Cancel'), + isClosable: true, + position: 'top' + }); + onClosePayment(); } - ); + }, [onClosePayment, router.query, t, toast]); return ( handleStripeConfirm()} + onClick={() => handlePayConfirm('stripe')} > {t('pay with stripe')} @@ -242,19 +240,23 @@ export default function RechargeComponent() { h="auto" py="14px" px="34px" - onClick={() => handleWechatConfirm()} + onClick={() => handlePayConfirm('wechat')} > {t('pay with wechat')} )} - + 充值金额 - + diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index 92c20b48700..88e29a6625b 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -1,13 +1,13 @@ -import { ApiResp, LicenseRecord } from '@/types'; +import { getLicenseRecord } from '@/api/license'; +import { DownloadIcon, EmptyIcon, LicenseIcon, TokenIcon } from '@/components/icons'; import download from '@/utils/downloadFIle'; -import { formatMoney, getRemainingTime } from '@/utils/format'; +import { formatMoney, getRemainingTime } from '@/utils/tools'; import { Box, Flex, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useState } from 'react'; import Pagination from './Pagination'; -import { DownloadIcon, EmptyIcon, LicenseIcon, TokenIcon } from '@/components/icons'; -import { getLicenseRecord } from '@/api/license'; +import CurrencySymbol from './CurrencySymbol'; export default function History() { const { t } = useTranslation(); @@ -58,9 +58,9 @@ export default function History() { License - + - {formatMoney(item.amount)} + {item.amount} @@ -73,7 +73,9 @@ export default function History() { Token - + downloadToken(item.token)}> + + ))} diff --git a/service/license/src/pages/license/components/WechatPayment.tsx b/service/license/src/pages/license/components/WechatPayment.tsx index 8faacec5885..071b3a1f3d3 100644 --- a/service/license/src/pages/license/components/WechatPayment.tsx +++ b/service/license/src/pages/license/components/WechatPayment.tsx @@ -37,7 +37,7 @@ export default function WechatPayment(props: { style={{ margin: '0 auto' }} imageSettings={{ // 二维码中间的logo图片 - src: 'icons/pay_wechat.svg', + src: 'images/pay_wechat.svg', height: 40, width: 40, excavate: true // 中间图片所在的位置是否镂空 diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx index c964dbf42cd..6d486d0a72a 100644 --- a/service/license/src/pages/license/index.tsx +++ b/service/license/src/pages/license/index.tsx @@ -1,59 +1,16 @@ import LangSelectSimple from '@/components/LangSelect'; -import { Flex, Image, Text, useToast } from '@chakra-ui/react'; +import Account from '@/components/account'; +import { Flex, Image, Text } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import { useRouter } from 'next/router'; import RechargeComponent from './components/Recharge'; import LicenseRecord from './components/Record'; -import { useRouter } from 'next/router'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { ApiResp, LicensePayload, SystemEnv } from '@/types'; -import Account from '@/components/account'; -import { useEffect } from 'react'; -import { createLicenseRecord } from '@/api/license'; -import { setCookie } from '@/utils/cookieUtils'; export default function LicensePage() { const { t } = useTranslation(); const router = useRouter(); const goHome = () => router.replace('/'); - const totast = useToast(); - // const queryClient = useQueryClient(); - - // const licenseRecordMutation = useMutation( - // (payload: LicensePayload) => createLicenseRecord(payload), - // { - // onSuccess(data) { - // console.log(data); - // queryClient.invalidateQueries(['getLicenseActive']); - // }, - // onError(err: any) { - // console.log(err); - // } - // } - // ); - - // useEffect(() => { - // const { stripeState } = router.query; - // if (stripeState === 'success') { - // totast({ - // status: 'success', - // duration: 3000, - // title: t('Stripe Success'), - // isClosable: true, - // position: 'top' - // }); - // licenseRecordMutation.mutate(); - // } else if (stripeState === 'error') { - // totast({ - // status: 'error', - // duration: 3000, - // title: t('Stripe Cancel'), - // isClosable: true, - // position: 'top' - // }); - // } - // !!stripeState && router.replace(router.pathname); - // }, []); return ( @@ -96,8 +53,7 @@ export default function LicensePage() { export async function getServerSideProps({ req, res, locales }: any) { const lang: string = req?.headers?.['accept-language'] || 'zh'; const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; - console.log(local); - // setCookie() + res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); return { props: { diff --git a/service/license/src/pages/signin.tsx b/service/license/src/pages/signin.tsx index 5e88304d2a4..a50f4e28a7f 100644 --- a/service/license/src/pages/signin.tsx +++ b/service/license/src/pages/signin.tsx @@ -8,6 +8,7 @@ export default function SigninPage() { export async function getServerSideProps({ req, res, locales }: any) { const lang: string = req?.headers?.['accept-language'] || 'zh'; const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; + res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); const props = { ...(await serverSideTranslations(local, undefined, null, locales || [])) diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts index ef35d01a6f1..8e73935e5fe 100644 --- a/service/license/src/services/backend/db/license.ts +++ b/service/license/src/services/backend/db/license.ts @@ -1,11 +1,11 @@ -import { LicensePayload, LicenseRecord, LicenseToken } from '@/types'; +import { LicenseDB, LicenseRecordPayload, LicenseToken } from '@/types'; +import { base64Decode } from '@/utils/tools'; import { sign } from 'jsonwebtoken'; import { connectToDatabase } from './mongodb'; -import { base64Decode } from '@/utils/tools'; async function connectLicenseRecordCollection() { const client = await connectToDatabase(); - const collection = client.db().collection('license'); + const collection = client.db().collection('license'); return collection; } @@ -15,18 +15,18 @@ export async function createLicenseRecord({ token, orderID, quota, - paymentMethod -}: LicensePayload) { + payMethod +}: LicenseRecordPayload) { const collection = await connectLicenseRecordCollection(); const now = Math.floor(Date.now() / 1000); // Get current timestamp in seconds - const oneDayInSeconds = 24 * 60 * 60; // One day in seconds + const oneDayInSeconds = 3 * 24 * 60 * 60; - const record: LicenseRecord = { + const record: LicenseDB = { uid: uid, token: token, orderID: orderID, - paymentMethod: paymentMethod, + payMethod: payMethod, service: { quota: quota }, @@ -76,7 +76,7 @@ export async function getLicenseRecordsByUid({ export function generateLicenseToken(payload: LicenseToken) { const privateKey = process.env.LICENSE_PRIVATE_KEY; if (!privateKey) { - throw new Error('PRIVATE KEY is missing'); + throw new Error('LICENSE PRIVATE KEY IS MISSING'); } const nowInSeconds = Math.floor(Date.now() / 1000); const expirationTime = nowInSeconds + 3 * 24 * 60 * 60; @@ -91,3 +91,18 @@ export function generateLicenseToken(payload: LicenseToken) { const token = sign(_payload, base64Decode(privateKey), { algorithm: 'RS256' }); return token; } + +export async function hasIssuedLicense({ uid, orderID }: { uid: string; orderID: string }) { + try { + const collection = await connectLicenseRecordCollection(); + + const existingLicense = await collection.findOne({ + uid: uid, + orderID: orderID + }); + + return !!existingLicense; // 如果找到匹配的记录,返回 true;否则返回 false + } catch (error) { + throw new Error('Error checking for issued license:'); + } +} diff --git a/service/license/src/services/backend/db/payment.ts b/service/license/src/services/backend/db/payment.ts new file mode 100644 index 00000000000..cf70d496f3b --- /dev/null +++ b/service/license/src/services/backend/db/payment.ts @@ -0,0 +1,107 @@ +import { LicenseRecordPayload, PaymentDB, PaymentStatus, TPayMethod } from '@/types'; +import { connectToDatabase } from './mongodb'; +import { createLicenseRecord, generateLicenseToken } from './license'; + +async function connectPaymentCollection() { + const client = await connectToDatabase(); + const collection = client.db().collection('payment'); + return collection; +} + +export async function createPaymentRecord(payload: PaymentDB) { + const collection = await connectPaymentCollection(); + const result = await collection.insertOne(payload); + return result; +} + +export async function getPaymentByID({ uid, orderID }: { uid: string; orderID: string }) { + const collection = await connectPaymentCollection(); + const query = { + uid, + orderID + }; + const paymentRecord = await collection.findOne(query); + return paymentRecord; +} + +export async function updatePaymentStatus({ + uid, + orderID, + status +}: { + uid: string; + orderID: string; + status: PaymentStatus; +}) { + const collection = await connectPaymentCollection(); + + const result = await collection.findOneAndUpdate( + { + uid, + orderID + }, + { + $set: { + status: status, + updatedAt: new Date() + } + } + ); + + return result; +} + +// export async function updatePaymentAndLicenseSuccess({ +// uid, +// orderID, +// status, +// amount, +// quota, +// payMethod +// }: { +// uid: string; +// orderID: string; +// status: PaymentStatus; +// amount: number; +// quota: number; +// payMethod: TPayMethod; +// }) { +// const db = await connectToDatabase(); +// const session = db.startSession(); + +// // const transactionOptions = { +// // readConcern: { level: 'majority' }, +// // writeConcern: { w: 'majority' }, +// // readPreference: 'primary', +// // } + +// try { +// session.startTransaction(); +// console.log('事务状态:', session.transaction); +// await updatePaymentStatus({ +// uid: uid, +// orderID: orderID, +// status: status +// }); + +// // 在事务中执行生成许可证记录操作 +// const _token = generateLicenseToken({ type: 'Account', data: { amount: amount } }); +// const record = { +// uid: uid, +// amount: amount, +// token: _token, +// orderID: orderID, +// quota: quota, +// payMethod: payMethod +// }; +// await createLicenseRecord(record); + +// await session.commitTransaction(); +// } catch (err) { +// console.log(`[MongoDB transaction] ERROR: ${err}`); +// await session.abortTransaction(); +// } finally { +// await session.endSession(); +// console.log('事务状态:', session.transaction); +// } +// } diff --git a/service/license/src/stores/payment.ts b/service/license/src/stores/payment.ts new file mode 100644 index 00000000000..6c553d7d580 --- /dev/null +++ b/service/license/src/stores/payment.ts @@ -0,0 +1,19 @@ +import { PaymentData } from '@/types'; +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +type PaymentDataState = { + paymentData: PaymentData | undefined; + setPaymentData: (data: PaymentData) => void; + deletePaymentData: () => void; +}; + +export const usePaymentDataStore = create( + immer((set) => ({ + paymentData: undefined, + setPaymentData: (data) => set({ paymentData: data }), + deletePaymentData: () => set({ paymentData: undefined }) + })) +); + +export default usePaymentDataStore; diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts index f544467dfb6..79800134509 100644 --- a/service/license/src/types/license.ts +++ b/service/license/src/types/license.ts @@ -1,23 +1,33 @@ -// export type LicenseRecord = { -// _id?: string; -// uid: string; // user id -// token: string; // license token -// orderID: string; // order number -// paymentMethod: 'wechat' | 'stripe'; -// service: { -// quota: number; // 额度 -// }; -// iat: number; // 签发日期 -// exp: number; // 有效期 -// amount: number; // 消费金额 -// }; +import { TPayMethod } from './payment'; + +export type LicenseDB = { + _id?: string; + uid: string; // user id + token: string; // license token + orderID: string; // order number + payMethod: TPayMethod; + service: { + quota: number; // 额度 + }; + iat: number; // 签发日期 + exp: number; // 有效期 + amount: number; // 消费金额 +}; + +export type LicenseRecordPayload = { + uid: string; // user id + token: string; // license token + orderID: string; // order number + payMethod: TPayMethod; + quota: number; // 额度 + amount: number; // 重置金额 +}; export type LicensePayload = { - uid: string; amount: number; orderID: string; quota: number; - paymentMethod: 'wechat' | 'stripe'; + payMethod: TPayMethod; }; // new diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index 872bd1d3a92..5ee54bdccb9 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -1,3 +1,20 @@ +export type PaymentDB = { + uid: string; + amount: number; + // quota: number; + codeURL?: string; + currency: string; + orderID: string; + tradeNO?: string; + sessionID?: string; + payMethod: TPayMethod; + status: PaymentStatus; + createdAt: Date; // Creation timestamp + updatedAt: Date; // Modification timestamp +}; + +export type TPayMethod = 'stripe' | 'wechat'; + export enum PaymentStatus { PaymentNotPaid = 'notpaid', // 未支付 PaymentProcessing = 'processing', // 支付中 @@ -10,30 +27,26 @@ export enum PaymentStatus { export type PaymentParams = { amount: string; currency: 'CNY'; - payMethod: 'stripe' | 'wechat'; + payMethod: TPayMethod; }; -export type StripePaymentData = { +export type PaymentData = { amount: string; + codeURL?: string; currency: string; message: string; orderID: string; - sessionID: string; - user: string; + tradeNO?: string; + sessionID?: string; }; -export type WechatPaymentData = { - amount: string; - codeURL: string; - currency: string; +export type PaymentResult = { message: string; orderID: string; - tradeNO: string; - user: string; + status: PaymentStatus; }; -export type PaymentResultParams = { - orderID: string; - payMethod: 'stripe' | 'wechat'; - sessionID?: string; +export type WechatPaymentData = { + codeURL: string; + tradeNO: string; }; diff --git a/service/license/src/types/session.ts b/service/license/src/types/session.ts index 2c0169d00c0..8c1b75a8a3d 100644 --- a/service/license/src/types/session.ts +++ b/service/license/src/types/session.ts @@ -21,4 +21,4 @@ export type JWTPayload = { uid: string; } & UserSignInType; -export const sessionKey = 'session'; +export const sessionKey = 'sealos_session'; diff --git a/service/license/src/utils/format.ts b/service/license/src/utils/format.ts deleted file mode 100644 index 5f24f135ef4..00000000000 --- a/service/license/src/utils/format.ts +++ /dev/null @@ -1,54 +0,0 @@ -import dayjs from 'dayjs'; - -export const formatTime = (time: string | number | Date, format = 'YYYY-MM-DD HH:mm:ss') => { - return dayjs(time).format(format); -}; -export const k8sFormatTime = (time: string | number | Date) => { - return dayjs(time).format('TYYMM-DDTHH-mm-ss'); -}; -// 1¥=10000 -export const formatMoney = (mone: number) => { - return mone / 1000000; -}; -export const deFormatMoney = (money: number) => money * 1000000; - -export function formatUrl(url: string, query: Record) { - const urlObj = new URL(url); - // 添加新的查询参数 - for (const key in query) { - urlObj.searchParams.append(key, query[key]); - } - return urlObj.toString(); -} -export const parseOpenappQuery = (openapp: string) => { - let param = decodeURIComponent(openapp); - const firstQuestionMarkIndex = param.indexOf('?'); - let appkey = ''; - let appQuery = ''; - if (firstQuestionMarkIndex === -1) { - appkey = param; - } else { - appkey = param.substring(0, firstQuestionMarkIndex); - appQuery = param.substring(firstQuestionMarkIndex + 1); - } - return { - appkey, - appQuery - }; -}; - -export const getRemainingTime = (expirationTime: number) => { - const currentTime = Math.floor(Date.now() / 1000); - - if (currentTime >= expirationTime) { - return 'expired'; - } - - const remainingTimeInSeconds = expirationTime - currentTime; - const hours = Math.floor(remainingTimeInSeconds / 3600); - const minutes = Math.floor((remainingTimeInSeconds % 3600) / 60); - const seconds = remainingTimeInSeconds % 60; - - const formattedTime = `${hours}小时${minutes}分钟`; - return formattedTime; -}; diff --git a/service/license/src/utils/tools.ts b/service/license/src/utils/tools.ts index d308ca021e7..805646ddad6 100644 --- a/service/license/src/utils/tools.ts +++ b/service/license/src/utils/tools.ts @@ -4,9 +4,20 @@ export const formatTime = (time: string | number | Date, format = 'YYYY-MM-DD HH return dayjs(time).format(format); }; -// 1¥=10000 -export const formatMoney = (money: number) => { - return (money / 10000).toFixed(2); +export const getRemainingTime = (expirationTime: number) => { + const currentTime = Math.floor(Date.now() / 1000); + + if (currentTime >= expirationTime) { + return 'expired'; + } + + const remainingTimeInSeconds = expirationTime - currentTime; + const hours = Math.floor(remainingTimeInSeconds / 3600); + const minutes = Math.floor((remainingTimeInSeconds % 3600) / 60); + const seconds = remainingTimeInSeconds % 60; + + const formattedTime = `${hours}小时${minutes}分钟`; + return formattedTime; }; export function appWaitSeconds(ms: number) { @@ -16,6 +27,7 @@ export function appWaitSeconds(ms: number) { }, ms); }); } + export async function getBase64FromRemote(url: string) { try { const res = await fetch(url); @@ -77,3 +89,10 @@ export function base64Decode(str: string) { const decodedBuffer = Buffer.from(str, 'base64').toString('binary'); return decodedBuffer; } + +// 1¥=100 +export const formatMoney = (money: number) => { + return money / 100; +}; + +export const deFormatMoney = (money: number) => money * 100; diff --git a/service/license/tsconfig.json b/service/license/tsconfig.json index 3ca6a9a50cb..06f3aee2e25 100644 --- a/service/license/tsconfig.json +++ b/service/license/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], "allowJs": true, "skipLibCheck": true, "strict": true, @@ -14,9 +18,17 @@ "jsx": "preserve", "incremental": true, "paths": { - "@/*": ["./src/*"] + "@/*": [ + "./src/*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] -} + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file From 81260dfb9e59069477f36cb42077f47e130b470b Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Fri, 20 Oct 2023 13:53:14 +0800 Subject: [PATCH 06/17] docker build Signed-off-by: jingyang <3161362058@qq.com> --- service/license/Dockerfile | 110 +++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 46 deletions(-) diff --git a/service/license/Dockerfile b/service/license/Dockerfile index 32e15899dcc..0e41b481da9 100644 --- a/service/license/Dockerfile +++ b/service/license/Dockerfile @@ -1,72 +1,90 @@ -# Copyright © 2022 sealos. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Install dependencies only when needed -FROM node:current-alpine AS deps +# 指定基础镜像版本,确保每次构建都是幂等的 +FROM node:18-alpine AS base + +FROM base AS builder + # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. -RUN apk add --no-cache libc6-compat && npm install -g pnpm -WORKDIR /app +RUN apk add --no-cache libc6-compat -# Install dependencies based on the preferred package manager -COPY package.json pnpm-lock.yaml* ./ -RUN \ - [ -f pnpm-lock.yaml ] && pnpm install || \ - (echo "Lockfile not found." && exit 1) +# Node v16.13 开始支持 corepack 用于管理第三方包管理器 +# 锁定包管理器版本,确保 CI 每次构建都是幂等的 +# RUN corepack enable && corepack prepare pnpm@latest --activate +RUN corepack enable && corepack prepare pnpm@8.5.0 --activate -# Rebuild the source code only when needed -FROM node:current-alpine AS builder WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules + +# pnpm fetch does require only lockfile +# 注意还需要复制 `.npmrc`,因为里面可能包含 npm registry 等配置,下载依赖需要用到 +COPY pnpm-lock.yaml ./ + +# 推荐使用 pnpm fetch 命令下载依赖到 virtual store,专为 docker 构建优化 +# 参考:https://pnpm.io/cli/fetch +RUN pnpm fetch + +# 将本地文件复制到构建上下文 COPY . . -# Next.js collects completely anonymous telemetry data about general usage. -# Learn more here: https://nextjs.org/telemetry # Uncomment the following line in case you want to disable telemetry during the build. ENV NEXT_TELEMETRY_DISABLED 1 -RUN npm install -g pnpm && pnpm run build +# 基于 virtual store 生成 node_modules && 打包构建 +# 此处不需要与 package registry 进行通信,因此依赖安装速度极快 +# 注意 PNPM v8.4.0 版本有一个 breaking change +# 当 `node_modules` 存在,运行 `pnpm install` 会出现命令行交互操作,导致 CI 挂掉 +# 这里加上 `--force` 参数,关闭命令行交互操作 +RUN pnpm install --offline --force && pnpm build -# Production image, copy all the files and run next -FROM node:current-alpine AS runner -WORKDIR /app +FROM base AS runner + +# RUN apk update && apk add --no-cache git +RUN apk add --no-cache curl + +# 如果需要是用 TZ 环境变量 实现时区控制,需要安装 tzdata 这个包 +# debian 的基础镜像默认情况下已经安装了 tzdata,而 ubuntu 并没有 +# RUN apk add --no-cache tzdata +ARG RUNTIME_ENV +ENV RUNTIME_ENV=$RUNTIME_ENV ENV NODE_ENV production -# Uncomment the following line in case you want to disable telemetry during runtime. -ENV NEXT_TELEMETRY_DISABLED 1 +# Docker 容器不推荐用 root 身份运行 +# 这边先建立一个特定的用户和用户组,为它分配必要的权限,使用 USER 切换到这个用户 +# 注意,如果不是 root 权限,对于可执行文件,需要修改权限,确保文件可以执行 RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs -RUN sed -i 's/https/http/' /etc/apk/repositories -RUN apk add curl \ - && apk add ca-certificates \ - && update-ca-certificates +# 设置时区 +# 在使用 Docker 容器时,系统默认的时区就是 UTC 时间(0 时区),和我们实际需要的北京时间相差八个小时 +# ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 TZ=Asia/Shanghai +# RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone -# You only need to copy next.config.js if you are NOT using the default configuration -# COPY --from=builder /app/next.config.js ./ -COPY --from=builder /app/public ./public -COPY --from=builder /app/package.json ./package.json +WORKDIR /app + +# PNPM 有一个全局 store,项目中的 node_modules 实际上是全局 store 的 symlink +# 正常需要从上一阶段同时复制 `node_modules` 和全局 store,这样才能正常运行 +# 但是由于 `standalone` 目录里面包含所有运行时依赖,且都是独立目录 +# 因此可以直接复制该目录,无需复制全局 store(如果复制还会增加镜像体积) +# 另外运行需要的配置文件、dotfile 也都在 `standalone` 目录里面,无需单独复制 -# Automatically leverage output traces to reduce image size -# https://nextjs.org/docs/advanced-features/output-file-tracing +# `standalone` 模式打包,默认包含服务端代码,没有客户端代码 +# 因为官方建议通过 CDN 托管,但也可以手动复制 `public`、`.next/static` 目录 +COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static -USER nextjs +# 注意,`standalone` 目录下已经包含了服务端代码,无需再复制 `.next/server` +# COPY --from=builder /app/.next/server ./.next/server -EXPOSE 3000 +USER nextjs +# Uncomment the following line in case you want to disable telemetry during runtime. +ENV NEXT_TELEMETRY_DISABLED 1 ENV PORT 3000 +# 默认暴露 80 端口 +EXPOSE 3000 + +# 用 standalone 模式打包后,生成的 `standalone/node_modules` 目录下缺少 `.bin` 目录 +# 导致无法用 `next` 命令启动项目,但可以用 `node server.js` 启动 +# 参考:https://nextjs.org/docs/advanced-features/output-file-tracing CMD ["node", "server.js"] From f4a4c4a75f8ca02d6dffd64d3f24f17b40df1925 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Fri, 20 Oct 2023 16:56:01 +0800 Subject: [PATCH 07/17] done Signed-off-by: jingyang <3161362058@qq.com> --- service/license/deploy/Kubefile | 16 ++ service/license/deploy/README.md | 53 +++++ .../license/deploy/manifests/deploy.yaml.tmpl | 185 ++++++++++++++++++ .../deploy/manifests/ingress.yaml.tmpl | 27 +++ service/license/deploy/manifests/rbac.yaml | 41 ++++ service/license/deploy/manifests/secret.yaml | 37 ++++ service/license/deploy/scripts/init.sh | 13 ++ service/license/public/locales/en/common.json | 15 +- service/license/public/locales/zh/common.json | 7 +- service/license/src/api/payment.ts | 2 + .../src/pages/api/auth/oauth/wechat/index.ts | 1 - .../src/pages/api/payment/checkWechat.ts | 24 ++- .../license/src/pages/api/payment/result.ts | 27 +-- .../src/pages/license/components/Recharge.tsx | 31 ++- .../src/pages/license/components/Record.tsx | 1 + .../src/services/backend/db/license.ts | 4 +- .../src/services/backend/db/payment.ts | 127 +++++++----- .../license/src/services/backend/db/user.ts | 4 +- service/license/src/services/request.ts | 2 + service/license/src/types/license.ts | 2 + service/license/src/types/user.ts | 2 + 21 files changed, 530 insertions(+), 91 deletions(-) create mode 100644 service/license/deploy/Kubefile create mode 100644 service/license/deploy/README.md create mode 100644 service/license/deploy/manifests/deploy.yaml.tmpl create mode 100644 service/license/deploy/manifests/ingress.yaml.tmpl create mode 100644 service/license/deploy/manifests/rbac.yaml create mode 100644 service/license/deploy/manifests/secret.yaml create mode 100644 service/license/deploy/scripts/init.sh diff --git a/service/license/deploy/Kubefile b/service/license/deploy/Kubefile new file mode 100644 index 00000000000..977af9d55ff --- /dev/null +++ b/service/license/deploy/Kubefile @@ -0,0 +1,16 @@ +FROM scratch +USER 65532:65532 + +COPY registry registry +COPY manifests manifests +COPY scripts scripts + +ENV cloudDomain="127.0.0.1.nip.io" +ENV cloudPort="" +ENV certSecretName="wildcard-cert" +ENV passWordEnabled="false" +ENV githubEnabled="false" +ENV wechatEnabled="false" +ENV smsEnabled="false" + +CMD ["bash scripts/init.sh"] diff --git a/service/license/deploy/README.md b/service/license/deploy/README.md new file mode 100644 index 00000000000..3f4712eefbc --- /dev/null +++ b/service/license/deploy/README.md @@ -0,0 +1,53 @@ +### How to build image + +```shell +sealos build -t docker.io/labring/sealos-cloud-desktop:latest -f Kubefile . +``` + +### Env + +| Name | Description | Default | +|----------------------------|-----------------------------|----------------------------------------| +| `cloudDomain` | sealos cloud domain | `cloud.example.com` | +| `wildcardCertSecretName` | wildcard cert secret name | `wildcard-cert` | + +### Config + +If you enable password login (which is enabled by default), you need to set the password salt by using a config file. + +And this is a command to generate a password salt: +```shell +echo -n "your-password-salt" | base64 +``` + + +Here is a config file example: +```yaml +# desktop-config.yaml +apiVersion: apps.sealos.io/v1beta1 +kind: Config +metadata: + name: secret +spec: + path: manifests/secret.yaml + match: docker.io/labring/sealos-cloud-desktop:latest + strategy: merge + data: | + data: + mongodb_uri: + jwt_secret: + password_salt: +``` + +*Please make sure `spec.match` is the same as the image you want to run* + +### How to run + +```shell +sealos run \ + --env cloudDomain="127.0.0.1.nip.io" \ + --env wildcardCertSecretName="wildcard-cert" \ + --env passwordEnabled="true" \ + docker.io/labring/sealos-cloud-desktop:latest \ + --config-file desktop-config.yaml +``` diff --git a/service/license/deploy/manifests/deploy.yaml.tmpl b/service/license/deploy/manifests/deploy.yaml.tmpl new file mode 100644 index 00000000000..2b1b4e8f26d --- /dev/null +++ b/service/license/deploy/manifests/deploy.yaml.tmpl @@ -0,0 +1,185 @@ +# Copyright © 2022 sealos. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: desktop-frontend + namespace: sealos +--- +apiVersion: v1 +kind: Service +metadata: + name: desktop-frontend + namespace: sealos +spec: + ports: + - port: 3000 + selector: + app: desktop-frontend +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: desktop-frontend-config + namespace: sealos +data: + config.yaml: |- + addr: :3000 + config.json: |- + { + "scripts": [] + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: desktop-frontend + namespace: sealos +spec: + selector: + matchLabels: + app: desktop-frontend + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% + template: + metadata: + labels: + app: desktop-frontend + spec: + serviceAccountName: desktop-frontend + containers: + - name: desktop-frontend + env: + # callback url is used for oauth2 login, required + - name: CALLBACK_URL + value: https://{{ .cloudDomain }}{{ if .cloudPort }}:{{ .cloudPort }}{{ end }}/callback + # mongodb uri, required + - name: MONGODB_URI + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: mongodb_uri + # jwt secret, required + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: jwt_secret + + # set to true to enable password login, modify the PASSWORD_SALT env to change the salt + - name: PASSWORD_ENABLED + value: '{{ .passwordEnabled }}' + # set to true to enable github login + - name: GITHUB_ENABLED + value: '{{ .githubEnabled }}' + # set to true to enable wechat login + - name: WECHAT_ENABLED + value: '{{ .wechatEnabled }}' + # set to true to enable sms login + - name: SMS_ENABLED + value: '{{ .smsEnabled }}' + # password login env + - name: PASSWORD_SALT + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: password_salt + # github login env + - name: GITHUB_CLIENT_ID + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: github_client_id + optional: true + - name: GITHUB_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: github_client_secret + optional: true + # wechat login env + - name: WECHAT_CLIENT_ID + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: wechat_client_id + optional: true + - name: WECHAT_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: wechat_client_secret + optional: true + # sms login env + - name: ALI_ENDPOINT + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: ali_sms_endpoint + optional: true + - name: ALI_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: ali_access_key_id + optional: true + - name: ALI_ACCESS_KEY_SECRET + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: ali_access_key_secret + optional: true + - name: ALI_SIGN_NAME + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: ali_sms_sign_name + optional: true + - name: ALI_TEMPLATE_CODE + valueFrom: + secretKeyRef: + name: desktop-frontend-secret + key: ali_sms_template_code + optional: true + securityContext: + runAsNonRoot: true + runAsUser: 1001 + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + image: ghcr.io/labring/license-system-frontend:latest + imagePullPolicy: IfNotPresent + volumeMounts: + - name: desktop-frontend-volume + mountPath: /config.yaml + subPath: config.yaml + - mountPath: /app/data/config.json + name: desktop-frontend-volume + subPath: config.json + resources: + limits: + cpu: 1000m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + volumes: + - name: desktop-frontend-volume + configMap: + name: desktop-frontend-config diff --git a/service/license/deploy/manifests/ingress.yaml.tmpl b/service/license/deploy/manifests/ingress.yaml.tmpl new file mode 100644 index 00000000000..b17d84c485c --- /dev/null +++ b/service/license/deploy/manifests/ingress.yaml.tmpl @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + nginx.ingress.kubernetes.io/rewrite-target: /$2 + name: sealos-desktop + namespace: sealos +spec: + rules: + - host: {{ .cloudDomain }} + http: + paths: + - pathType: Prefix + #@see: https://github.com/kubernetes/ingress-nginx/issues/3122#issuecomment-1125881703 + path: /()(.*) + backend: + service: + name: desktop-frontend + port: + number: 3000 + tls: + - hosts: + - '{{ .cloudDomain }}' + secretName: {{ .certSecretName }} \ No newline at end of file diff --git a/service/license/deploy/manifests/rbac.yaml b/service/license/deploy/manifests/rbac.yaml new file mode 100644 index 00000000000..b6209409426 --- /dev/null +++ b/service/license/deploy/manifests/rbac.yaml @@ -0,0 +1,41 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: auth-system-manager-role +rules: + - apiGroups: ["user.sealos.io"] + resources: ["users"] + verbs: ["list", "get", "create", "update", "patch", "watch"] + - apiGroups: ["user.sealos.io"] + resources: ["users/status"] + verbs: ["list", "get", "create", "update", "patch", "watch"] + - apiGroups: ["user.sealos.io"] + resources: ["operationrequests", "deleterequests"] + verbs: ["create","get"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: desktop-user-editor-role-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: user-editor-role +subjects: + - kind: ServiceAccount + name: desktop-frontend + namespace: sealos +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: desktop-operationrequest-editor-role-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: operationrequest-editor-role +subjects: + - kind: ServiceAccount + name: desktop-frontend + namespace: sealos \ No newline at end of file diff --git a/service/license/deploy/manifests/secret.yaml b/service/license/deploy/manifests/secret.yaml new file mode 100644 index 00000000000..76bb66f2c65 --- /dev/null +++ b/service/license/deploy/manifests/secret.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Secret +metadata: + name: desktop-frontend-secret + namespace: sealos +type: Opaque +data: + # base64 encoded mongodb uri, required + mongodb_uri: + + # base64 encoded jwt secret, required + jwt_secret: + + # base64 encoded password salt, required if env PASSWORD_ENABLED is true + # please use a random string and do not change it after deployment + password_salt: + + # base64 encoded GitHub client id, required if env GITHUB_ENABLED is true + github_client_id: + # base64 encoded GitHub client secret, required if env GITHUB_ENABLED is true + github_client_secret: + + # base64 encoded WeChat client id, required if env WECHAT_ENABLED is true + wechat_client_id: + # base64 encoded WeChat client secret, required if env WECHAT_ENABLED is true + wechat_client_secret: + + # base64 encoded ali sms endpoint, required if env SMS_ENABLED is true + ali_sms_endpoint: + # base64 encoded ali access key id, required if env SMS_ENABLED is true + ali_access_key_id: + # base64 encoded ali access key secret, required if env SMS_ENABLED is true + ali_access_key_secret: + # base64 encoded ali sms sign name, required if env SMS_ENABLED is true + ali_sms_sign_name: + # base64 encoded ali sms template code, required if env SMS_ENABLED is true + ali_sms_template_code: diff --git a/service/license/deploy/scripts/init.sh b/service/license/deploy/scripts/init.sh new file mode 100644 index 00000000000..7adfbd31adf --- /dev/null +++ b/service/license/deploy/scripts/init.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -ex + +kubectl apply -f manifests/deploy.yaml -f manifests/rbac.yaml -f manifests/ingress.yaml + +secret_exists=$(kubectl get secret desktop-frontend-secret -n sealos --ignore-not-found=true) +if [[ -n "$secret_exists" ]]; then + echo "desktop-frontend-secret already exists, skip create desktop secret" +else + echo "create desktop secret" + kubectl apply -f manifests/secret.yaml +fi diff --git a/service/license/public/locales/en/common.json b/service/license/public/locales/en/common.json index 436a19a8921..4827a492182 100644 --- a/service/license/public/locales/en/common.json +++ b/service/license/public/locales/en/common.json @@ -1,10 +1,4 @@ { - "Cost Center": "Cost Center", - "Laf on Sealos": "Laf on Sealos", - "App Launchpad": "App Launchpad", - "Database": "Database", - "Sealos Document": "Sealos Document", - "Terminal": "Terminal", "More Apps": "More Apps", "Message Center": "Message Center", "Have Read": "Have read", @@ -34,7 +28,6 @@ "and": "and", "Privacy Policy": "Privacy Policy", "Get Code": "verification", - "Total Amount": "Total Amount", "Payment Result": "Payment Result", "Payment Successful": "Payment Successful", "In Payment": "In Payment ...", @@ -90,5 +83,9 @@ "Please read and agree to the agreement": "Please read and agree to the agreement", "Purchase Link Error": "Purchase Link Error", "You have not purchased the License": "You have not purchased the License", - "App Info": "App Info" -} \ No newline at end of file + "App Info": "App Info", + "License issued successfully": "License issued successfully", + "Pay Minimum Tips": "The amount need to be more than 10 when paying with Stripe", + "Stripe Cancel": "Stripe Cancel", + "Recharge Amount": "Recharge Amount" +} diff --git a/service/license/public/locales/zh/common.json b/service/license/public/locales/zh/common.json index acf40eb1d84..ccf3a0e41ee 100644 --- a/service/license/public/locales/zh/common.json +++ b/service/license/public/locales/zh/common.json @@ -84,5 +84,8 @@ "Please read and agree to the agreement": "请阅读并同意协议", "Purchase Link Error": "购买链接错误", "You have not purchased the License": "您还没有购买 License", - "App Info": "应用信息" -} \ No newline at end of file + "App Info": "应用信息", + "License issued successfully": "签发 License 成功", + "Pay Minimum Tips": "Stripe支付时金额需大于10", + "Stripe Cancel": "Stripe 支付取消" +} diff --git a/service/license/src/api/payment.ts b/service/license/src/api/payment.ts index 2f33455650a..b366f07f28e 100644 --- a/service/license/src/api/payment.ts +++ b/service/license/src/api/payment.ts @@ -6,3 +6,5 @@ export const createPayment = (payload: PaymentParams) => export const getPaymentResult = (payload: { orderID: string }) => POST('/api/payment/result', payload); + +export const checkWechatPay = () => GET('/api/payment/checkWechat'); diff --git a/service/license/src/pages/api/auth/oauth/wechat/index.ts b/service/license/src/pages/api/auth/oauth/wechat/index.ts index 90fc819e154..903db8e17bd 100644 --- a/service/license/src/pages/api/auth/oauth/wechat/index.ts +++ b/service/license/src/pages/api/auth/oauth/wechat/index.ts @@ -1,6 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { jsonRes } from '@/services/backend/response'; - const APP_ID = process.env.WECHAT_CLIENT_ID!; const APP_SECRET = process.env.WECHAT_CLIENT_SECRET!; import { TWechatToken, TWechatUser } from '@/types/user'; diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts index b462272d9ce..0f34711b684 100644 --- a/service/license/src/pages/api/payment/checkWechat.ts +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -1,6 +1,5 @@ import { authSession } from '@/services/backend/auth'; -import { createLicenseRecord, generateLicenseToken } from '@/services/backend/db/license'; -import { getPaymentByID, updatePaymentStatus } from '@/services/backend/db/payment'; +import { findRecentNopayOrder, updatePaymentAndIssueLicense } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; import { PaymentResult, PaymentStatus } from '@/types'; @@ -8,17 +7,22 @@ import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { orderID } = req.body as { orderID: string }; const userInfo = await authSession(req.headers); if (!userInfo) { return jsonRes(res, { code: 401, message: 'token verify error' }); } + const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); if (!sealosPayUrl) { return jsonRes(res, { code: 500, message: 'sealos payment has not been activated' }); } - const payment = await getPaymentByID({ uid: userInfo.uid, orderID: orderID }); + const payment = await findRecentNopayOrder({ + uid: userInfo.uid, + payMethod: 'wechat', + status: PaymentStatus.PaymentNotPaid + }); + if (!payment) { return jsonRes(res, { code: 400, message: 'No order found' }); } @@ -36,6 +40,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }) }).then((res) => res.json()); + if (result.status === PaymentStatus.PaymentSuccess) { + await updatePaymentAndIssueLicense({ + uid: userInfo.uid, + amount: payment.amount, + quota: payment.amount, + payMethod: payment.payMethod, + // pay status + orderID: payment?.orderID, + status: result.status + }); + } + return jsonRes(res, { data: result }); diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts index f31876b902f..c53146edcae 100644 --- a/service/license/src/pages/api/payment/result.ts +++ b/service/license/src/pages/api/payment/result.ts @@ -4,7 +4,11 @@ import { generateLicenseToken, hasIssuedLicense } from '@/services/backend/db/license'; -import { getPaymentByID, updatePaymentStatus } from '@/services/backend/db/payment'; +import { + getPaymentByID, + updatePaymentAndIssueLicense, + updatePaymentStatus +} from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; import { PaymentResult, PaymentStatus } from '@/types'; @@ -26,7 +30,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } const payment = await getPaymentByID({ uid: userInfo.uid, orderID: orderID }); - console.log(payment); if (!payment) { return jsonRes(res, { code: 400, message: 'No order found' }); @@ -50,26 +53,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }).then((res) => res.json()); if (result.status === PaymentStatus.PaymentSuccess) { - await updatePaymentStatus({ - uid: userInfo.uid, - orderID: orderID, - status: result.status - }); - const _token = generateLicenseToken({ type: 'Account', data: { amount: payment.amount } }); - const record = { + await updatePaymentAndIssueLicense({ uid: userInfo.uid, amount: payment.amount, - token: _token, - orderID: orderID, quota: payment.amount, - payMethod: payment.payMethod - }; - await createLicenseRecord(record); - } - - if (result.status === PaymentStatus.PaymentProcessing) { - await updatePaymentStatus({ - uid: userInfo.uid, + payMethod: payment.payMethod, + // pay status orderID: orderID, status: result.status }); diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index 27d632b809a..73b407f943d 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -1,4 +1,4 @@ -import { createPayment, getPaymentResult } from '@/api/payment'; +import { checkWechatPay, createPayment, getPaymentResult } from '@/api/payment'; import { getSystemEnv } from '@/api/system'; import { StripeIcon, WechatIcon } from '@/components/icons'; import useBonusBox from '@/hooks/useBonusBox'; @@ -106,11 +106,11 @@ export default function RechargeComponent() { useQuery(['getLicenseResult', orderID], () => getPaymentResult({ orderID }), { refetchInterval: complete === 2 ? 3 * 1000 : false, - enabled: complete === 2 && orderID !== undefined, + enabled: complete === 2 && !!orderID, cacheTime: 0, staleTime: 0, onSuccess(data) { - console.log(data, 'xxxxxxxx'); + console.log(data, 'getLicenseResult'); if (data.status === PaymentStatus.PaymentSuccess) { onClosePayment(); toast({ @@ -133,11 +133,33 @@ export default function RechargeComponent() { } }); + useQuery(['checkWechatPay'], () => checkWechatPay(), { + onSuccess(data) { + console.log(data, 'checkWechatPay'); + if (data.status === PaymentStatus.PaymentSuccess) { + toast({ + status: 'success', + title: t('License issued successfully'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + } + } + }); + useEffect(() => { const { stripeState, orderID } = router.query; if (stripeState === 'success') { setComplete(2); setOrderID(orderID as string); + const clearQuery = () => { + router.replace({ + pathname: '/license', + query: null + }); + }; + setTimeout(clearQuery, 0); } else if (stripeState === 'error') { toast({ status: 'error', @@ -148,7 +170,8 @@ export default function RechargeComponent() { }); onClosePayment(); } - }, [onClosePayment, router.query, t, toast]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return ( { const result = Buffer.from(token, 'binary').toString('base64'); diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts index 8e73935e5fe..bc068359976 100644 --- a/service/license/src/services/backend/db/license.ts +++ b/service/license/src/services/backend/db/license.ts @@ -32,7 +32,9 @@ export async function createLicenseRecord({ }, iat: now, // Store the current timestamp as iat exp: now + oneDayInSeconds, // Set expiration to one day from now (in seconds) - amount: amount + amount: amount, + createdAt: new Date(), + updatedAt: new Date() }; const result = await collection.insertOne(record); diff --git a/service/license/src/services/backend/db/payment.ts b/service/license/src/services/backend/db/payment.ts index cf70d496f3b..8aad469d445 100644 --- a/service/license/src/services/backend/db/payment.ts +++ b/service/license/src/services/backend/db/payment.ts @@ -51,57 +51,84 @@ export async function updatePaymentStatus({ return result; } -// export async function updatePaymentAndLicenseSuccess({ -// uid, -// orderID, -// status, -// amount, -// quota, -// payMethod -// }: { -// uid: string; -// orderID: string; -// status: PaymentStatus; -// amount: number; -// quota: number; -// payMethod: TPayMethod; -// }) { -// const db = await connectToDatabase(); -// const session = db.startSession(); +export async function updatePaymentAndIssueLicense({ + uid, + orderID, + status, + amount, + quota, + payMethod +}: { + uid: string; + orderID: string; + status: PaymentStatus; + amount: number; + quota: number; + payMethod: TPayMethod; +}) { + const db = await connectToDatabase(); + const session = db.startSession(); + + // const transactionOptions = { + // readConcern: { level: 'majority' }, + // writeConcern: { w: 'majority' }, + // readPreference: 'primary', + // } -// // const transactionOptions = { -// // readConcern: { level: 'majority' }, -// // writeConcern: { w: 'majority' }, -// // readPreference: 'primary', -// // } + try { + session.startTransaction(); + console.log('事务状态:', session.transaction); + await updatePaymentStatus({ + uid: uid, + orderID: orderID, + status: status + }); -// try { -// session.startTransaction(); -// console.log('事务状态:', session.transaction); -// await updatePaymentStatus({ -// uid: uid, -// orderID: orderID, -// status: status -// }); + // 在事务中执行生成许可证记录操作 + const _token = generateLicenseToken({ type: 'Account', data: { amount: amount } }); + const record = { + uid: uid, + amount: amount, + token: _token, + orderID: orderID, + quota: quota, + payMethod: payMethod + }; + await createLicenseRecord(record); -// // 在事务中执行生成许可证记录操作 -// const _token = generateLicenseToken({ type: 'Account', data: { amount: amount } }); -// const record = { -// uid: uid, -// amount: amount, -// token: _token, -// orderID: orderID, -// quota: quota, -// payMethod: payMethod -// }; -// await createLicenseRecord(record); + await session.commitTransaction(); + } catch (err) { + console.log(`[MongoDB transaction] ERROR: ${err}`); + await session.abortTransaction(); + } finally { + await session.endSession(); + console.log('事务状态:', session.transaction); + } +} -// await session.commitTransaction(); -// } catch (err) { -// console.log(`[MongoDB transaction] ERROR: ${err}`); -// await session.abortTransaction(); -// } finally { -// await session.endSession(); -// console.log('事务状态:', session.transaction); -// } -// } +export async function findRecentNopayOrder({ + uid, + payMethod, + status +}: { + uid: string; + payMethod: TPayMethod; + status: PaymentStatus; +}) { + const collection = await connectPaymentCollection(); + + const query = { + uid: uid, + status: status, + payMethod: payMethod + }; + + const recentNopayOrder = await collection.findOne(query, { + sort: { + createdAt: -1 + }, + limit: 1 + }); + + return recentNopayOrder; +} diff --git a/service/license/src/services/backend/db/user.ts b/service/license/src/services/backend/db/user.ts index caa9fb66a0f..6cda97cd2a6 100644 --- a/service/license/src/services/backend/db/user.ts +++ b/service/license/src/services/backend/db/user.ts @@ -38,7 +38,9 @@ export async function createUser({ avatar_url, name, created_time: new Date().toISOString(), - [provider]: id + [provider]: id, + createdAt: new Date(), + updatedAt: new Date() }; if (password) { diff --git a/service/license/src/services/request.ts b/service/license/src/services/request.ts index 703986c6685..04b894e2c60 100644 --- a/service/license/src/services/request.ts +++ b/service/license/src/services/request.ts @@ -106,6 +106,8 @@ request.interceptors.response.use( return response.data; }, (error: any) => { + console.log(error); + if (axios.isCancel(error)) { return Promise.reject('cancel request' + String(error)); } else { diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts index 79800134509..86d5db2fefe 100644 --- a/service/license/src/types/license.ts +++ b/service/license/src/types/license.ts @@ -12,6 +12,8 @@ export type LicenseDB = { iat: number; // 签发日期 exp: number; // 有效期 amount: number; // 消费金额 + createdAt: Date; // Creation timestamp + updatedAt: Date; // Modification timestamp }; export type LicenseRecordPayload = { diff --git a/service/license/src/types/user.ts b/service/license/src/types/user.ts index 1ee27a59dc8..c3896d4724c 100644 --- a/service/license/src/types/user.ts +++ b/service/license/src/types/user.ts @@ -78,6 +78,8 @@ export type User = { name: string; created_time: string; password?: string; + createdAt: Date; // Creation timestamp + updatedAt: Date; // Modification timestamp } & UserSignInType; export type UserSignInType = { [key in AuthProvider]?: string }; From ec3fc452fe2b59d879c711093fcb02cb01055217 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Fri, 20 Oct 2023 17:21:41 +0800 Subject: [PATCH 08/17] license yaml Signed-off-by: jingyang <3161362058@qq.com> --- service/license/package.json | 2 ++ service/license/pnpm-lock.yaml | 14 ++++++++++++-- .../src/pages/license/components/Record.tsx | 5 ++--- service/license/src/utils/json2Yaml.ts | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 service/license/src/utils/json2Yaml.ts diff --git a/service/license/package.json b/service/license/package.json index 1f02920e489..23c812de728 100644 --- a/service/license/package.json +++ b/service/license/package.json @@ -24,6 +24,7 @@ "i18next": "^23.5.1", "immer": "^10.0.3", "js-cookie": "^3.0.5", + "js-yaml": "^4.1.0", "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "mongodb": "^6.1.0", @@ -41,6 +42,7 @@ }, "devDependencies": { "@types/js-cookie": "^3.0.4", + "@types/js-yaml": "^4.0.8", "@types/jsonwebtoken": "^9.0.4", "@types/lodash": "^4.14.199", "@types/node": "^20", diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml index 6ae20149140..250c7fb9ab7 100644 --- a/service/license/pnpm-lock.yaml +++ b/service/license/pnpm-lock.yaml @@ -50,6 +50,9 @@ dependencies: js-cookie: specifier: ^3.0.5 version: registry.npmmirror.com/js-cookie@3.0.5 + js-yaml: + specifier: ^4.1.0 + version: registry.npmmirror.com/js-yaml@4.1.0 jsonwebtoken: specifier: ^9.0.2 version: registry.npmmirror.com/jsonwebtoken@9.0.2 @@ -97,6 +100,9 @@ devDependencies: '@types/js-cookie': specifier: ^3.0.4 version: registry.npmmirror.com/@types/js-cookie@3.0.4 + '@types/js-yaml': + specifier: ^4.0.8 + version: registry.npmmirror.com/@types/js-yaml@4.0.8 '@types/jsonwebtoken': specifier: ^9.0.4 version: registry.npmmirror.com/@types/jsonwebtoken@9.0.4 @@ -2071,6 +2077,12 @@ packages: version: 3.0.4 dev: true + registry.npmmirror.com/@types/js-yaml@4.0.8: + resolution: {integrity: sha512-m6jnPk1VhlYRiLFm3f8X9Uep761f+CK8mHyS65LutH2OhmBF0BeMEjHgg05usH8PLZMWWc/BUR9RPmkvpWnyRA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/js-yaml/-/js-yaml-4.0.8.tgz} + name: '@types/js-yaml' + version: 4.0.8 + dev: true + registry.npmmirror.com/@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz} name: '@types/json5' @@ -2338,7 +2350,6 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz} name: argparse version: 2.0.1 - dev: true registry.npmmirror.com/aria-hidden@1.2.3: resolution: {integrity: sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.3.tgz} @@ -4186,7 +4197,6 @@ packages: hasBin: true dependencies: argparse: registry.npmmirror.com/argparse@2.0.1 - dev: true registry.npmmirror.com/json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz} diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index ed726875a5d..4331e587d1b 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -8,6 +8,7 @@ import { useTranslation } from 'next-i18next'; import { useState } from 'react'; import Pagination from './Pagination'; import CurrencySymbol from './CurrencySymbol'; +import { json2License } from '@/utils/json2Yaml'; export default function History() { const { t } = useTranslation(); @@ -20,11 +21,9 @@ export default function History() { pageSize: pageSize }) ); - console.log(data); const downloadToken = (token: string) => { - const result = Buffer.from(token, 'binary').toString('base64'); - download('token.txt', result); + download('token.yaml', json2License(token)); }; return ( diff --git a/service/license/src/utils/json2Yaml.ts b/service/license/src/utils/json2Yaml.ts new file mode 100644 index 00000000000..5bffa38f88d --- /dev/null +++ b/service/license/src/utils/json2Yaml.ts @@ -0,0 +1,17 @@ +import yaml from 'js-yaml'; + +export const json2License = (token: string) => { + const license_name = crypto.randomUUID(); + const template = { + apiVersion: 'infostream.sealos.io/v1', + kind: 'License', + metadata: { + name: license_name, + namespace: ' ns-admin' + }, + spec: { + token: token + } + }; + return yaml.dump(template); +}; From 8c38b0d7523f7be99bd8a8816ab42aed005beb26 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Sat, 21 Oct 2023 22:20:37 +0800 Subject: [PATCH 09/17] image --- service/license/public/images/bg.svg | 2 +- .../license/src/components/signin/index.tsx | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/service/license/public/images/bg.svg b/service/license/public/images/bg.svg index 8d9fcec31aa..9c6a6c47d0a 100644 --- a/service/license/public/images/bg.svg +++ b/service/license/public/images/bg.svg @@ -1,4 +1,4 @@ - + diff --git a/service/license/src/components/signin/index.tsx b/service/license/src/components/signin/index.tsx index 64320b76f04..129613c6ecc 100644 --- a/service/license/src/components/signin/index.tsx +++ b/service/license/src/components/signin/index.tsx @@ -16,6 +16,7 @@ import { TabIndicator, TabList, Tabs, + Image, useDisclosure } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; @@ -104,17 +105,25 @@ export default function SigninComponent() { overflow={'hidden'} w="100vw" h="100vh" - backgroundImage={'url(/images/bg.svg)'} - backgroundRepeat={'no-repeat'} - backgroundSize={'cover'} - backgroundAttachment={'fixed'} - min-width="100%" + // backgroundImage={'url(/images/bg.svg)'} + // backgroundRepeat={'no-repeat'} + // backgroundSize={'cover'} + // backgroundAttachment={'fixed'} + // min-width="100%" // /min-height="100%" // top={0} // left={0} // right={0} // bottom={0} > + sealos Cloud From def2c9badb3a62b63134574a66a62120710fa8a4 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Mon, 23 Oct 2023 14:06:17 +0800 Subject: [PATCH 10/17] fix type bg --- service/license/public/images/background.svg | 178 ------------------ service/license/public/images/bg-bottom.svg | 67 +++++++ service/license/public/images/bg.svg | 145 ++------------ service/license/public/images/logo.svg | 21 +++ service/license/public/images/moon.svg | 37 ++++ .../src/components/signin/background.tsx | 44 +++++ .../license/src/components/signin/index.tsx | 10 +- .../pages/api/license/createLicenseRecord.ts | 7 +- .../src/pages/api/payment/checkWechat.ts | 3 +- .../license/src/pages/api/payment/result.ts | 15 +- .../src/pages/license/components/Record.tsx | 2 +- .../src/services/backend/db/license.ts | 4 +- .../src/services/backend/db/payment.ts | 13 +- service/license/src/types/license.ts | 7 +- service/license/src/utils/json2Yaml.ts | 8 +- 15 files changed, 218 insertions(+), 343 deletions(-) delete mode 100644 service/license/public/images/background.svg create mode 100644 service/license/public/images/bg-bottom.svg create mode 100644 service/license/public/images/logo.svg create mode 100644 service/license/public/images/moon.svg create mode 100644 service/license/src/components/signin/background.tsx diff --git a/service/license/public/images/background.svg b/service/license/public/images/background.svg deleted file mode 100644 index 8b3de7be43f..00000000000 --- a/service/license/public/images/background.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/service/license/public/images/bg-bottom.svg b/service/license/public/images/bg-bottom.svg new file mode 100644 index 00000000000..406b12e2953 --- /dev/null +++ b/service/license/public/images/bg-bottom.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/license/public/images/bg.svg b/service/license/public/images/bg.svg index 9c6a6c47d0a..40796e6aca5 100644 --- a/service/license/public/images/bg.svg +++ b/service/license/public/images/bg.svg @@ -1,152 +1,33 @@ - - - - - - - - - - - - - - - - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - + - + - + - + - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/service/license/public/images/logo.svg b/service/license/public/images/logo.svg new file mode 100644 index 00000000000..96b34363d20 --- /dev/null +++ b/service/license/public/images/logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/service/license/public/images/moon.svg b/service/license/public/images/moon.svg new file mode 100644 index 00000000000..2b4503ca751 --- /dev/null +++ b/service/license/public/images/moon.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/license/src/components/signin/background.tsx b/service/license/src/components/signin/background.tsx new file mode 100644 index 00000000000..7fd3f1b4761 --- /dev/null +++ b/service/license/src/components/signin/background.tsx @@ -0,0 +1,44 @@ +import { Box, Flex, Image, Text } from '@chakra-ui/react'; + +export default function Background() { + return ( + <> + + + + + + + Sealos + + + | License + + + + ); +} diff --git a/service/license/src/components/signin/index.tsx b/service/license/src/components/signin/index.tsx index 129613c6ecc..760d55898d0 100644 --- a/service/license/src/components/signin/index.tsx +++ b/service/license/src/components/signin/index.tsx @@ -26,6 +26,7 @@ import Head from 'next/head'; import { useRouter } from 'next/router'; import sealosTitle from 'public/images/sealos-title.png'; import { useEffect, useMemo, useState } from 'react'; +import Background from './background'; export default function SigninComponent() { const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); @@ -116,14 +117,7 @@ export default function SigninComponent() { // right={0} // bottom={0} > - + sealos Cloud diff --git a/service/license/src/pages/api/license/createLicenseRecord.ts b/service/license/src/pages/api/license/createLicenseRecord.ts index 13d55dafa27..d815bf72f0a 100644 --- a/service/license/src/pages/api/license/createLicenseRecord.ts +++ b/service/license/src/pages/api/license/createLicenseRecord.ts @@ -9,9 +9,9 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse const payload = await authSession(req.headers); if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); - const { orderID, amount, quota, payMethod } = req.body as LicensePayload; + const { orderID, amount, quota, payMethod, type } = req.body as LicensePayload; - const _token = generateLicenseToken({ type: 'Account', data: { amount: quota } }); + const _token = generateLicenseToken({ type: type, data: { amount: quota } }); const record = { uid: payload.uid, @@ -19,7 +19,8 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse token: _token, orderID: orderID, quota: quota, - payMethod: payMethod + payMethod: payMethod, + type: type }; const result = await createLicenseRecord(record); diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts index 0f34711b684..eef89dd54c7 100644 --- a/service/license/src/pages/api/payment/checkWechat.ts +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -48,7 +48,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) payMethod: payment.payMethod, // pay status orderID: payment?.orderID, - status: result.status + status: result.status, + type: 'Account' }); } diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts index c53146edcae..56d974a4ca2 100644 --- a/service/license/src/pages/api/payment/result.ts +++ b/service/license/src/pages/api/payment/result.ts @@ -1,14 +1,6 @@ import { authSession } from '@/services/backend/auth'; -import { - createLicenseRecord, - generateLicenseToken, - hasIssuedLicense -} from '@/services/backend/db/license'; -import { - getPaymentByID, - updatePaymentAndIssueLicense, - updatePaymentStatus -} from '@/services/backend/db/payment'; +import { hasIssuedLicense } from '@/services/backend/db/license'; +import { getPaymentByID, updatePaymentAndIssueLicense } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; import { PaymentResult, PaymentStatus } from '@/types'; @@ -60,7 +52,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) payMethod: payment.payMethod, // pay status orderID: orderID, - status: result.status + status: result.status, + type: 'Account' }); } diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index 4331e587d1b..a28514c7b5e 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -23,7 +23,7 @@ export default function History() { ); const downloadToken = (token: string) => { - download('token.yaml', json2License(token)); + download('token.yaml', json2License({ token: token, type: 'Account' })); }; return ( diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts index bc068359976..2662107da0f 100644 --- a/service/license/src/services/backend/db/license.ts +++ b/service/license/src/services/backend/db/license.ts @@ -15,7 +15,8 @@ export async function createLicenseRecord({ token, orderID, quota, - payMethod + payMethod, + type }: LicenseRecordPayload) { const collection = await connectLicenseRecordCollection(); @@ -33,6 +34,7 @@ export async function createLicenseRecord({ iat: now, // Store the current timestamp as iat exp: now + oneDayInSeconds, // Set expiration to one day from now (in seconds) amount: amount, + type: type, createdAt: new Date(), updatedAt: new Date() }; diff --git a/service/license/src/services/backend/db/payment.ts b/service/license/src/services/backend/db/payment.ts index 8aad469d445..9c0e722b51b 100644 --- a/service/license/src/services/backend/db/payment.ts +++ b/service/license/src/services/backend/db/payment.ts @@ -1,4 +1,4 @@ -import { LicenseRecordPayload, PaymentDB, PaymentStatus, TPayMethod } from '@/types'; +import { LicenseRecordPayload, LicenseType, PaymentDB, PaymentStatus, TPayMethod } from '@/types'; import { connectToDatabase } from './mongodb'; import { createLicenseRecord, generateLicenseToken } from './license'; @@ -57,7 +57,8 @@ export async function updatePaymentAndIssueLicense({ status, amount, quota, - payMethod + payMethod, + type }: { uid: string; orderID: string; @@ -65,6 +66,7 @@ export async function updatePaymentAndIssueLicense({ amount: number; quota: number; payMethod: TPayMethod; + type: LicenseType; }) { const db = await connectToDatabase(); const session = db.startSession(); @@ -85,15 +87,18 @@ export async function updatePaymentAndIssueLicense({ }); // 在事务中执行生成许可证记录操作 - const _token = generateLicenseToken({ type: 'Account', data: { amount: amount } }); + const _token = generateLicenseToken({ type: type, data: { amount: amount } }); const record = { uid: uid, amount: amount, token: _token, orderID: orderID, quota: quota, - payMethod: payMethod + payMethod: payMethod, + type: type }; + console.log(record, 'record'); + await createLicenseRecord(record); await session.commitTransaction(); diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts index 86d5db2fefe..a3e8fe6b827 100644 --- a/service/license/src/types/license.ts +++ b/service/license/src/types/license.ts @@ -12,6 +12,7 @@ export type LicenseDB = { iat: number; // 签发日期 exp: number; // 有效期 amount: number; // 消费金额 + type: LicenseType; // license type createdAt: Date; // Creation timestamp updatedAt: Date; // Modification timestamp }; @@ -23,6 +24,7 @@ export type LicenseRecordPayload = { payMethod: TPayMethod; quota: number; // 额度 amount: number; // 重置金额 + type: LicenseType; }; export type LicensePayload = { @@ -30,12 +32,15 @@ export type LicensePayload = { orderID: string; quota: number; payMethod: TPayMethod; + type: LicenseType; }; // new export type LicenseToken = { - type: 'Account' | 'Cluster'; + type: LicenseType; data: { amount: number; }; }; + +export type LicenseType = 'Account' | 'Cluster'; diff --git a/service/license/src/utils/json2Yaml.ts b/service/license/src/utils/json2Yaml.ts index 5bffa38f88d..a0981998270 100644 --- a/service/license/src/utils/json2Yaml.ts +++ b/service/license/src/utils/json2Yaml.ts @@ -1,15 +1,17 @@ +import { LicenseType } from '@/types'; import yaml from 'js-yaml'; -export const json2License = (token: string) => { +export const json2License = ({ token, type }: { token: string; type: LicenseType }) => { const license_name = crypto.randomUUID(); const template = { - apiVersion: 'infostream.sealos.io/v1', + apiVersion: 'license.sealos.io/v1', kind: 'License', metadata: { name: license_name, - namespace: ' ns-admin' + namespace: 'ns-admin' }, spec: { + type: type, token: token } }; From 5bc2854a9be416cc0b7b8952305dac4adff71bca Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Mon, 23 Oct 2023 15:44:11 +0800 Subject: [PATCH 11/17] env --- service/license/src/pages/api/payment/create.ts | 5 +++-- service/license/src/pages/api/payment/result.ts | 4 ++-- service/license/src/pages/license/components/Recharge.tsx | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/service/license/src/pages/api/payment/create.ts b/service/license/src/pages/api/payment/create.ts index e3811c2b041..77bb820e62b 100644 --- a/service/license/src/pages/api/payment/create.ts +++ b/service/license/src/pages/api/payment/create.ts @@ -19,14 +19,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const result: PaymentData = await fetch(`${sealosPayUrl}/v1alpha1/pay/session`, { method: 'POST', body: JSON.stringify({ - appID: 45141910007488120, - sign: '076f82f8e996d7', + appID: +sealosPayID, + sign: sealosPayKey, amount: amount, currency: currency, user: userInfo.uid, payMethod: payMethod }) }).then((res) => res.json()); + console.log(result, 'PaymentData'); let payRecord: PaymentDB = { ...result, diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts index 56d974a4ca2..ae1ed4ba93a 100644 --- a/service/license/src/pages/api/payment/result.ts +++ b/service/license/src/pages/api/payment/result.ts @@ -34,8 +34,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const result: PaymentResult = await fetch(`${sealosPayUrl}/v1alpha1/pay/status`, { method: 'POST', body: JSON.stringify({ - appID: 45141910007488120, - sign: '076f82f8e996d7', + appID: +sealosPayID, + sign: sealosPayKey, orderID: payment?.orderID, payMethod: payment?.payMethod, tradeNO: payment?.tradeNO, diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index 73b407f943d..bc637ae37f8 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -135,7 +135,6 @@ export default function RechargeComponent() { useQuery(['checkWechatPay'], () => checkWechatPay(), { onSuccess(data) { - console.log(data, 'checkWechatPay'); if (data.status === PaymentStatus.PaymentSuccess) { toast({ status: 'success', From 7932751d817b4036b9f185caa467f710bc00ac36 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Tue, 24 Oct 2023 15:15:15 +0800 Subject: [PATCH 12/17] add oss Signed-off-by: jingyang <3161362058@qq.com> --- service/license/package.json | 1 + service/license/pnpm-lock.yaml | 523 +++++++++++++++++- service/license/src/api/oos.ts | 4 + service/license/src/pages/api/oss/get.ts | 30 + service/license/src/pages/cluster/index.tsx | 1 + .../src/pages/license/components/Record.tsx | 2 +- service/license/src/pages/license/index.tsx | 12 + service/license/src/pages/pricing/index.tsx | 0 service/license/src/utils/downloadFIle.ts | 15 +- 9 files changed, 578 insertions(+), 10 deletions(-) create mode 100644 service/license/src/api/oos.ts create mode 100644 service/license/src/pages/api/oss/get.ts create mode 100644 service/license/src/pages/cluster/index.tsx create mode 100644 service/license/src/pages/pricing/index.tsx diff --git a/service/license/package.json b/service/license/package.json index 23c812de728..428f88d43d6 100644 --- a/service/license/package.json +++ b/service/license/package.json @@ -17,6 +17,7 @@ "@emotion/styled": "^11.11.0", "@stripe/stripe-js": "^2.1.9", "@tanstack/react-query": "^4.36.1", + "ali-oss": "^6.18.1", "axios": "^1.5.1", "clsx": "^2.0.0", "dayjs": "^1.11.10", diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml index 250c7fb9ab7..cf7ab2a54bd 100644 --- a/service/license/pnpm-lock.yaml +++ b/service/license/pnpm-lock.yaml @@ -29,6 +29,9 @@ dependencies: '@tanstack/react-query': specifier: ^4.36.1 version: registry.npmmirror.com/@tanstack/react-query@4.36.1(react-dom@18.0.0)(react@18.0.0) + ali-oss: + specifier: ^6.18.1 + version: registry.npmmirror.com/ali-oss@6.18.1 axios: specifier: ^1.5.1 version: registry.npmmirror.com/axios@1.5.1 @@ -2303,6 +2306,22 @@ packages: hasBin: true dev: true + registry.npmmirror.com/address@1.2.2: + resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/address/-/address-1.2.2.tgz} + name: address + version: 1.2.2 + engines: {node: '>= 10.0.0'} + dev: false + + registry.npmmirror.com/agentkeepalive@3.5.2: + resolution: {integrity: sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz} + name: agentkeepalive + version: 3.5.2 + engines: {node: '>= 4.0.0'} + dependencies: + humanize-ms: registry.npmmirror.com/humanize-ms@1.2.1 + dev: false + registry.npmmirror.com/ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz} name: ajv @@ -2314,6 +2333,40 @@ packages: uri-js: registry.npmmirror.com/uri-js@4.4.1 dev: true + registry.npmmirror.com/ali-oss@6.18.1: + resolution: {integrity: sha512-VsptD0jX3JNc3AjiLs5a9oTP0ArfT9IYhBuY6G/SpuY6LMuiwfqywrAosY65BlHKODAdYy8VWL6kmt0mO7BUGA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ali-oss/-/ali-oss-6.18.1.tgz} + name: ali-oss + version: 6.18.1 + engines: {node: '>=8'} + dependencies: + address: registry.npmmirror.com/address@1.2.2 + agentkeepalive: registry.npmmirror.com/agentkeepalive@3.5.2 + bowser: registry.npmmirror.com/bowser@1.9.4 + copy-to: registry.npmmirror.com/copy-to@2.0.1 + dateformat: registry.npmmirror.com/dateformat@2.2.0 + debug: registry.npmmirror.com/debug@4.3.4 + destroy: registry.npmmirror.com/destroy@1.2.0 + end-or-error: registry.npmmirror.com/end-or-error@1.0.1 + get-ready: registry.npmmirror.com/get-ready@1.0.0 + humanize-ms: registry.npmmirror.com/humanize-ms@1.2.1 + is-type-of: registry.npmmirror.com/is-type-of@1.4.0 + js-base64: registry.npmmirror.com/js-base64@2.6.4 + jstoxml: registry.npmmirror.com/jstoxml@2.2.9 + merge-descriptors: registry.npmmirror.com/merge-descriptors@1.0.1 + mime: registry.npmmirror.com/mime@2.6.0 + platform: registry.npmmirror.com/platform@1.3.6 + pump: registry.npmmirror.com/pump@3.0.0 + sdk-base: registry.npmmirror.com/sdk-base@2.0.1 + stream-http: registry.npmmirror.com/stream-http@2.8.2 + stream-wormhole: registry.npmmirror.com/stream-wormhole@1.1.0 + urllib: registry.npmmirror.com/urllib@2.41.0 + utility: registry.npmmirror.com/utility@1.18.0 + xml2js: registry.npmmirror.com/xml2js@0.6.2 + transitivePeerDependencies: + - proxy-agent + - supports-color + dev: false + registry.npmmirror.com/ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz} name: ansi-colors @@ -2346,6 +2399,12 @@ packages: color-convert: registry.npmmirror.com/color-convert@2.0.1 dev: true + registry.npmmirror.com/any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz} + name: any-promise + version: 1.3.0 + dev: false + registry.npmmirror.com/argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz} name: argparse @@ -2554,6 +2613,12 @@ packages: readable-stream: registry.npmmirror.com/readable-stream@3.6.2 dev: false + registry.npmmirror.com/bowser@1.9.4: + resolution: {integrity: sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/bowser/-/bowser-1.9.4.tgz} + name: bowser + version: 1.9.4 + dev: false + registry.npmmirror.com/brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz} name: brace-expansion @@ -2594,6 +2659,12 @@ packages: ieee754: registry.npmmirror.com/ieee754@1.2.1 dev: false + registry.npmmirror.com/builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz} + name: builtin-status-codes + version: 3.0.0 + dev: false + registry.npmmirror.com/busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz} name: busboy @@ -2610,7 +2681,6 @@ packages: dependencies: function-bind: registry.npmmirror.com/function-bind@1.1.2 get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 - dev: true registry.npmmirror.com/callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz} @@ -2737,6 +2807,13 @@ packages: version: 0.0.1 dev: true + registry.npmmirror.com/content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz} + name: content-type + version: 1.0.5 + engines: {node: '>= 0.6'} + dev: false + registry.npmmirror.com/convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz} name: convert-source-map @@ -2751,6 +2828,12 @@ packages: toggle-selection: registry.npmmirror.com/toggle-selection@1.0.6 dev: false + registry.npmmirror.com/copy-to@2.0.1: + resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/copy-to/-/copy-to-2.0.1.tgz} + name: copy-to + version: 2.0.1 + dev: false + registry.npmmirror.com/core-js@3.33.0: resolution: {integrity: sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/core-js/-/core-js-3.33.0.tgz} name: core-js @@ -2758,6 +2841,12 @@ packages: requiresBuild: true dev: false + registry.npmmirror.com/core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz} + name: core-util-is + version: 1.0.3 + dev: false + registry.npmmirror.com/cosmiconfig@7.1.0: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz} name: cosmiconfig @@ -2801,12 +2890,31 @@ packages: version: 1.0.8 dev: true + registry.npmmirror.com/dateformat@2.2.0: + resolution: {integrity: sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dateformat/-/dateformat-2.2.0.tgz} + name: dateformat + version: 2.2.0 + dev: false + registry.npmmirror.com/dayjs@1.11.10: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz} name: dayjs version: 1.11.10 dev: false + registry.npmmirror.com/debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz} + name: debug + version: 2.6.9 + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: registry.npmmirror.com/ms@2.0.0 + dev: false + registry.npmmirror.com/debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz} name: debug @@ -2855,6 +2963,15 @@ packages: version: 0.1.4 dev: true + registry.npmmirror.com/default-user-agent@1.0.0: + resolution: {integrity: sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/default-user-agent/-/default-user-agent-1.0.0.tgz} + name: default-user-agent + version: 1.0.0 + engines: {node: '>= 0.10.0'} + dependencies: + os-name: registry.npmmirror.com/os-name@1.0.3 + dev: false + registry.npmmirror.com/define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.1.tgz} name: define-data-property @@ -2891,6 +3008,13 @@ packages: engines: {node: '>=6'} dev: true + registry.npmmirror.com/destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz} + name: destroy + version: 1.2.0 + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: false + registry.npmmirror.com/detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/detect-libc/-/detect-libc-2.0.2.tgz} name: detect-libc @@ -2904,6 +3028,13 @@ packages: version: 1.1.0 dev: false + registry.npmmirror.com/digest-header@1.1.0: + resolution: {integrity: sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/digest-header/-/digest-header-1.1.0.tgz} + name: digest-header + version: 1.1.0 + engines: {node: '>= 8.0.0'} + dev: false + registry.npmmirror.com/dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz} name: dir-glob @@ -2939,6 +3070,12 @@ packages: safe-buffer: registry.npmmirror.com/safe-buffer@5.2.1 dev: false + registry.npmmirror.com/ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz} + name: ee-first + version: 1.1.1 + dev: false + registry.npmmirror.com/emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz} name: emoji-regex @@ -2953,6 +3090,13 @@ packages: once: registry.npmmirror.com/once@1.4.0 dev: false + registry.npmmirror.com/end-or-error@1.0.1: + resolution: {integrity: sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/end-or-error/-/end-or-error-1.0.1.tgz} + name: end-or-error + version: 1.0.1 + engines: {node: '>= 0.11.14'} + dev: false + registry.npmmirror.com/enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz} name: enhanced-resolve @@ -3079,6 +3223,12 @@ packages: is-symbol: registry.npmmirror.com/is-symbol@1.0.4 dev: true + registry.npmmirror.com/escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz} + name: escape-html + version: 1.0.3 + dev: false + registry.npmmirror.com/escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz} name: escape-string-regexp @@ -3433,6 +3583,15 @@ packages: engines: {node: '>=6'} dev: false + registry.npmmirror.com/extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz} + name: extend-shallow + version: 2.0.1 + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: registry.npmmirror.com/is-extendable@0.1.1 + dev: false + registry.npmmirror.com/fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz} name: fast-deep-equal @@ -3559,6 +3718,16 @@ packages: mime-types: registry.npmmirror.com/mime-types@2.1.35 dev: false + registry.npmmirror.com/formstream@1.3.1: + resolution: {integrity: sha512-FkW++ub+VbE5dpwukJVDizNWhSgp8FhmhI65pF7BZSVStBqe6Wgxe2Z9/Vhsn7l7nXCPwP+G1cyYlX8VwWOf0g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/formstream/-/formstream-1.3.1.tgz} + name: formstream + version: 1.3.1 + dependencies: + destroy: registry.npmmirror.com/destroy@1.2.0 + mime: registry.npmmirror.com/mime@2.6.0 + pause-stream: registry.npmmirror.com/pause-stream@0.0.11 + dev: false + registry.npmmirror.com/framer-motion@10.16.4(react-dom@18.0.0)(react@18.0.0): resolution: {integrity: sha512-p9V9nGomS3m6/CALXqv6nFGMuFOxbWsmaOrdmhyQimMIlLl3LC7h7l86wge/Js/8cRu5ktutS/zlzgR7eBOtFA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/framer-motion/-/framer-motion-10.16.4.tgz} id: registry.npmmirror.com/framer-motion/10.16.4 @@ -3604,7 +3773,6 @@ packages: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz} name: function-bind version: 1.1.2 - dev: true registry.npmmirror.com/function.prototype.name@1.1.6: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz} @@ -3639,7 +3807,6 @@ packages: has: registry.npmmirror.com/has@1.0.4 has-proto: registry.npmmirror.com/has-proto@1.0.1 has-symbols: registry.npmmirror.com/has-symbols@1.0.3 - dev: true registry.npmmirror.com/get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-nonce/-/get-nonce-1.0.1.tgz} @@ -3648,6 +3815,12 @@ packages: engines: {node: '>=6'} dev: false + registry.npmmirror.com/get-ready@1.0.0: + resolution: {integrity: sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-ready/-/get-ready-1.0.0.tgz} + name: get-ready + version: 1.0.0 + dev: false + registry.npmmirror.com/get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz} name: get-symbol-description @@ -3800,14 +3973,12 @@ packages: name: has-proto version: 1.0.1 engines: {node: '>= 0.4'} - dev: true registry.npmmirror.com/has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz} name: has-symbols version: 1.0.3 engines: {node: '>= 0.4'} - dev: true registry.npmmirror.com/has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz} @@ -3851,6 +4022,14 @@ packages: - supports-color dev: false + registry.npmmirror.com/humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz} + name: humanize-ms + version: 1.2.1 + dependencies: + ms: registry.npmmirror.com/ms@2.1.3 + dev: false + registry.npmmirror.com/i18next-fs-backend@2.2.0: resolution: {integrity: sha512-VOPHhdDX0M/csRqEw+9Ectpf6wvTIg1MZDfAHxc3JKnAlJz7fcZSAKAeyDohOq0xuLx57esYpJopIvBaRb0Bag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/i18next-fs-backend/-/i18next-fs-backend-2.2.0.tgz} name: i18next-fs-backend @@ -3865,6 +4044,15 @@ packages: '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 dev: false + registry.npmmirror.com/iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz} + name: iconv-lite + version: 0.4.24 + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: registry.npmmirror.com/safer-buffer@2.1.2 + dev: false + registry.npmmirror.com/ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz} name: ieee754 @@ -3946,6 +4134,12 @@ packages: loose-envify: registry.npmmirror.com/loose-envify@1.4.0 dev: false + registry.npmmirror.com/ip@1.1.8: + resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ip/-/ip-1.1.8.tgz} + name: ip + version: 1.1.8 + dev: false + registry.npmmirror.com/is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz} name: is-array-buffer @@ -4002,6 +4196,12 @@ packages: engines: {node: '>= 0.4'} dev: true + registry.npmmirror.com/is-class-hotfix@0.0.6: + resolution: {integrity: sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz} + name: is-class-hotfix + version: 0.0.6 + dev: false + registry.npmmirror.com/is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.0.tgz} name: is-core-module @@ -4018,6 +4218,13 @@ packages: has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 dev: true + registry.npmmirror.com/is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz} + name: is-extendable + version: 0.1.1 + engines: {node: '>=0.10.0'} + dev: false + registry.npmmirror.com/is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz} name: is-extglob @@ -4122,6 +4329,16 @@ packages: has-symbols: registry.npmmirror.com/has-symbols@1.0.3 dev: true + registry.npmmirror.com/is-type-of@1.4.0: + resolution: {integrity: sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-type-of/-/is-type-of-1.4.0.tgz} + name: is-type-of + version: 1.4.0 + dependencies: + core-util-is: registry.npmmirror.com/core-util-is@1.0.3 + is-class-hotfix: registry.npmmirror.com/is-class-hotfix@0.0.6 + isstream: registry.npmmirror.com/isstream@0.1.2 + dev: false + registry.npmmirror.com/is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.12.tgz} name: is-typed-array @@ -4154,6 +4371,12 @@ packages: get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 dev: true + registry.npmmirror.com/isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz} + name: isarray + version: 1.0.0 + dev: false + registry.npmmirror.com/isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz} name: isarray @@ -4166,6 +4389,12 @@ packages: version: 2.0.0 dev: true + registry.npmmirror.com/isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz} + name: isstream + version: 0.1.2 + dev: false + registry.npmmirror.com/iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz} name: iterator.prototype @@ -4178,6 +4407,12 @@ packages: set-function-name: registry.npmmirror.com/set-function-name@2.0.1 dev: true + registry.npmmirror.com/js-base64@2.6.4: + resolution: {integrity: sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-base64/-/js-base64-2.6.4.tgz} + name: js-base64 + version: 2.6.4 + dev: false + registry.npmmirror.com/js-cookie@3.0.5: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz} name: js-cookie @@ -4249,6 +4484,12 @@ packages: semver: registry.npmmirror.com/semver@7.5.4 dev: false + registry.npmmirror.com/jstoxml@2.2.9: + resolution: {integrity: sha512-OYWlK0j+roh+eyaMROlNbS5cd5R25Y+IUpdl7cNdB8HNrkgwQzIS7L9MegxOiWNBj9dQhA/yAxiMwCC5mwNoBw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jstoxml/-/jstoxml-2.2.9.tgz} + name: jstoxml + version: 2.2.9 + dev: false + registry.npmmirror.com/jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz} name: jsx-ast-utils @@ -4408,6 +4649,12 @@ packages: version: 1.5.0 dev: false + registry.npmmirror.com/merge-descriptors@1.0.1: + resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz} + name: merge-descriptors + version: 1.0.1 + dev: false + registry.npmmirror.com/merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz} name: merge2 @@ -4441,6 +4688,14 @@ packages: mime-db: registry.npmmirror.com/mime-db@1.52.0 dev: false + registry.npmmirror.com/mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz} + name: mime + version: 2.6.0 + engines: {node: '>=4.0.0'} + hasBin: true + dev: false + registry.npmmirror.com/mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz} name: mimic-response @@ -4467,6 +4722,15 @@ packages: version: 0.5.3 dev: false + registry.npmmirror.com/mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz} + name: mkdirp + version: 0.5.6 + hasBin: true + dependencies: + minimist: registry.npmmirror.com/minimist@1.2.8 + dev: false + registry.npmmirror.com/mongodb-connection-string-url@2.6.0: resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz} name: mongodb-connection-string-url @@ -4510,6 +4774,12 @@ packages: mongodb-connection-string-url: registry.npmmirror.com/mongodb-connection-string-url@2.6.0 dev: false + registry.npmmirror.com/ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz} + name: ms + version: 2.0.0 + dev: false + registry.npmmirror.com/ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz} name: ms @@ -4520,6 +4790,16 @@ packages: name: ms version: 2.1.3 + registry.npmmirror.com/mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz} + name: mz + version: 2.7.0 + dependencies: + any-promise: registry.npmmirror.com/any-promise@1.3.0 + object-assign: registry.npmmirror.com/object-assign@4.1.1 + thenify-all: registry.npmmirror.com/thenify-all@1.6.0 + dev: false + registry.npmmirror.com/nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz} name: nanoid @@ -4636,7 +4916,6 @@ packages: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz} name: object-inspect version: 1.12.3 - dev: true registry.npmmirror.com/object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz} @@ -4731,6 +5010,27 @@ packages: type-check: registry.npmmirror.com/type-check@0.4.0 dev: true + registry.npmmirror.com/os-name@1.0.3: + resolution: {integrity: sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/os-name/-/os-name-1.0.3.tgz} + name: os-name + version: 1.0.3 + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + osx-release: registry.npmmirror.com/osx-release@1.1.0 + win-release: registry.npmmirror.com/win-release@1.1.1 + dev: false + + registry.npmmirror.com/osx-release@1.1.0: + resolution: {integrity: sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/osx-release/-/osx-release-1.1.0.tgz} + name: osx-release + version: 1.1.0 + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + minimist: registry.npmmirror.com/minimist@1.2.8 + dev: false + registry.npmmirror.com/parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz} name: parent-module @@ -4776,6 +5076,14 @@ packages: version: 4.0.0 engines: {node: '>=8'} + registry.npmmirror.com/pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pause-stream/-/pause-stream-0.0.11.tgz} + name: pause-stream + version: 0.0.11 + dependencies: + through: registry.npmmirror.com/through@2.3.8 + dev: false + registry.npmmirror.com/picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz} name: picocolors @@ -4789,6 +5097,12 @@ packages: engines: {node: '>=8.6'} dev: true + registry.npmmirror.com/platform@1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/platform/-/platform-1.3.6.tgz} + name: platform + version: 1.3.6 + dev: false + registry.npmmirror.com/postcss@8.4.31: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/postcss/-/postcss-8.4.31.tgz} name: postcss @@ -4836,6 +5150,12 @@ packages: hasBin: true dev: true + registry.npmmirror.com/process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz} + name: process-nextick-args + version: 2.0.1 + dev: false + registry.npmmirror.com/progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/progress/-/progress-2.0.3.tgz} name: progress @@ -4884,6 +5204,15 @@ packages: react: registry.npmmirror.com/react@18.0.0 dev: false + registry.npmmirror.com/qs@6.11.2: + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz} + name: qs + version: 6.11.2 + engines: {node: '>=0.6'} + dependencies: + side-channel: registry.npmmirror.com/side-channel@1.0.4 + dev: false + registry.npmmirror.com/queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz} name: queue-microtask @@ -5071,6 +5400,20 @@ packages: loose-envify: registry.npmmirror.com/loose-envify@1.4.0 dev: false + registry.npmmirror.com/readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz} + name: readable-stream + version: 2.3.8 + dependencies: + core-util-is: registry.npmmirror.com/core-util-is@1.0.3 + inherits: registry.npmmirror.com/inherits@2.0.4 + isarray: registry.npmmirror.com/isarray@1.0.0 + process-nextick-args: registry.npmmirror.com/process-nextick-args@2.0.1 + safe-buffer: registry.npmmirror.com/safe-buffer@5.1.2 + string_decoder: registry.npmmirror.com/string_decoder@1.1.1 + util-deprecate: registry.npmmirror.com/util-deprecate@1.0.2 + dev: false + registry.npmmirror.com/readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz} name: readable-stream @@ -5188,6 +5531,12 @@ packages: isarray: registry.npmmirror.com/isarray@2.0.5 dev: true + registry.npmmirror.com/safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz} + name: safe-buffer + version: 5.1.2 + dev: false + registry.npmmirror.com/safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz} name: safe-buffer @@ -5204,6 +5553,12 @@ packages: is-regex: registry.npmmirror.com/is-regex@1.1.4 dev: true + registry.npmmirror.com/safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz} + name: safer-buffer + version: 2.1.2 + dev: false + registry.npmmirror.com/sax@1.3.0: resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sax/-/sax-1.3.0.tgz} name: sax @@ -5218,6 +5573,21 @@ packages: loose-envify: registry.npmmirror.com/loose-envify@1.4.0 dev: false + registry.npmmirror.com/sdk-base@2.0.1: + resolution: {integrity: sha512-eeG26wRwhtwYuKGCDM3LixCaxY27Pa/5lK4rLKhQa7HBjJ3U3Y+f81MMZQRsDw/8SC2Dao/83yJTXJ8aULuN8Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sdk-base/-/sdk-base-2.0.1.tgz} + name: sdk-base + version: 2.0.1 + dependencies: + get-ready: registry.npmmirror.com/get-ready@1.0.0 + dev: false + + registry.npmmirror.com/semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz} + name: semver + version: 5.7.2 + hasBin: true + dev: false + registry.npmmirror.com/semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz} name: semver @@ -5286,7 +5656,6 @@ packages: call-bind: registry.npmmirror.com/call-bind@1.0.2 get-intrinsic: registry.npmmirror.com/get-intrinsic@1.2.1 object-inspect: registry.npmmirror.com/object-inspect@1.12.3 - dev: true registry.npmmirror.com/simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz} @@ -5347,6 +5716,32 @@ packages: memory-pager: registry.npmmirror.com/memory-pager@1.5.0 dev: false + registry.npmmirror.com/statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/statuses/-/statuses-1.5.0.tgz} + name: statuses + version: 1.5.0 + engines: {node: '>= 0.6'} + dev: false + + registry.npmmirror.com/stream-http@2.8.2: + resolution: {integrity: sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/stream-http/-/stream-http-2.8.2.tgz} + name: stream-http + version: 2.8.2 + dependencies: + builtin-status-codes: registry.npmmirror.com/builtin-status-codes@3.0.0 + inherits: registry.npmmirror.com/inherits@2.0.4 + readable-stream: registry.npmmirror.com/readable-stream@2.3.8 + to-arraybuffer: registry.npmmirror.com/to-arraybuffer@1.0.1 + xtend: registry.npmmirror.com/xtend@4.0.2 + dev: false + + registry.npmmirror.com/stream-wormhole@1.1.0: + resolution: {integrity: sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/stream-wormhole/-/stream-wormhole-1.1.0.tgz} + name: stream-wormhole + version: 1.1.0 + engines: {node: '>=4.0.0'} + dev: false + registry.npmmirror.com/streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz} name: streamsearch @@ -5410,6 +5805,14 @@ packages: es-abstract: registry.npmmirror.com/es-abstract@1.22.2 dev: true + registry.npmmirror.com/string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz} + name: string_decoder + version: 1.1.1 + dependencies: + safe-buffer: registry.npmmirror.com/safe-buffer@5.1.2 + dev: false + registry.npmmirror.com/string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz} name: string_decoder @@ -5555,12 +5958,41 @@ packages: version: 0.2.0 dev: true + registry.npmmirror.com/thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz} + name: thenify-all + version: 1.6.0 + engines: {node: '>=0.8'} + dependencies: + thenify: registry.npmmirror.com/thenify@3.3.1 + dev: false + + registry.npmmirror.com/thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz} + name: thenify + version: 3.3.1 + dependencies: + any-promise: registry.npmmirror.com/any-promise@1.3.0 + dev: false + + registry.npmmirror.com/through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/through/-/through-2.3.8.tgz} + name: through + version: 2.3.8 + dev: false + registry.npmmirror.com/tiny-invariant@1.3.1: resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz} name: tiny-invariant version: 1.3.1 dev: false + registry.npmmirror.com/to-arraybuffer@1.0.1: + resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz} + name: to-arraybuffer + version: 1.0.1 + dev: false + registry.npmmirror.com/to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz} name: to-fast-properties @@ -5716,6 +6148,15 @@ packages: which-boxed-primitive: registry.npmmirror.com/which-boxed-primitive@1.0.2 dev: true + registry.npmmirror.com/unescape@1.0.1: + resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/unescape/-/unescape-1.0.1.tgz} + name: unescape + version: 1.0.1 + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: registry.npmmirror.com/extend-shallow@2.0.1 + dev: false + registry.npmmirror.com/uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz} name: uri-js @@ -5724,6 +6165,35 @@ packages: punycode: registry.npmmirror.com/punycode@2.3.0 dev: true + registry.npmmirror.com/urllib@2.41.0: + resolution: {integrity: sha512-pNXdxEv52L67jahLT+/7QE+Fup1y2Gc6EdmrAhQ6OpQIC2rl14oWwv9hvk1GXOZqEnJNwRXHABuwgPOs1CtL7g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/urllib/-/urllib-2.41.0.tgz} + name: urllib + version: 2.41.0 + engines: {node: '>= 0.10.0'} + peerDependencies: + proxy-agent: ^5.0.0 + peerDependenciesMeta: + proxy-agent: + optional: true + dependencies: + any-promise: registry.npmmirror.com/any-promise@1.3.0 + content-type: registry.npmmirror.com/content-type@1.0.5 + debug: registry.npmmirror.com/debug@2.6.9 + default-user-agent: registry.npmmirror.com/default-user-agent@1.0.0 + digest-header: registry.npmmirror.com/digest-header@1.1.0 + ee-first: registry.npmmirror.com/ee-first@1.1.1 + formstream: registry.npmmirror.com/formstream@1.3.1 + humanize-ms: registry.npmmirror.com/humanize-ms@1.2.1 + iconv-lite: registry.npmmirror.com/iconv-lite@0.4.24 + ip: registry.npmmirror.com/ip@1.1.8 + pump: registry.npmmirror.com/pump@3.0.0 + qs: registry.npmmirror.com/qs@6.11.2 + statuses: registry.npmmirror.com/statuses@1.5.0 + utility: registry.npmmirror.com/utility@1.18.0 + transitivePeerDependencies: + - supports-color + dev: false + registry.npmmirror.com/use-callback-ref@1.3.0(@types/react@18.0.0)(react@18.0.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz} id: registry.npmmirror.com/use-callback-ref/1.3.0 @@ -5778,6 +6248,19 @@ packages: version: 1.0.2 dev: false + registry.npmmirror.com/utility@1.18.0: + resolution: {integrity: sha512-PYxZDA+6QtvRvm//++aGdmKG/cI07jNwbROz0Ql+VzFV1+Z0Dy55NI4zZ7RHc9KKpBePNFwoErqIuqQv/cjiTA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/utility/-/utility-1.18.0.tgz} + name: utility + version: 1.18.0 + engines: {node: '>= 0.12.0'} + dependencies: + copy-to: registry.npmmirror.com/copy-to@2.0.1 + escape-html: registry.npmmirror.com/escape-html@1.0.3 + mkdirp: registry.npmmirror.com/mkdirp@0.5.6 + mz: registry.npmmirror.com/mz@2.7.0 + unescape: registry.npmmirror.com/unescape@1.0.1 + dev: false + registry.npmmirror.com/uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz} name: uuid @@ -5891,6 +6374,15 @@ packages: isexe: registry.npmmirror.com/isexe@2.0.0 dev: true + registry.npmmirror.com/win-release@1.1.1: + resolution: {integrity: sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/win-release/-/win-release-1.1.1.tgz} + name: win-release + version: 1.1.1 + engines: {node: '>=0.10.0'} + dependencies: + semver: registry.npmmirror.com/semver@5.7.2 + dev: false + registry.npmmirror.com/wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz} name: wrappy @@ -5906,6 +6398,16 @@ packages: xmlbuilder: registry.npmmirror.com/xmlbuilder@11.0.1 dev: false + registry.npmmirror.com/xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xml2js/-/xml2js-0.6.2.tgz} + name: xml2js + version: 0.6.2 + engines: {node: '>=4.0.0'} + dependencies: + sax: registry.npmmirror.com/sax@1.3.0 + xmlbuilder: registry.npmmirror.com/xmlbuilder@11.0.1 + dev: false + registry.npmmirror.com/xmlbuilder@11.0.1: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz} name: xmlbuilder @@ -5913,6 +6415,13 @@ packages: engines: {node: '>=4.0'} dev: false + registry.npmmirror.com/xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz} + name: xtend + version: 4.0.2 + engines: {node: '>=0.4'} + dev: false + registry.npmmirror.com/yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz} name: yallist diff --git a/service/license/src/api/oos.ts b/service/license/src/api/oos.ts new file mode 100644 index 00000000000..2463c345cd6 --- /dev/null +++ b/service/license/src/api/oos.ts @@ -0,0 +1,4 @@ +import { GET, POST } from '@/services/request'; +import { LicensePayload, LicenseDB } from '@/types'; + +export const getFileByName = (fileName: string) => POST('/api/oss/get', { fileName: fileName }); diff --git a/service/license/src/pages/api/oss/get.ts b/service/license/src/pages/api/oss/get.ts new file mode 100644 index 00000000000..c467f1b772b --- /dev/null +++ b/service/license/src/pages/api/oss/get.ts @@ -0,0 +1,30 @@ +import { authSession } from '@/services/backend/auth'; +import { jsonRes } from '@/services/backend/response'; +import type { NextApiRequest, NextApiResponse } from 'next'; +const OSS = require('ali-oss'); +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { fileName } = req.body as { fileName: string }; + + const userInfo = await authSession(req.headers); + if (!userInfo) return jsonRes(res, { code: 401, message: 'token verify error' }); + + const client = new OSS({ + region: 'oss-cn-hangzhou', + accessKeyId: process.env.ALI_OSS_KEY_ID, + accessKeySecret: process.env.ALI_OSS_KEY_SECRET, + bucket: 'sealos-io' + }); + // 生成用于下载文件的签名URL。 + const url = client.signatureUrl(fileName, { + // expires: 30 * 60 // 默认30分钟 最长60分钟 + }); + + return jsonRes(res, { + data: url + }); + } catch (error) { + console.error(error); + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/cluster/index.tsx b/service/license/src/pages/cluster/index.tsx new file mode 100644 index 00000000000..089d34917cb --- /dev/null +++ b/service/license/src/pages/cluster/index.tsx @@ -0,0 +1 @@ +export default function Cluster() {} diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index a28514c7b5e..12320f54a02 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -1,6 +1,6 @@ import { getLicenseRecord } from '@/api/license'; import { DownloadIcon, EmptyIcon, LicenseIcon, TokenIcon } from '@/components/icons'; -import download from '@/utils/downloadFIle'; +import { download } from '@/utils/downloadFIle'; import { formatMoney, getRemainingTime } from '@/utils/tools'; import { Box, Flex, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx index 6d486d0a72a..26e2cfa0399 100644 --- a/service/license/src/pages/license/index.tsx +++ b/service/license/src/pages/license/index.tsx @@ -6,6 +6,8 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { useRouter } from 'next/router'; import RechargeComponent from './components/Recharge'; import LicenseRecord from './components/Record'; +import { getFileByName } from '@/api/oos'; +import { downloadFromURL } from '@/utils/downloadFIle'; export default function LicensePage() { const { t } = useTranslation(); @@ -14,6 +16,16 @@ export default function LicensePage() { return ( + {/* { + getFileByName('token.txt').then((res) => { + console.log(res); + downloadFromURL(res); + }); + }} + > + ceshi + */} Date: Wed, 25 Oct 2023 10:54:57 +0800 Subject: [PATCH 13/17] done Signed-off-by: jingyang <3161362058@qq.com> cluster done Signed-off-by: jingyang <3161362058@qq.com> done Signed-off-by: jingyang <3161362058@qq.com> cluster done Signed-off-by: jingyang <3161362058@qq.com> done cluster Signed-off-by: jingyang <3161362058@qq.com> done Signed-off-by: jingyang <3161362058@qq.com> --- service/license/.env.template | 4 +- service/license/package.json | 2 + service/license/pnpm-lock.yaml | 194 ++++++++ service/license/public/locales/en/common.json | 16 +- service/license/public/locales/zh/common.json | 16 +- service/license/src/api/cluster.ts | 17 + service/license/src/api/license.ts | 9 +- service/license/src/api/oos.ts | 4 +- service/license/src/api/payment.ts | 4 +- .../src/components/CodeBlock/index.tsx | 32 ++ .../components/{icons => Icon}/CancelIcon.tsx | 0 .../license/src/components/Icon/CheckIcon.tsx | 22 + .../src/components/Icon/CheckListIcon.tsx | 21 + .../components/{icons => Icon}/CloseIcon.tsx | 0 .../src/components/Icon/ClusterIcon.tsx | 32 ++ .../{icons => Icon}/CodeDoneIcon.tsx | 1 + .../license/src/components/Icon/CopyIcon.tsx | 21 + .../components/{icons => Icon}/CopyLink.tsx | 0 .../components/{icons => Icon}/DeleteIcon.tsx | 0 .../{icons => Icon}/DownloadIcon.tsx | 5 +- .../components/{icons => Icon}/EmptyIcon.tsx | 1 + .../{icons => Icon}/ExchangeIcon.tsx | 0 .../components/{icons => Icon}/GithubIcon.tsx | 0 .../components/{icons => Icon}/GoogleIcon.tsx | 0 .../components/{icons => Icon}/GroupAdd.tsx | 0 .../components/{icons => Icon}/HomePage.tsx | 2 +- .../components/{icons => Icon}/HtmlIcon.tsx | 0 .../{icons => Icon}/LicenseIcon.tsx | 1 + .../components/{icons => Icon}/LockIcon.tsx | 0 .../src/components/{icons => Icon}/MdIcon.tsx | 0 .../src/components/Icon/OfflineIcon.tsx | 19 + .../components/Icon/OnlineComputerIcon.tsx | 19 + .../components/{icons => Icon}/PersonIcon.tsx | 0 .../RightArrow.tsx => Icon/RightIcon.tsx} | 0 .../components/{icons => Icon}/SafetyIcon.tsx | 0 .../src/components/{icons => Icon}/Share.tsx | 0 .../{icons => Icon}/SignOutIcon.tsx | 1 + .../license/src/components/Icon/StarIcon.tsx | 19 + .../components/{icons => Icon}/StripeIcon.tsx | 1 + .../src/components/Icon/SuccessIcon.tsx | 16 + .../components/{icons => Icon}/TokenIcon.tsx | 1 + .../components/{icons => Icon}/VectorIcon.tsx | 9 +- .../{icons => Icon}/WarningIcon.tsx | 0 .../components/{icons => Icon}/WechatIcon.tsx | 0 .../src/components/{icons => Icon}/index.ts | 10 +- .../license/src/components/Layout/index.tsx | 82 ++++ .../Pagination/index.tsx} | 0 .../WechatPayment/index.tsx} | 2 +- .../license/src/components/account/index.tsx | 2 +- .../components/icons/DownloadIcon copy 3.tsx | 14 - .../components/signin/auth/useAuthList.tsx | 2 +- .../components/signin/auth/useCustomError.tsx | 2 +- .../components/signin/auth/usePassword.tsx | 2 +- .../src/components/signin/auth/useSms.tsx | 2 +- .../license/src/components/signin/index.tsx | 14 +- service/license/src/constant/product.ts | 57 +++ service/license/src/pages/404.tsx | 1 + service/license/src/pages/_app.tsx | 16 +- .../pages/api/cluster/clusterAndLicense.ts | 55 +++ .../license/src/pages/api/cluster/create.ts | 27 + .../license/src/pages/api/cluster/findById.ts | 28 ++ .../src/pages/api/cluster/getRecord.ts | 28 ++ .../license/src/pages/api/license/create.ts | 54 ++ .../pages/api/license/createLicenseRecord.ts | 34 -- .../{getLicenseRecord.ts => getRecord.ts} | 8 +- service/license/src/pages/api/oss/get.ts | 15 +- .../src/pages/api/payment/checkWechat.ts | 26 +- .../license/src/pages/api/payment/create.ts | 16 +- .../license/src/pages/api/payment/result.ts | 29 +- service/license/src/pages/api/price/bonus.ts | 8 +- .../src/pages/cluster/components/Record.tsx | 111 +++++ .../src/pages/cluster/components/Tutorial.tsx | 299 +++++++++++ service/license/src/pages/cluster/index.tsx | 86 +++- service/license/src/pages/index.tsx | 2 +- .../src/pages/license/components/Recharge.tsx | 62 ++- .../src/pages/license/components/Record.tsx | 11 +- service/license/src/pages/license/index.tsx | 77 +-- .../src/pages/pricing/components/Product.tsx | 464 ++++++++++++++++++ .../pricing/components/ServicePackage.tsx | 34 ++ service/license/src/pages/pricing/index.tsx | 24 + service/license/src/pages/signin.tsx | 7 +- .../src/services/backend/db/cluster.ts | 127 +++++ .../src/services/backend/db/license.ts | 29 +- .../license/src/services/backend/db/oss.ts | 26 + .../src/services/backend/db/payment.ts | 127 ++--- service/license/src/stores/routeParams.ts | 45 ++ service/license/src/styles/chakraTheme.ts | 2 +- service/license/src/styles/prism.css | 13 + service/license/src/types/cluster.ts | 48 ++ service/license/src/types/index.ts | 1 + service/license/src/types/license.ts | 19 +- service/license/src/types/payment.ts | 11 +- service/license/src/types/user.ts | 6 +- service/license/src/utils/tools.ts | 8 + 94 files changed, 2358 insertions(+), 304 deletions(-) create mode 100644 service/license/src/api/cluster.ts create mode 100644 service/license/src/components/CodeBlock/index.tsx rename service/license/src/components/{icons => Icon}/CancelIcon.tsx (100%) create mode 100644 service/license/src/components/Icon/CheckIcon.tsx create mode 100644 service/license/src/components/Icon/CheckListIcon.tsx rename service/license/src/components/{icons => Icon}/CloseIcon.tsx (100%) create mode 100644 service/license/src/components/Icon/ClusterIcon.tsx rename service/license/src/components/{icons => Icon}/CodeDoneIcon.tsx (99%) create mode 100644 service/license/src/components/Icon/CopyIcon.tsx rename service/license/src/components/{icons => Icon}/CopyLink.tsx (100%) rename service/license/src/components/{icons => Icon}/DeleteIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/DownloadIcon.tsx (92%) rename service/license/src/components/{icons => Icon}/EmptyIcon.tsx (99%) rename service/license/src/components/{icons => Icon}/ExchangeIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/GithubIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/GoogleIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/GroupAdd.tsx (100%) rename service/license/src/components/{icons => Icon}/HomePage.tsx (98%) rename service/license/src/components/{icons => Icon}/HtmlIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/LicenseIcon.tsx (99%) rename service/license/src/components/{icons => Icon}/LockIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/MdIcon.tsx (100%) create mode 100644 service/license/src/components/Icon/OfflineIcon.tsx create mode 100644 service/license/src/components/Icon/OnlineComputerIcon.tsx rename service/license/src/components/{icons => Icon}/PersonIcon.tsx (100%) rename service/license/src/components/{icons/RightArrow.tsx => Icon/RightIcon.tsx} (100%) rename service/license/src/components/{icons => Icon}/SafetyIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/Share.tsx (100%) rename service/license/src/components/{icons => Icon}/SignOutIcon.tsx (99%) create mode 100644 service/license/src/components/Icon/StarIcon.tsx rename service/license/src/components/{icons => Icon}/StripeIcon.tsx (98%) create mode 100644 service/license/src/components/Icon/SuccessIcon.tsx rename service/license/src/components/{icons => Icon}/TokenIcon.tsx (98%) rename service/license/src/components/{icons => Icon}/VectorIcon.tsx (84%) rename service/license/src/components/{icons => Icon}/WarningIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/WechatIcon.tsx (100%) rename service/license/src/components/{icons => Icon}/index.ts (73%) create mode 100644 service/license/src/components/Layout/index.tsx rename service/license/src/{pages/license/components/Pagination.tsx => components/Pagination/index.tsx} (100%) rename service/license/src/{pages/license/components/WechatPayment.tsx => components/WechatPayment/index.tsx} (96%) delete mode 100644 service/license/src/components/icons/DownloadIcon copy 3.tsx create mode 100644 service/license/src/constant/product.ts create mode 100644 service/license/src/pages/api/cluster/clusterAndLicense.ts create mode 100644 service/license/src/pages/api/cluster/create.ts create mode 100644 service/license/src/pages/api/cluster/findById.ts create mode 100644 service/license/src/pages/api/cluster/getRecord.ts create mode 100644 service/license/src/pages/api/license/create.ts delete mode 100644 service/license/src/pages/api/license/createLicenseRecord.ts rename service/license/src/pages/api/license/{getLicenseRecord.ts => getRecord.ts} (70%) create mode 100644 service/license/src/pages/cluster/components/Record.tsx create mode 100644 service/license/src/pages/cluster/components/Tutorial.tsx create mode 100644 service/license/src/pages/pricing/components/Product.tsx create mode 100644 service/license/src/pages/pricing/components/ServicePackage.tsx create mode 100644 service/license/src/services/backend/db/cluster.ts create mode 100644 service/license/src/services/backend/db/oss.ts create mode 100644 service/license/src/stores/routeParams.ts create mode 100644 service/license/src/styles/prism.css create mode 100644 service/license/src/types/cluster.ts diff --git a/service/license/.env.template b/service/license/.env.template index 53db89856ce..231e10e3941 100644 --- a/service/license/.env.template +++ b/service/license/.env.template @@ -23,5 +23,5 @@ SEALOS_CLOUD_DOMAIN="cloud.sealos.io" # SMS_ENABLED= # costcenter -STRIPE_ENABLED= -STRIPE_PUB= \ No newline at end of file +# STRIPE_ENABLED= +# STRIPE_PUB= \ No newline at end of file diff --git a/service/license/package.json b/service/license/package.json index 428f88d43d6..f83f607a8b8 100644 --- a/service/license/package.json +++ b/service/license/package.json @@ -37,6 +37,7 @@ "react-dom": "^18", "react-hook-form": "^7.47.0", "react-i18next": "^13.3.0", + "react-syntax-highlighter": "^15.5.0", "sharp": "^0.32.6", "uuid": "^9.0.1", "zustand": "^4.4.3" @@ -50,6 +51,7 @@ "@types/nprogress": "^0.2.1", "@types/react": "^18", "@types/react-dom": "^18", + "@types/react-syntax-highlighter": "^15.5.9", "@types/uuid": "^9.0.5", "eslint": "^8", "eslint-config-next": "13.5.4", diff --git a/service/license/pnpm-lock.yaml b/service/license/pnpm-lock.yaml index cf7ab2a54bd..5ba59afa95c 100644 --- a/service/license/pnpm-lock.yaml +++ b/service/license/pnpm-lock.yaml @@ -89,6 +89,9 @@ dependencies: react-i18next: specifier: ^13.3.0 version: registry.npmmirror.com/react-i18next@13.3.0(i18next@23.5.1)(react-dom@18.0.0)(react@18.0.0) + react-syntax-highlighter: + specifier: ^15.5.0 + version: registry.npmmirror.com/react-syntax-highlighter@15.5.0(react@18.0.0) sharp: specifier: ^0.32.6 version: registry.npmmirror.com/sharp@0.32.6 @@ -124,6 +127,9 @@ devDependencies: '@types/react-dom': specifier: ^18 version: registry.npmmirror.com/@types/react-dom@18.0.0 + '@types/react-syntax-highlighter': + specifier: ^15.5.9 + version: registry.npmmirror.com/@types/react-syntax-highlighter@15.5.9 '@types/uuid': specifier: ^9.0.5 version: registry.npmmirror.com/@types/uuid@9.0.5 @@ -2065,6 +2071,14 @@ packages: use-sync-external-store: registry.npmmirror.com/use-sync-external-store@1.2.0(react@18.0.0) dev: false + registry.npmmirror.com/@types/hast@2.3.7: + resolution: {integrity: sha512-EVLigw5zInURhzfXUM65eixfadfsHKomGKUakToXo84t8gGIJuTcD2xooM2See7GyQ7DRtYjhCHnSUQez8JaLw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/hast/-/hast-2.3.7.tgz} + name: '@types/hast' + version: 2.3.7 + dependencies: + '@types/unist': registry.npmmirror.com/@types/unist@2.0.9 + dev: false + registry.npmmirror.com/@types/hoist-non-react-statics@3.3.3: resolution: {integrity: sha512-Wny3a2UXn5FEA1l7gc6BbpoV5mD1XijZqgkp4TRgDCDL5r3B5ieOFGUX5h3n78Tr1MEG7BfvoM8qeztdvNU0fw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.3.tgz} name: '@types/hoist-non-react-statics' @@ -2149,6 +2163,14 @@ packages: '@types/react': registry.npmmirror.com/@types/react@18.0.0 dev: true + registry.npmmirror.com/@types/react-syntax-highlighter@15.5.9: + resolution: {integrity: sha512-ven8zRSVMNkqt8ySJ2eEW5ugbfl/V/Z9S1c9UNhGqwkwVZNV5akk10rYDALxgwS25cLmN+/Q5UxlGj9CJmZ6Ew==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.9.tgz} + name: '@types/react-syntax-highlighter' + version: 15.5.9 + dependencies: + '@types/react': registry.npmmirror.com/@types/react@18.0.0 + dev: true + registry.npmmirror.com/@types/react@18.0.0: resolution: {integrity: sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/react/-/react-18.0.0.tgz} name: '@types/react' @@ -2163,6 +2185,12 @@ packages: name: '@types/scheduler' version: 0.16.4 + registry.npmmirror.com/@types/unist@2.0.9: + resolution: {integrity: sha512-zC0iXxAv1C1ERURduJueYzkzZ2zaGyc+P2c95hgkikHPr3z8EdUZOlgEQ5X0DRmwDZn+hekycQnoeiiRVrmilQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/unist/-/unist-2.0.9.tgz} + name: '@types/unist' + version: 2.0.9 + dev: false + registry.npmmirror.com/@types/uuid@9.0.5: resolution: {integrity: sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/uuid/-/uuid-9.0.5.tgz} name: '@types/uuid' @@ -2715,6 +2743,24 @@ packages: supports-color: registry.npmmirror.com/supports-color@7.2.0 dev: true + registry.npmmirror.com/character-entities-legacy@1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz} + name: character-entities-legacy + version: 1.1.4 + dev: false + + registry.npmmirror.com/character-entities@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/character-entities/-/character-entities-1.2.4.tgz} + name: character-entities + version: 1.2.4 + dev: false + + registry.npmmirror.com/character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz} + name: character-reference-invalid + version: 1.1.4 + dev: false + registry.npmmirror.com/chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz} name: chownr @@ -2795,6 +2841,12 @@ packages: delayed-stream: registry.npmmirror.com/delayed-stream@1.0.0 dev: false + registry.npmmirror.com/comma-separated-tokens@1.0.8: + resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz} + name: comma-separated-tokens + version: 1.0.8 + dev: false + registry.npmmirror.com/compute-scroll-into-view@3.0.3: resolution: {integrity: sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz} name: compute-scroll-into-view @@ -3637,6 +3689,14 @@ packages: reusify: registry.npmmirror.com/reusify@1.0.4 dev: true + registry.npmmirror.com/fault@1.0.4: + resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/fault/-/fault-1.0.4.tgz} + name: fault + version: 1.0.4 + dependencies: + format: registry.npmmirror.com/format@0.2.2 + dev: false + registry.npmmirror.com/file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz} name: file-entry-cache @@ -3718,6 +3778,13 @@ packages: mime-types: registry.npmmirror.com/mime-types@2.1.35 dev: false + registry.npmmirror.com/format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/format/-/format-0.2.2.tgz} + name: format + version: 0.2.2 + engines: {node: '>=0.4.x'} + dev: false + registry.npmmirror.com/formstream@1.3.1: resolution: {integrity: sha512-FkW++ub+VbE5dpwukJVDizNWhSgp8FhmhI65pF7BZSVStBqe6Wgxe2Z9/Vhsn7l7nXCPwP+G1cyYlX8VwWOf0g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/formstream/-/formstream-1.3.1.tgz} name: formstream @@ -3995,6 +4062,30 @@ packages: version: 1.0.4 engines: {node: '>= 0.4.0'} + registry.npmmirror.com/hast-util-parse-selector@2.2.5: + resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz} + name: hast-util-parse-selector + version: 2.2.5 + dev: false + + registry.npmmirror.com/hastscript@6.0.0: + resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/hastscript/-/hastscript-6.0.0.tgz} + name: hastscript + version: 6.0.0 + dependencies: + '@types/hast': registry.npmmirror.com/@types/hast@2.3.7 + comma-separated-tokens: registry.npmmirror.com/comma-separated-tokens@1.0.8 + hast-util-parse-selector: registry.npmmirror.com/hast-util-parse-selector@2.2.5 + property-information: registry.npmmirror.com/property-information@5.6.0 + space-separated-tokens: registry.npmmirror.com/space-separated-tokens@1.1.5 + dev: false + + registry.npmmirror.com/highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz} + name: highlight.js + version: 10.7.3 + dev: false + registry.npmmirror.com/hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz} name: hoist-non-react-statics @@ -4140,6 +4231,21 @@ packages: version: 1.1.8 dev: false + registry.npmmirror.com/is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz} + name: is-alphabetical + version: 1.0.4 + dev: false + + registry.npmmirror.com/is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz} + name: is-alphanumerical + version: 1.0.4 + dependencies: + is-alphabetical: registry.npmmirror.com/is-alphabetical@1.0.4 + is-decimal: registry.npmmirror.com/is-decimal@1.0.4 + dev: false + registry.npmmirror.com/is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz} name: is-array-buffer @@ -4218,6 +4324,12 @@ packages: has-tostringtag: registry.npmmirror.com/has-tostringtag@1.0.0 dev: true + registry.npmmirror.com/is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-decimal/-/is-decimal-1.0.4.tgz} + name: is-decimal + version: 1.0.4 + dev: false + registry.npmmirror.com/is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz} name: is-extendable @@ -4258,6 +4370,12 @@ packages: is-extglob: registry.npmmirror.com/is-extglob@2.1.1 dev: true + registry.npmmirror.com/is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz} + name: is-hexadecimal + version: 1.0.4 + dev: false + registry.npmmirror.com/is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-map/-/is-map-2.0.2.tgz} name: is-map @@ -4635,6 +4753,15 @@ packages: dependencies: js-tokens: registry.npmmirror.com/js-tokens@4.0.0 + registry.npmmirror.com/lowlight@1.20.0: + resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lowlight/-/lowlight-1.20.0.tgz} + name: lowlight + version: 1.20.0 + dependencies: + fault: registry.npmmirror.com/fault@1.0.4 + highlight.js: registry.npmmirror.com/highlight.js@10.7.3 + dev: false + registry.npmmirror.com/lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz} name: lru-cache @@ -5039,6 +5166,19 @@ packages: dependencies: callsites: registry.npmmirror.com/callsites@3.1.0 + registry.npmmirror.com/parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parse-entities/-/parse-entities-2.0.0.tgz} + name: parse-entities + version: 2.0.0 + dependencies: + character-entities: registry.npmmirror.com/character-entities@1.2.4 + character-entities-legacy: registry.npmmirror.com/character-entities-legacy@1.1.4 + character-reference-invalid: registry.npmmirror.com/character-reference-invalid@1.1.4 + is-alphanumerical: registry.npmmirror.com/is-alphanumerical@1.0.4 + is-decimal: registry.npmmirror.com/is-decimal@1.0.4 + is-hexadecimal: registry.npmmirror.com/is-hexadecimal@1.0.4 + dev: false + registry.npmmirror.com/parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz} name: parse-json @@ -5150,6 +5290,20 @@ packages: hasBin: true dev: true + registry.npmmirror.com/prismjs@1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prismjs/-/prismjs-1.27.0.tgz} + name: prismjs + version: 1.27.0 + engines: {node: '>=6'} + dev: false + + registry.npmmirror.com/prismjs@1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz} + name: prismjs + version: 1.29.0 + engines: {node: '>=6'} + dev: false + registry.npmmirror.com/process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz} name: process-nextick-args @@ -5172,6 +5326,14 @@ packages: object-assign: registry.npmmirror.com/object-assign@4.1.1 react-is: registry.npmmirror.com/react-is@16.13.1 + registry.npmmirror.com/property-information@5.6.0: + resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/property-information/-/property-information-5.6.0.tgz} + name: property-information + version: 5.6.0 + dependencies: + xtend: registry.npmmirror.com/xtend@4.0.2 + dev: false + registry.npmmirror.com/proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz} name: proxy-from-env @@ -5391,6 +5553,22 @@ packages: tslib: registry.npmmirror.com/tslib@2.6.2 dev: false + registry.npmmirror.com/react-syntax-highlighter@15.5.0(react@18.0.0): + resolution: {integrity: sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz} + id: registry.npmmirror.com/react-syntax-highlighter/15.5.0 + name: react-syntax-highlighter + version: 15.5.0 + peerDependencies: + react: '>= 0.14.0' + dependencies: + '@babel/runtime': registry.npmmirror.com/@babel/runtime@7.23.2 + highlight.js: registry.npmmirror.com/highlight.js@10.7.3 + lowlight: registry.npmmirror.com/lowlight@1.20.0 + prismjs: registry.npmmirror.com/prismjs@1.29.0 + react: registry.npmmirror.com/react@18.0.0 + refractor: registry.npmmirror.com/refractor@3.6.0 + dev: false + registry.npmmirror.com/react@18.0.0: resolution: {integrity: sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react/-/react-18.0.0.tgz} name: react @@ -5439,6 +5617,16 @@ packages: which-builtin-type: registry.npmmirror.com/which-builtin-type@1.1.3 dev: true + registry.npmmirror.com/refractor@3.6.0: + resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/refractor/-/refractor-3.6.0.tgz} + name: refractor + version: 3.6.0 + dependencies: + hastscript: registry.npmmirror.com/hastscript@6.0.0 + parse-entities: registry.npmmirror.com/parse-entities@2.0.0 + prismjs: registry.npmmirror.com/prismjs@1.27.0 + dev: false + registry.npmmirror.com/regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz} name: regenerator-runtime @@ -5708,6 +5896,12 @@ packages: engines: {node: '>=0.10.0'} dev: false + registry.npmmirror.com/space-separated-tokens@1.1.5: + resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz} + name: space-separated-tokens + version: 1.1.5 + dev: false + registry.npmmirror.com/sparse-bitfield@3.0.3: resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz} name: sparse-bitfield diff --git a/service/license/public/locales/en/common.json b/service/license/public/locales/en/common.json index 4827a492182..1ee50030bf5 100644 --- a/service/license/public/locales/en/common.json +++ b/service/license/public/locales/en/common.json @@ -87,5 +87,17 @@ "License issued successfully": "License issued successfully", "Pay Minimum Tips": "The amount need to be more than 10 when paying with Stripe", "Stripe Cancel": "Stripe Cancel", - "Recharge Amount": "Recharge Amount" -} + "Recharge Amount": "Recharge Amount", + "price": "Price", + "My Cluster": "My Cluster", + "Cluster List": "Cluster List", + "Deploy": "Deploy", + "Cluster": "Cluster", + "Standard": "Standard", + "Enterprise": "Enterprise", + "You have not purchased the Cluster": "You have not purchased the Cluster", + "Contact Us": "Contact Us", + "Buy": "Buy", + "Checking Payment Results": "Checking Payment Results", + "Cluster Pay Success": "Buy {{clusterType}} Success" +} \ No newline at end of file diff --git a/service/license/public/locales/zh/common.json b/service/license/public/locales/zh/common.json index ccf3a0e41ee..7cb2c42bd08 100644 --- a/service/license/public/locales/zh/common.json +++ b/service/license/public/locales/zh/common.json @@ -87,5 +87,17 @@ "App Info": "应用信息", "License issued successfully": "签发 License 成功", "Pay Minimum Tips": "Stripe支付时金额需大于10", - "Stripe Cancel": "Stripe 支付取消" -} + "Stripe Cancel": "Stripe 支付取消", + "price": "价格", + "My Cluster": "我的集群", + "Cluster List": "集群列表", + "Deploy": "部署", + "Cluster": "集群", + "Standard": "标准版", + "Enterprise": "企业版", + "You have not purchased the Cluster": "您还没有购买集群", + "Contact Us": "联系我们", + "Buy": "购买", + "Checking Payment Results": "正在查询支付结果", + "Cluster Pay Success": "购买 {{clusterType}} 成功" +} \ No newline at end of file diff --git a/service/license/src/api/cluster.ts b/service/license/src/api/cluster.ts new file mode 100644 index 00000000000..02090a46f30 --- /dev/null +++ b/service/license/src/api/cluster.ts @@ -0,0 +1,17 @@ +import { GET, POST } from '@/services/request'; +import { CreateClusterParams, ClusterDB, ClusterType, ClusterResult } from '@/types'; + +export const createCluster = (payload: { type: ClusterType }) => + POST('/api/cluster/create', payload); + +export const createClusterAndLicense = (payload: CreateClusterParams) => + POST('/api/cluster/clusterAndLicense', payload); + +export const getClusterRecord = ({ page, pageSize }: { page: number; pageSize: number }) => + POST<{ total: number; records: ClusterDB[] }>('/api/cluster/getRecord', { + page, + pageSize + }); + +export const findClusterById = (payload: { clusterId: string }) => + GET('/api/cluster/findById', payload); diff --git a/service/license/src/api/license.ts b/service/license/src/api/license.ts index a711c717633..e45a18bf9e8 100644 --- a/service/license/src/api/license.ts +++ b/service/license/src/api/license.ts @@ -1,11 +1,10 @@ -import { GET, POST } from '@/services/request'; -import { LicensePayload, LicenseDB } from '@/types'; +import { POST } from '@/services/request'; +import { CreateLicenseParams, LicenseDB } from '@/types'; -export const createLicenseRecord = (payload: LicensePayload) => - POST('/api/license/createLicenseRecord', payload); +export const createLicense = (payload: CreateLicenseParams) => POST('/api/license/create', payload); export const getLicenseRecord = ({ page, pageSize }: { page: number; pageSize: number }) => - POST<{ total: number; records: LicenseDB[] }>('/api/license/getLicenseRecord', { + POST<{ total: number; records: LicenseDB[] }>('/api/license/getRecord', { page, pageSize }); diff --git a/service/license/src/api/oos.ts b/service/license/src/api/oos.ts index 2463c345cd6..ad9ed0dbef9 100644 --- a/service/license/src/api/oos.ts +++ b/service/license/src/api/oos.ts @@ -1,4 +1,4 @@ import { GET, POST } from '@/services/request'; -import { LicensePayload, LicenseDB } from '@/types'; -export const getFileByName = (fileName: string) => POST('/api/oss/get', { fileName: fileName }); +export const getFileByName = (fileName: string) => + GET('/api/oss/get', { fileName: fileName }); diff --git a/service/license/src/api/payment.ts b/service/license/src/api/payment.ts index b366f07f28e..7a8ad5f48d1 100644 --- a/service/license/src/api/payment.ts +++ b/service/license/src/api/payment.ts @@ -1,10 +1,10 @@ import { GET, POST } from '@/services/request'; -import { PaymentData, PaymentParams, PaymentResult } from '@/types'; +import { PaymentData, PaymentParams, PaymentResult, PaymentResultParams } from '@/types'; export const createPayment = (payload: PaymentParams) => POST('/api/payment/create', payload); -export const getPaymentResult = (payload: { orderID: string }) => +export const handlePaymentResult = (payload: PaymentResultParams) => POST('/api/payment/result', payload); export const checkWechatPay = () => GET('/api/payment/checkWechat'); diff --git a/service/license/src/components/CodeBlock/index.tsx b/service/license/src/components/CodeBlock/index.tsx new file mode 100644 index 00000000000..fd5fe82bc41 --- /dev/null +++ b/service/license/src/components/CodeBlock/index.tsx @@ -0,0 +1,32 @@ +import { useCopyData } from '@/hooks/useCopyData'; +import { Center, Flex, FlexProps, Text } from '@chakra-ui/react'; +import { CSSProperties } from 'react'; +import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { CopyIcon } from '@/components/Icon'; + +type CodeBlockProps = { + code: string; + language: string; + customStyle?: CSSProperties | undefined; + flexStyle?: FlexProps; +}; + +export default function CodeBlock({ code, language, customStyle, flexStyle }: CodeBlockProps) { + const { copyData } = useCopyData(); + + return ( + + + + $ + + + {code} + + +
copyData(code)}> + +
+
+ ); +} diff --git a/service/license/src/components/icons/CancelIcon.tsx b/service/license/src/components/Icon/CancelIcon.tsx similarity index 100% rename from service/license/src/components/icons/CancelIcon.tsx rename to service/license/src/components/Icon/CancelIcon.tsx diff --git a/service/license/src/components/Icon/CheckIcon.tsx b/service/license/src/components/Icon/CheckIcon.tsx new file mode 100644 index 00000000000..7879c0462d0 --- /dev/null +++ b/service/license/src/components/Icon/CheckIcon.tsx @@ -0,0 +1,22 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const CheckIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/Icon/CheckListIcon.tsx b/service/license/src/components/Icon/CheckListIcon.tsx new file mode 100644 index 00000000000..d53d53e00b5 --- /dev/null +++ b/service/license/src/components/Icon/CheckListIcon.tsx @@ -0,0 +1,21 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const CheckListIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/CloseIcon.tsx b/service/license/src/components/Icon/CloseIcon.tsx similarity index 100% rename from service/license/src/components/icons/CloseIcon.tsx rename to service/license/src/components/Icon/CloseIcon.tsx diff --git a/service/license/src/components/Icon/ClusterIcon.tsx b/service/license/src/components/Icon/ClusterIcon.tsx new file mode 100644 index 00000000000..6a302f21b5c --- /dev/null +++ b/service/license/src/components/Icon/ClusterIcon.tsx @@ -0,0 +1,32 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const ClusterIcon = (props: IconProps) => { + return ( + + + + + + ); +}; diff --git a/service/license/src/components/icons/CodeDoneIcon.tsx b/service/license/src/components/Icon/CodeDoneIcon.tsx similarity index 99% rename from service/license/src/components/icons/CodeDoneIcon.tsx rename to service/license/src/components/Icon/CodeDoneIcon.tsx index 73de6a609e8..236c23329aa 100644 --- a/service/license/src/components/icons/CodeDoneIcon.tsx +++ b/service/license/src/components/Icon/CodeDoneIcon.tsx @@ -7,6 +7,7 @@ export const CodeDoneIcon = (props: IconProps) => { height="17px" fill="#219BF4" viewBox="0 0 16 17" + {...props} > { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/CopyLink.tsx b/service/license/src/components/Icon/CopyLink.tsx similarity index 100% rename from service/license/src/components/icons/CopyLink.tsx rename to service/license/src/components/Icon/CopyLink.tsx diff --git a/service/license/src/components/icons/DeleteIcon.tsx b/service/license/src/components/Icon/DeleteIcon.tsx similarity index 100% rename from service/license/src/components/icons/DeleteIcon.tsx rename to service/license/src/components/Icon/DeleteIcon.tsx diff --git a/service/license/src/components/icons/DownloadIcon.tsx b/service/license/src/components/Icon/DownloadIcon.tsx similarity index 92% rename from service/license/src/components/icons/DownloadIcon.tsx rename to service/license/src/components/Icon/DownloadIcon.tsx index 78e3450c4c1..b50895c48a3 100644 --- a/service/license/src/components/icons/DownloadIcon.tsx +++ b/service/license/src/components/Icon/DownloadIcon.tsx @@ -2,11 +2,12 @@ import { Icon, IconProps } from '@chakra-ui/react'; export const DownloadIcon = (props: IconProps) => { return ( diff --git a/service/license/src/components/icons/EmptyIcon.tsx b/service/license/src/components/Icon/EmptyIcon.tsx similarity index 99% rename from service/license/src/components/icons/EmptyIcon.tsx rename to service/license/src/components/Icon/EmptyIcon.tsx index 16f8fa41906..33c05f26a0b 100644 --- a/service/license/src/components/icons/EmptyIcon.tsx +++ b/service/license/src/components/Icon/EmptyIcon.tsx @@ -7,6 +7,7 @@ export const EmptyIcon = (props: IconProps) => { viewBox="0 0 48 49" fill="none" xmlns="http://www.w3.org/2000/svg" + {...props} > ( - + { viewBox="0 0 24 24" fill="#485058" xmlns="http://www.w3.org/2000/svg" + {...props} > diff --git a/service/license/src/components/icons/LockIcon.tsx b/service/license/src/components/Icon/LockIcon.tsx similarity index 100% rename from service/license/src/components/icons/LockIcon.tsx rename to service/license/src/components/Icon/LockIcon.tsx diff --git a/service/license/src/components/icons/MdIcon.tsx b/service/license/src/components/Icon/MdIcon.tsx similarity index 100% rename from service/license/src/components/icons/MdIcon.tsx rename to service/license/src/components/Icon/MdIcon.tsx diff --git a/service/license/src/components/Icon/OfflineIcon.tsx b/service/license/src/components/Icon/OfflineIcon.tsx new file mode 100644 index 00000000000..77a10f54159 --- /dev/null +++ b/service/license/src/components/Icon/OfflineIcon.tsx @@ -0,0 +1,19 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const OfflineIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/Icon/OnlineComputerIcon.tsx b/service/license/src/components/Icon/OnlineComputerIcon.tsx new file mode 100644 index 00000000000..a047fc0ea1e --- /dev/null +++ b/service/license/src/components/Icon/OnlineComputerIcon.tsx @@ -0,0 +1,19 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const OnlineComputerIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/PersonIcon.tsx b/service/license/src/components/Icon/PersonIcon.tsx similarity index 100% rename from service/license/src/components/icons/PersonIcon.tsx rename to service/license/src/components/Icon/PersonIcon.tsx diff --git a/service/license/src/components/icons/RightArrow.tsx b/service/license/src/components/Icon/RightIcon.tsx similarity index 100% rename from service/license/src/components/icons/RightArrow.tsx rename to service/license/src/components/Icon/RightIcon.tsx diff --git a/service/license/src/components/icons/SafetyIcon.tsx b/service/license/src/components/Icon/SafetyIcon.tsx similarity index 100% rename from service/license/src/components/icons/SafetyIcon.tsx rename to service/license/src/components/Icon/SafetyIcon.tsx diff --git a/service/license/src/components/icons/Share.tsx b/service/license/src/components/Icon/Share.tsx similarity index 100% rename from service/license/src/components/icons/Share.tsx rename to service/license/src/components/Icon/Share.tsx diff --git a/service/license/src/components/icons/SignOutIcon.tsx b/service/license/src/components/Icon/SignOutIcon.tsx similarity index 99% rename from service/license/src/components/icons/SignOutIcon.tsx rename to service/license/src/components/Icon/SignOutIcon.tsx index deb50f6737e..6f735879507 100644 --- a/service/license/src/components/icons/SignOutIcon.tsx +++ b/service/license/src/components/Icon/SignOutIcon.tsx @@ -7,6 +7,7 @@ export const SignOutIcon = (props: IconProps) => { height="21px" viewBox="0 0 20 21" fill="#5A646E" + {...props} > diff --git a/service/license/src/components/Icon/StarIcon.tsx b/service/license/src/components/Icon/StarIcon.tsx new file mode 100644 index 00000000000..a55295c40a8 --- /dev/null +++ b/service/license/src/components/Icon/StarIcon.tsx @@ -0,0 +1,19 @@ +import { Icon, IconProps } from '@chakra-ui/react'; +export const StarIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/StripeIcon.tsx b/service/license/src/components/Icon/StripeIcon.tsx similarity index 98% rename from service/license/src/components/icons/StripeIcon.tsx rename to service/license/src/components/Icon/StripeIcon.tsx index fdd6f22aa89..c413baa3783 100644 --- a/service/license/src/components/icons/StripeIcon.tsx +++ b/service/license/src/components/Icon/StripeIcon.tsx @@ -7,6 +7,7 @@ export const StripeIcon = (props: IconProps) => { viewBox="0 0 24 25" fill="#9893FF" xmlns="http://www.w3.org/2000/svg" + {...props} > diff --git a/service/license/src/components/Icon/SuccessIcon.tsx b/service/license/src/components/Icon/SuccessIcon.tsx new file mode 100644 index 00000000000..c2e2a7827c2 --- /dev/null +++ b/service/license/src/components/Icon/SuccessIcon.tsx @@ -0,0 +1,16 @@ +import { Icon, IconProps } from '@chakra-ui/react'; + +export const SuccessIcon = (props: IconProps) => { + return ( + + + + ); +}; diff --git a/service/license/src/components/icons/TokenIcon.tsx b/service/license/src/components/Icon/TokenIcon.tsx similarity index 98% rename from service/license/src/components/icons/TokenIcon.tsx rename to service/license/src/components/Icon/TokenIcon.tsx index 44cd6be8fb1..5e6d5bd0550 100644 --- a/service/license/src/components/icons/TokenIcon.tsx +++ b/service/license/src/components/Icon/TokenIcon.tsx @@ -7,6 +7,7 @@ export const TokenIcon = (props: IconProps) => { viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg" + {...props} > { return ( - + ); diff --git a/service/license/src/components/icons/WarningIcon.tsx b/service/license/src/components/Icon/WarningIcon.tsx similarity index 100% rename from service/license/src/components/icons/WarningIcon.tsx rename to service/license/src/components/Icon/WarningIcon.tsx diff --git a/service/license/src/components/icons/WechatIcon.tsx b/service/license/src/components/Icon/WechatIcon.tsx similarity index 100% rename from service/license/src/components/icons/WechatIcon.tsx rename to service/license/src/components/Icon/WechatIcon.tsx diff --git a/service/license/src/components/icons/index.ts b/service/license/src/components/Icon/index.ts similarity index 73% rename from service/license/src/components/icons/index.ts rename to service/license/src/components/Icon/index.ts index ab672079855..0dd17f3b961 100644 --- a/service/license/src/components/icons/index.ts +++ b/service/license/src/components/Icon/index.ts @@ -10,7 +10,7 @@ export * from './CopyLink'; export * from './DeleteIcon'; export * from './ExchangeIcon'; export * from './GroupAdd'; -export * from './RightArrow'; +export * from './RightIcon'; export * from './WechatIcon'; export * from './WarningIcon'; export * from './CloseIcon'; @@ -25,3 +25,11 @@ export * from './CodeDoneIcon'; export * from './VectorIcon'; export * from './SignOutIcon'; export * from './StripeIcon'; +export * from './StarIcon'; +export * from './CheckIcon'; +export * from './ClusterIcon'; +export * from './SuccessIcon'; +export * from './CheckListIcon'; +export * from './OfflineIcon'; +export * from './OnlineComputerIcon'; +export * from './CopyIcon'; diff --git a/service/license/src/components/Layout/index.tsx b/service/license/src/components/Layout/index.tsx new file mode 100644 index 00000000000..18a83257e4c --- /dev/null +++ b/service/license/src/components/Layout/index.tsx @@ -0,0 +1,82 @@ +import { Box, Flex, Image, Text } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; +import { ReactNode, useState } from 'react'; +import LangSelectSimple from '../LangSelect'; +import Account from '../Account'; + +export default function Layout({ children }: { children: ReactNode }) { + const { t } = useTranslation(); + const router = useRouter(); + const goHome = () => router.replace('/'); + const [active, setActive] = useState(router.pathname); + + const tabs = [ + { + url: '/pricing', + label: t('price') + }, + { + url: '/cluster', + label: t('My Cluster') + }, + { + url: '/license', + label: t('License Buy') + } + ]; + + return ( + + + logo + + Sealos + + + | + + + {tabs.map((i) => { + return ( + { + router.push(i.url); + }} + > + + {i.label} + + + ); + })} + + + + + {children} + + ); +} diff --git a/service/license/src/pages/license/components/Pagination.tsx b/service/license/src/components/Pagination/index.tsx similarity index 100% rename from service/license/src/pages/license/components/Pagination.tsx rename to service/license/src/components/Pagination/index.tsx diff --git a/service/license/src/pages/license/components/WechatPayment.tsx b/service/license/src/components/WechatPayment/index.tsx similarity index 96% rename from service/license/src/pages/license/components/WechatPayment.tsx rename to service/license/src/components/WechatPayment/index.tsx index 071b3a1f3d3..88e1ec4fb92 100644 --- a/service/license/src/pages/license/components/WechatPayment.tsx +++ b/service/license/src/components/WechatPayment/index.tsx @@ -1,4 +1,4 @@ -import { Flex, Box, Text } from '@chakra-ui/react'; +import { Box, Flex, Text } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { QRCodeSVG } from 'qrcode.react'; diff --git a/service/license/src/components/account/index.tsx b/service/license/src/components/account/index.tsx index 00d41572028..ffbd1fa5a4a 100644 --- a/service/license/src/components/account/index.tsx +++ b/service/license/src/components/account/index.tsx @@ -1,6 +1,6 @@ import useSessionStore from '@/stores/session'; import { Box, Flex, Image, useDisclosure, Text, Divider } from '@chakra-ui/react'; -import { SignOutIcon } from '../icons'; +import { SignOutIcon } from '../Icon'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; diff --git a/service/license/src/components/icons/DownloadIcon copy 3.tsx b/service/license/src/components/icons/DownloadIcon copy 3.tsx deleted file mode 100644 index 78e3450c4c1..00000000000 --- a/service/license/src/components/icons/DownloadIcon copy 3.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Icon, IconProps } from '@chakra-ui/react'; -export const DownloadIcon = (props: IconProps) => { - return ( - - - - ); -}; diff --git a/service/license/src/components/signin/auth/useAuthList.tsx b/service/license/src/components/signin/auth/useAuthList.tsx index f5aaf5d245c..fea1a1ddeff 100644 --- a/service/license/src/components/signin/auth/useAuthList.tsx +++ b/service/license/src/components/signin/auth/useAuthList.tsx @@ -1,5 +1,5 @@ import { getSystemEnv } from '@/api/system'; -import { GithubIcon, GoogleIcon, WechatIcon } from '@/components/icons'; +import { GithubIcon, GoogleIcon, WechatIcon } from '@/components/Icon'; import useSessionStore from '@/stores/session'; import { OauthProvider } from '@/types/user'; import { Button, Flex, Icon } from '@chakra-ui/react'; diff --git a/service/license/src/components/signin/auth/useCustomError.tsx b/service/license/src/components/signin/auth/useCustomError.tsx index d525de0eb81..7b807b71744 100644 --- a/service/license/src/components/signin/auth/useCustomError.tsx +++ b/service/license/src/components/signin/auth/useCustomError.tsx @@ -1,6 +1,6 @@ import { Flex, Img, Button, Text } from '@chakra-ui/react'; import React, { useState, useEffect } from 'react'; -import { WarningIcon, CloseIcon } from '@/components/icons'; +import { WarningIcon, CloseIcon } from '@/components/Icon'; import { useTranslation } from 'next-i18next'; const useCustomError = () => { diff --git a/service/license/src/components/signin/auth/usePassword.tsx b/service/license/src/components/signin/auth/usePassword.tsx index ab85ee4352b..4e3a41bde1b 100644 --- a/service/license/src/components/signin/auth/usePassword.tsx +++ b/service/license/src/components/signin/auth/usePassword.tsx @@ -1,5 +1,5 @@ import { signInByPassword } from '@/api/user'; -import { LocklIcon, PersonIcon, VectorIcon } from '@/components/icons'; +import { LocklIcon, PersonIcon, VectorIcon } from '@/components/Icon'; import useSessionStore from '@/stores/session'; import { Flex, Input, InputGroup, InputLeftAddon, Text } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; diff --git a/service/license/src/components/signin/auth/useSms.tsx b/service/license/src/components/signin/auth/useSms.tsx index 23cb7ba8825..c98b2e127d5 100644 --- a/service/license/src/components/signin/auth/useSms.tsx +++ b/service/license/src/components/signin/auth/useSms.tsx @@ -1,5 +1,5 @@ import { sendCodeByPhone, signInByPhone } from '@/api/user'; -import { CodeDoneIcon, SafetyIcon } from '@/components/icons'; +import { CodeDoneIcon, SafetyIcon } from '@/components/Icon'; import useSessionStore from '@/stores/session'; import { Input, InputGroup, InputLeftAddon, InputRightAddon, Link, Text } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; diff --git a/service/license/src/components/signin/index.tsx b/service/license/src/components/signin/index.tsx index 760d55898d0..01c0e7fba67 100644 --- a/service/license/src/components/signin/index.tsx +++ b/service/license/src/components/signin/index.tsx @@ -1,10 +1,10 @@ import { getSystemEnv } from '@/api/system'; -import useAuthList from '@/components/signin/auth/useAuthList'; -import useCustomError from '@/components/signin/auth/useCustomError'; -import Language from '@/components/signin/auth/useLanguage'; -import usePassword from '@/components/signin/auth/usePassword'; -import useProtocol from '@/components/signin/auth/useProtocol'; -import useSms from '@/components/signin/auth/useSms'; +import useAuthList from '@/components/SignIn/auth/useAuthList'; +import useCustomError from '@/components/SignIn/auth/useCustomError'; +import Language from '@/components/SignIn/auth/useLanguage'; +import usePassword from '@/components/SignIn/auth/usePassword'; +import useProtocol from '@/components/SignIn/auth/useProtocol'; +import useSms from '@/components/SignIn/auth/useSms'; import useSessionStore from '@/stores/session'; import { LoginType } from '@/types'; import { @@ -60,7 +60,7 @@ export default function SigninComponent() { useEffect(() => { if (isSignIn()) { - router.push('/license'); + router.push('/pricing'); } }, [isSignIn, router]); diff --git a/service/license/src/constant/product.ts b/service/license/src/constant/product.ts new file mode 100644 index 00000000000..417717dbb92 --- /dev/null +++ b/service/license/src/constant/product.ts @@ -0,0 +1,57 @@ +export type ServiceItem = { label: string; icon: 'check' | 'star' }; + +const baseServiceItem: ServiceItem[] = [ + { + label: '应用管理', + icon: 'check' + }, + { + label: '高可用数据库', + icon: 'check' + }, + { + label: '应用市场', + icon: 'check' + }, + { + label: '多租户', + icon: 'check' + }, + { + label: '计量/配额', + icon: 'check' + } +]; + +export const standard: ServiceItem[] = [ + { + label: '工单服务', + icon: 'check' + }, + ...baseServiceItem +]; + +export const company: ServiceItem[] = [ + { + label: '私有化/离线部署', + icon: 'star' + }, + { label: '工单/即时通信服务', icon: 'check' }, + { label: '周一到周五,8h 内响应', icon: 'check' }, + ...baseServiceItem +]; + +export const contect: ServiceItem[] = [ + { + label: '定制化开发与业务云原生化服务', + icon: 'check' + }, + { label: '支持超大规模', icon: 'check' }, + { + label: '私有化/离线部署', + icon: 'check' + }, + { label: '工单/即时通信/专家对接/现场支持', icon: 'check' }, + { label: '周一到周日,24h 内响应', icon: 'check' }, + ...baseServiceItem +]; diff --git a/service/license/src/pages/404.tsx b/service/license/src/pages/404.tsx index aa2904849d7..71c114c1ff1 100644 --- a/service/license/src/pages/404.tsx +++ b/service/license/src/pages/404.tsx @@ -3,6 +3,7 @@ import { useRouter } from 'next/router'; const NonePage = () => { const router = useRouter(); + useEffect(() => { router.push('/signin'); }, [router]); diff --git a/service/license/src/pages/_app.tsx b/service/license/src/pages/_app.tsx index e34ebdebe6e..8e2a26791e6 100644 --- a/service/license/src/pages/_app.tsx +++ b/service/license/src/pages/_app.tsx @@ -1,13 +1,16 @@ +import { theme } from '@/styles/chakraTheme'; import '@/styles/globals.css'; +import '@/styles/prism.css'; +import { getCookie } from '@/utils/cookieUtils'; import { ChakraProvider } from '@chakra-ui/react'; +import '@stripe/stripe-js'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { appWithTranslation } from 'next-i18next'; +import { appWithTranslation, useTranslation } from 'next-i18next'; import type { AppProps } from 'next/app'; import Router from 'next/router'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; -import { theme } from '@/styles/chakraTheme'; -import '@stripe/stripe-js'; +import { useEffect } from 'react'; const queryClient = new QueryClient({ defaultOptions: { @@ -23,6 +26,13 @@ Router.events.on('routeChangeComplete', () => NProgress.done()); Router.events.on('routeChangeError', () => NProgress.done()); const App = ({ Component, pageProps }: AppProps) => { + const { i18n } = useTranslation(); + + useEffect(() => { + const lang = getCookie('NEXT_LOCALE'); + i18n?.changeLanguage?.(lang); + }, [i18n]); + return ( diff --git a/service/license/src/pages/api/cluster/clusterAndLicense.ts b/service/license/src/pages/api/cluster/clusterAndLicense.ts new file mode 100644 index 00000000000..7127657157e --- /dev/null +++ b/service/license/src/pages/api/cluster/clusterAndLicense.ts @@ -0,0 +1,55 @@ +import { authSession } from '@/services/backend/auth'; +import { createClusterAndLicense } from '@/services/backend/db/cluster'; +import { generateLicenseToken } from '@/services/backend/db/license'; +import { getPaymentByID } from '@/services/backend/db/payment'; +import { jsonRes } from '@/services/backend/response'; +import { CreateClusterParams, LicenseRecordPayload, PaymentStatus } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { orderID, type } = req.body as CreateClusterParams; + + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(res, { code: 401, message: 'token verify error' }); + } + const payment = await getPaymentByID({ uid: userInfo.uid, orderID: orderID }); + if (!payment) { + return jsonRes(res, { code: 400, message: 'No order found' }); + } + + if (payment.status !== PaymentStatus.PaymentSuccess) { + return jsonRes(res, { + code: 400, + message: 'Unpaid' + }); + } + + const _token = generateLicenseToken({ type: 'Account', data: { amount: payment.amount } }); + const record: LicenseRecordPayload = { + uid: userInfo.uid, + amount: payment.amount, + token: _token, + orderID: orderID, + quota: payment.amount, + payMethod: payment.payMethod, + type: 'Account' + }; + + const result = await createClusterAndLicense({ + licensePayload: record, + clusterPayload: { + uid: userInfo.uid, + orderID: orderID, + type: type + } + }); + + return jsonRes(res, { + data: result + }); + } catch (error) { + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/cluster/create.ts b/service/license/src/pages/api/cluster/create.ts new file mode 100644 index 00000000000..add3423b17f --- /dev/null +++ b/service/license/src/pages/api/cluster/create.ts @@ -0,0 +1,27 @@ +import { authSession } from '@/services/backend/auth'; +import { createClusterRecord } from '@/services/backend/db/cluster'; +import { jsonRes } from '@/services/backend/response'; +import { ClusterType, CreateClusterParams } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { type = ClusterType.Standard } = req.body as CreateClusterParams; + + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(res, { code: 401, message: 'token verify error' }); + } + + const result = await createClusterRecord({ + uid: userInfo.uid, + type: type + }); + + return jsonRes(res, { + data: result + }); + } catch (error) { + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/cluster/findById.ts b/service/license/src/pages/api/cluster/findById.ts new file mode 100644 index 00000000000..b857a9cc258 --- /dev/null +++ b/service/license/src/pages/api/cluster/findById.ts @@ -0,0 +1,28 @@ +import { authSession } from '@/services/backend/auth'; +import { + findClusterByUIDAndClusterID, + getClusterRecordsByUid +} from '@/services/backend/db/cluster'; +import { getOssUrl } from '@/services/backend/db/oss'; +import { jsonRes } from '@/services/backend/response'; +import { ClusterType } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { clusterId } = req.query as { clusterId: string }; + const userInfo = await authSession(req.headers); + if (!userInfo) return jsonRes(res, { code: 401, message: 'token verify error' }); + + const cluster = await findClusterByUIDAndClusterID({ + uid: userInfo.uid, + clusterId: clusterId + }); + + return jsonRes(res, { + data: cluster + }); + } catch (error) { + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/cluster/getRecord.ts b/service/license/src/pages/api/cluster/getRecord.ts new file mode 100644 index 00000000000..9061ad409cc --- /dev/null +++ b/service/license/src/pages/api/cluster/getRecord.ts @@ -0,0 +1,28 @@ +import { authSession } from '@/services/backend/auth'; +import { getClusterRecordsByUid } from '@/services/backend/db/cluster'; +import { jsonRes } from '@/services/backend/response'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const payload = await authSession(req.headers); + if (!payload) return jsonRes(res, { code: 401, message: 'token verify error' }); + + const { page = 1, pageSize = 10 } = req.body as { + page: number; + pageSize: number; + }; + + const result = await getClusterRecordsByUid({ + uid: payload.uid, + page: page, + pageSize: pageSize + }); + + return jsonRes(res, { + data: result + }); + } catch (error) { + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/create.ts b/service/license/src/pages/api/license/create.ts new file mode 100644 index 00000000000..5ffa5d5cea4 --- /dev/null +++ b/service/license/src/pages/api/license/create.ts @@ -0,0 +1,54 @@ +import { authSession } from '@/services/backend/auth'; +import { + createLicenseRecord, + generateLicenseToken, + hasIssuedLicense +} from '@/services/backend/db/license'; +import { getPaymentByID } from '@/services/backend/db/payment'; +import { jsonRes } from '@/services/backend/response'; +import { CreateLicenseParams, LicenseRecordPayload, PaymentStatus } from '@/types'; +import type { NextApiRequest, NextApiResponse } from 'next'; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + try { + const { orderID } = req.body as CreateLicenseParams; + + const userInfo = await authSession(req.headers); + if (!userInfo) { + return jsonRes(res, { code: 401, message: 'token verify error' }); + } + const payment = await getPaymentByID({ uid: userInfo.uid, orderID: orderID }); + if (!payment) { + return jsonRes(res, { code: 400, message: 'No order found' }); + } + const issuedLicense = await hasIssuedLicense({ uid: userInfo.uid, orderID: orderID }); + if (issuedLicense) { + return jsonRes(res, { code: 400, message: 'orderID cannot be reused' }); + } + + const _token = generateLicenseToken({ type: 'Account', data: { amount: payment.amount } }); + const record: LicenseRecordPayload = { + uid: userInfo.uid, + amount: payment.amount, + token: _token, + orderID: orderID, + quota: payment.amount, + payMethod: payment.payMethod, + type: 'Account' + }; + + if (payment.status !== PaymentStatus.PaymentSuccess) { + return jsonRes(res, { + code: 400, + message: 'Unpaid' + }); + } + + const result = await createLicenseRecord(record); + return jsonRes(res, { + data: result + }); + } catch (error) { + jsonRes(res, { code: 500, data: error }); + } +} diff --git a/service/license/src/pages/api/license/createLicenseRecord.ts b/service/license/src/pages/api/license/createLicenseRecord.ts deleted file mode 100644 index d815bf72f0a..00000000000 --- a/service/license/src/pages/api/license/createLicenseRecord.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { authSession } from '@/services/backend/auth'; -import { createLicenseRecord, generateLicenseToken } from '@/services/backend/db/license'; -import { jsonRes } from '@/services/backend/response'; -import { LicensePayload } from '@/types'; -import type { NextApiRequest, NextApiResponse } from 'next'; - -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { - try { - const payload = await authSession(req.headers); - if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); - - const { orderID, amount, quota, payMethod, type } = req.body as LicensePayload; - - const _token = generateLicenseToken({ type: type, data: { amount: quota } }); - - const record = { - uid: payload.uid, - amount: amount, - token: _token, - orderID: orderID, - quota: quota, - payMethod: payMethod, - type: type - }; - - const result = await createLicenseRecord(record); - - return jsonRes(resp, { - data: result - }); - } catch (error) { - jsonRes(resp, { code: 500, data: error }); - } -} diff --git a/service/license/src/pages/api/license/getLicenseRecord.ts b/service/license/src/pages/api/license/getRecord.ts similarity index 70% rename from service/license/src/pages/api/license/getLicenseRecord.ts rename to service/license/src/pages/api/license/getRecord.ts index 510ddc12f5a..dbaec13e877 100644 --- a/service/license/src/pages/api/license/getLicenseRecord.ts +++ b/service/license/src/pages/api/license/getRecord.ts @@ -3,10 +3,10 @@ import { getLicenseRecordsByUid } from '@/services/backend/db/license'; import { jsonRes } from '@/services/backend/response'; import type { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { +export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { const payload = await authSession(req.headers); - if (!payload) return jsonRes(resp, { code: 401, message: 'token verify error' }); + if (!payload) return jsonRes(res, { code: 401, message: 'token verify error' }); const { page = 1, pageSize = 10 } = req.body as { page: number; @@ -19,10 +19,10 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse pageSize: pageSize }); - return jsonRes(resp, { + return jsonRes(res, { data: result }); } catch (error) { - jsonRes(resp, { code: 500, data: error }); + jsonRes(res, { code: 500, data: error }); } } diff --git a/service/license/src/pages/api/oss/get.ts b/service/license/src/pages/api/oss/get.ts index c467f1b772b..de7d31b056c 100644 --- a/service/license/src/pages/api/oss/get.ts +++ b/service/license/src/pages/api/oss/get.ts @@ -1,24 +1,17 @@ import { authSession } from '@/services/backend/auth'; +import { getOssUrl } from '@/services/backend/db/oss'; import { jsonRes } from '@/services/backend/response'; import type { NextApiRequest, NextApiResponse } from 'next'; const OSS = require('ali-oss'); + export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { fileName } = req.body as { fileName: string }; + const { fileName } = req.query as { fileName: string }; const userInfo = await authSession(req.headers); if (!userInfo) return jsonRes(res, { code: 401, message: 'token verify error' }); - const client = new OSS({ - region: 'oss-cn-hangzhou', - accessKeyId: process.env.ALI_OSS_KEY_ID, - accessKeySecret: process.env.ALI_OSS_KEY_SECRET, - bucket: 'sealos-io' - }); - // 生成用于下载文件的签名URL。 - const url = client.signatureUrl(fileName, { - // expires: 30 * 60 // 默认30分钟 最长60分钟 - }); + const url = await getOssUrl({ fileName }); return jsonRes(res, { data: url diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts index eef89dd54c7..f3fa3b8c435 100644 --- a/service/license/src/pages/api/payment/checkWechat.ts +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -1,5 +1,5 @@ import { authSession } from '@/services/backend/auth'; -import { findRecentNopayOrder, updatePaymentAndIssueLicense } from '@/services/backend/db/payment'; +import { findRecentNopayOrder } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; import { PaymentResult, PaymentStatus } from '@/types'; @@ -40,18 +40,18 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }) }).then((res) => res.json()); - if (result.status === PaymentStatus.PaymentSuccess) { - await updatePaymentAndIssueLicense({ - uid: userInfo.uid, - amount: payment.amount, - quota: payment.amount, - payMethod: payment.payMethod, - // pay status - orderID: payment?.orderID, - status: result.status, - type: 'Account' - }); - } + // if (result.status === PaymentStatus.PaymentSuccess) { + // await updatePaymentAndIssueLicense({ + // uid: userInfo.uid, + // amount: payment.amount, + // quota: payment.amount, + // payMethod: payment.payMethod, + // // pay status + // orderID: payment?.orderID, + // status: result.status, + // type: 'Account' + // }); + // } return jsonRes(res, { data: result diff --git a/service/license/src/pages/api/payment/create.ts b/service/license/src/pages/api/payment/create.ts index 77bb820e62b..86b5f1f772c 100644 --- a/service/license/src/pages/api/payment/create.ts +++ b/service/license/src/pages/api/payment/create.ts @@ -8,12 +8,17 @@ import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - const { amount, currency, payMethod } = req.body as PaymentParams; - + const { + amount, + currency, + payMethod, + stripeCallBackUrl = '/license' + } = req.body as PaymentParams; + const STRIPE_CALLBACK_URL = process.env.STRIPE_CALLBACK_URL; const userInfo = await authSession(req.headers); if (!userInfo) return jsonRes(res, { code: 401, message: 'token verify error' }); const { sealosPayUrl, sealosPayID, sealosPayKey } = getSealosPay(); - if (!sealosPayUrl) + if (!sealosPayUrl || !STRIPE_CALLBACK_URL) return jsonRes(res, { code: 500, message: 'sealos payment has not been activated' }); const result: PaymentData = await fetch(`${sealosPayUrl}/v1alpha1/pay/session`, { @@ -24,10 +29,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) amount: amount, currency: currency, user: userInfo.uid, - payMethod: payMethod + payMethod: payMethod, + stripeSuccessUrl: `${STRIPE_CALLBACK_URL}${stripeCallBackUrl}?stripeState=success`, + stripeCancelUrl: `${STRIPE_CALLBACK_URL}${stripeCallBackUrl}?stripeState=error` }) }).then((res) => res.json()); - console.log(result, 'PaymentData'); let payRecord: PaymentDB = { ...result, diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts index ae1ed4ba93a..4b4e7ef99c1 100644 --- a/service/license/src/pages/api/payment/result.ts +++ b/service/license/src/pages/api/payment/result.ts @@ -1,17 +1,14 @@ import { authSession } from '@/services/backend/auth'; import { hasIssuedLicense } from '@/services/backend/db/license'; -import { getPaymentByID, updatePaymentAndIssueLicense } from '@/services/backend/db/payment'; +import { getPaymentByID, updatePaymentStatus } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; -import { PaymentResult, PaymentStatus } from '@/types'; +import { PaymentResult, PaymentResultParams, PaymentStatus } from '@/types'; import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { - // test - // const _token = generateLicenseToken({ type: 'Account', data: { amount: 299 } }); - - const { orderID } = req.body as { orderID: string }; + const { orderID } = req.body as PaymentResultParams; const userInfo = await authSession(req.headers); if (!userInfo) { return jsonRes(res, { code: 401, message: 'token verify error' }); @@ -44,21 +41,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }) }).then((res) => res.json()); - if (result.status === PaymentStatus.PaymentSuccess) { - await updatePaymentAndIssueLicense({ - uid: userInfo.uid, - amount: payment.amount, - quota: payment.amount, - payMethod: payment.payMethod, - // pay status - orderID: orderID, - status: result.status, - type: 'Account' - }); - } + const updateStatusResult = await updatePaymentStatus({ + orderID: payment?.orderID, + status: result.status, + uid: userInfo.uid + }); + console.log(updateStatusResult, 'updateStatusResult'); return jsonRes(res, { - data: result + data: updateStatusResult }); } catch (error) { console.error(error, '===payment error===\n'); diff --git a/service/license/src/pages/api/price/bonus.ts b/service/license/src/pages/api/price/bonus.ts index eb6d131455b..4c59cc8e7f6 100644 --- a/service/license/src/pages/api/price/bonus.ts +++ b/service/license/src/pages/api/price/bonus.ts @@ -2,13 +2,13 @@ import { authSession } from '@/services/backend/auth'; import { jsonRes } from '@/services/backend/response'; import type { NextApiRequest, NextApiResponse } from 'next'; -export default async function handler(req: NextApiRequest, resp: NextApiResponse) { +export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { const payload = await authSession(req.headers); if (!payload) { - return jsonRes(resp, { code: 401, message: 'token verify error' }); + return jsonRes(res, { code: 401, message: 'token verify error' }); } - return jsonRes(resp, { + return jsonRes(res, { code: 200, data: { ratios: '10,15,20,25,30', @@ -18,6 +18,6 @@ export default async function handler(req: NextApiRequest, resp: NextApiResponse }); } catch (error) { console.log(error); - jsonRes(resp, { code: 500, message: 'get price bonus error' }); + jsonRes(res, { code: 500, message: 'get price bonus error' }); } } diff --git a/service/license/src/pages/cluster/components/Record.tsx b/service/license/src/pages/cluster/components/Record.tsx new file mode 100644 index 00000000000..867a9cface4 --- /dev/null +++ b/service/license/src/pages/cluster/components/Record.tsx @@ -0,0 +1,111 @@ +import { getClusterRecord } from '@/api/cluster'; +import { ClusterIcon, EmptyIcon, RightIcon } from '@/components/Icon'; +import Pagination from '@/components/Pagination'; +import { ClusterType } from '@/types'; +import { Box, Center, Flex, Text } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; +import { useState } from 'react'; + +export type TClusterRecord = { + changeClusterId: (id: string) => void; + clusterId: string; +}; + +export default function ClusterRecord({ changeClusterId, clusterId }: TClusterRecord) { + const { t } = useTranslation(); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + + const { data } = useQuery(['getClusterRecord', page, pageSize], () => + getClusterRecord({ + page: page, + pageSize: pageSize + }) + ); + + return ( + + + {t('Cluster List')} + + {data?.records && data?.records?.length > 0 ? ( + + {data?.records.map((item, i) => ( + changeClusterId(item?.clusterId)} + > + + + + + {t('Cluster')} {i + 1} + +
+ {t(item.type)} +
+
+
+ + + + {t('Deploy')} + + + +
+ ))} +
+ ) : ( + + + + {t('You have not purchased the License')} + + + )} + + {}} /> + +
+ ); +} diff --git a/service/license/src/pages/cluster/components/Tutorial.tsx b/service/license/src/pages/cluster/components/Tutorial.tsx new file mode 100644 index 00000000000..d5359764ad5 --- /dev/null +++ b/service/license/src/pages/cluster/components/Tutorial.tsx @@ -0,0 +1,299 @@ +import { findClusterById } from '@/api/cluster'; +import { getFileByName } from '@/api/oos'; +import CodeBlock from '@/components/CodeBlock'; +import { CheckListIcon, DownloadIcon, OfflineIcon, OnlineComputerIcon } from '@/components/Icon'; +import { useCopyData } from '@/hooks/useCopyData'; +import { ClusterType } from '@/types'; +import { downloadFromURL } from '@/utils/downloadFIle'; +import { + Accordion, + AccordionButton, + AccordionIcon, + AccordionItem, + AccordionPanel, + Box, + Center, + Divider, + Flex, + Link, + Text +} from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; +import { useState } from 'react'; + +export default function Tutorial({ clusterId }: { clusterId: string }) { + const { t } = useTranslation(); + const { copyData } = useCopyData(); + const [ossLink, setOssLink] = useState(''); + const { data } = useQuery( + ['findClusterByIds', clusterId], + () => + findClusterById({ + clusterId + }), + { + async onSuccess(data) { + if (data?.orderID && data.type === ClusterType.Enterprise) { + const _link = await getFileByName('/cloud/sealos-cloud-dev.tar.gz'); + console.log(_link); + setOssLink(_link); + } + } + } + ); + + return ( + + + 集群安装教程 + + + + + + + 准备工作 + + + + + + 服务器 + + + + 奇数台 + + 的 master 服务器及任意的 node 服务器。推荐使用 ubuntu 22.04 LTS linux + 发行版,操作系统内核在 5.4 以上。 + + + 服务器配置: + + + + + + + 推荐配置 + + + + + CPU + 内存 + 存储卷 + + + 4 Core + + 8 G + + 100 G + + + + 最小配置 + + + + CPU + 内存 + 存储卷 + + + 2 Core + + 4 G + + 60 G + + + + + 网络 + + + 服务器之间的网络互通,其中 + + master0 + + (执行 sealos cli 的 master 节点)可以通过 ssh + 免密登陆到其他节点;所有节点间可以互相通信。 + + + + 域名 + + + 你需要一个域名,用于访问 Sealos 及你将部署的各种服务。如果您没有域名,可以使用 + + nip.io + + 提供的免费域名服务。 + + + + 证书 + + + Sealos 需要使用证书来保证通信安全,默认在您不提供证书的情况下我们会使用 + + cret-manager + + 来自动签发证书。 + + + 如果您能提供证书,证书需要解析下列域名(假设您提供的域名为:cloud.example.io): + + + + + 1 + + *.cloud.example.io + + + + 2 + + cloud.example.io + + + + + + {data?.type === ClusterType.Enterprise && ( + + + + + 离线安装 + + + + + + 下载离线包 + +
downloadFromURL(ossLink)} + > + + 点击下载 +
+ + + 服务器上下载 + + + {/* + + + + + 验证 + + + + + + + + */} + + + 部署集群 + + +
+
+ )} + + + + + + 在线安装 + + + + + + + +
+
+ ); +} diff --git a/service/license/src/pages/cluster/index.tsx b/service/license/src/pages/cluster/index.tsx index 089d34917cb..e4c6cef3993 100644 --- a/service/license/src/pages/cluster/index.tsx +++ b/service/license/src/pages/cluster/index.tsx @@ -1 +1,85 @@ -export default function Cluster() {} +import { getClusterRecord } from '@/api/cluster'; +import { EmptyIcon } from '@/components/Icon'; +import Layout from '@/components/Layout'; +import { compareFirstLanguages } from '@/utils/tools'; +import { Flex, Spinner, Text } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import { useEffect, useState } from 'react'; +import ClusterRecord from './components/Record'; +import Tutorial from './components/Tutorial'; + +export default function MyCluster() { + const [clusterId, setClusterId] = useState(''); + const { t } = useTranslation(); + + const changeClusterId = (id: string) => { + setClusterId(id); + }; + + const { data, isLoading, isSuccess } = useQuery( + ['getClusterRecord'], + () => + getClusterRecord({ + page: 1, + pageSize: 10 + }), + { + enabled: !clusterId, + onSuccess(data) { + changeClusterId(data?.records?.[0]?.clusterId); + } + } + ); + + // if (isLoading) { + // return ( + // + // + // + // + // + // ); + // } + + if (isSuccess && data?.total === 0) { + return ( + + + + + {t('You have not purchased the Cluster')} + + + + ); + } + + return ( + + + + + + + ); +} + +export async function getServerSideProps({ req, res, locales }: any) { + const local = + req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); + res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); + + return { + props: { + ...(await serverSideTranslations(local, undefined, null, locales || [])) + } + }; +} diff --git a/service/license/src/pages/index.tsx b/service/license/src/pages/index.tsx index a8f2290b31d..4a2c13d2467 100644 --- a/service/license/src/pages/index.tsx +++ b/service/license/src/pages/index.tsx @@ -5,7 +5,7 @@ const NonePage = () => { const router = useRouter(); useEffect(() => { - router.push('/license'); + router.push('/pricing'); }, [router]); return
; diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index bc637ae37f8..fdeefbecabf 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -1,6 +1,6 @@ -import { checkWechatPay, createPayment, getPaymentResult } from '@/api/payment'; +import { checkWechatPay, createPayment, handlePaymentResult } from '@/api/payment'; import { getSystemEnv } from '@/api/system'; -import { StripeIcon, WechatIcon } from '@/components/icons'; +import { StripeIcon, WechatIcon } from '@/components/Icon'; import useBonusBox from '@/hooks/useBonusBox'; import { PaymentStatus, TPayMethod, WechatPaymentData } from '@/types'; import { deFormatMoney } from '@/utils/tools'; @@ -23,7 +23,8 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; import { useCallback, useEffect, useState } from 'react'; -import WechatPayment from './WechatPayment'; +import WechatPayment from '@/components/WechatPayment'; +import { createLicense } from '@/api/license'; export default function RechargeComponent() { const router = useRouter(); @@ -75,11 +76,11 @@ export default function RechargeComponent() { createPayment({ amount: deFormatMoney(selectAmount).toString(), payMethod: payType, - currency: 'CNY' + currency: 'CNY', + stripeCallBackUrl: '/license' }), { async onSuccess(data) { - // setPaymentData({ ...data, payMethod: payType }); if (payType === 'stripe' && platformEnv && data?.sessionID) { const stripe = await loadStripe(platformEnv?.stripePub); stripe?.redirectToCheckout({ @@ -104,14 +105,11 @@ export default function RechargeComponent() { } ); - useQuery(['getLicenseResult', orderID], () => getPaymentResult({ orderID }), { - refetchInterval: complete === 2 ? 3 * 1000 : false, - enabled: complete === 2 && !!orderID, - cacheTime: 0, - staleTime: 0, - onSuccess(data) { - console.log(data, 'getLicenseResult'); - if (data.status === PaymentStatus.PaymentSuccess) { + const licenseMutation = useMutation( + ({ orderID }: { orderID: string }) => createLicense({ orderID }), + { + onSuccess(data) { + console.log(data, 'licenseMutation'); onClosePayment(); toast({ status: 'success', @@ -120,6 +118,28 @@ export default function RechargeComponent() { position: 'top' }); queryClient.invalidateQueries(['getLicenseActive']); + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); + } + } + ); + + useQuery(['getPaymentResult', orderID], () => handlePaymentResult({ orderID }), { + refetchInterval: complete === 2 ? 3 * 1000 : false, + enabled: complete === 2 && !!orderID, + cacheTime: 0, + staleTime: 0, + onSuccess(data) { + console.log(data, 'getPaymentResult'); + if (data.status === PaymentStatus.PaymentSuccess) { + licenseMutation.mutate({ orderID: data.orderID }); } }, onError(err: any) { @@ -149,15 +169,16 @@ export default function RechargeComponent() { useEffect(() => { const { stripeState, orderID } = router.query; + console.log(stripeState, orderID); + const clearQuery = () => { + router.replace({ + pathname: '/license', + query: null + }); + }; if (stripeState === 'success') { setComplete(2); setOrderID(orderID as string); - const clearQuery = () => { - router.replace({ - pathname: '/license', - query: null - }); - }; setTimeout(clearQuery, 0); } else if (stripeState === 'error') { toast({ @@ -168,6 +189,7 @@ export default function RechargeComponent() { position: 'top' }); onClosePayment(); + setTimeout(clearQuery, 0); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -269,7 +291,7 @@ export default function RechargeComponent() { )}
- + 充值金额 diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index 12320f54a02..60ac515c7bb 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -1,12 +1,12 @@ import { getLicenseRecord } from '@/api/license'; -import { DownloadIcon, EmptyIcon, LicenseIcon, TokenIcon } from '@/components/icons'; +import { DownloadIcon, EmptyIcon, LicenseIcon, TokenIcon } from '@/components/Icon'; import { download } from '@/utils/downloadFIle'; import { formatMoney, getRemainingTime } from '@/utils/tools'; import { Box, Flex, Text } from '@chakra-ui/react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useState } from 'react'; -import Pagination from './Pagination'; +import Pagination from '@/components/Pagination'; import CurrencySymbol from './CurrencySymbol'; import { json2License } from '@/utils/json2Yaml'; @@ -43,7 +43,7 @@ export default function History() { {data?.records.map((item) => ( Token - downloadToken(item.token)}> + downloadToken(item.token)}> - +
))} @@ -97,7 +97,6 @@ export default function History() {
)} - {}} /> diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx index 26e2cfa0399..d418957425b 100644 --- a/service/license/src/pages/license/index.tsx +++ b/service/license/src/pages/license/index.tsx @@ -1,70 +1,43 @@ -import LangSelectSimple from '@/components/LangSelect'; -import Account from '@/components/account'; -import { Flex, Image, Text } from '@chakra-ui/react'; -import { useTranslation } from 'next-i18next'; +import { getLicenseRecord } from '@/api/license'; +import Layout from '@/components/Layout'; +import { compareFirstLanguages } from '@/utils/tools'; +import { Flex, Spinner } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -import { useRouter } from 'next/router'; import RechargeComponent from './components/Recharge'; import LicenseRecord from './components/Record'; -import { getFileByName } from '@/api/oos'; -import { downloadFromURL } from '@/utils/downloadFIle'; export default function LicensePage() { - const { t } = useTranslation(); - const router = useRouter(); - const goHome = () => router.replace('/'); + const { isLoading } = useQuery(['getLicenseActive'], () => + getLicenseRecord({ + page: 1, + pageSize: 10 + }) + ); + + if (isLoading) { + return ( + + + + + + ); + } return ( - - {/* { - getFileByName('token.txt').then((res) => { - console.log(res); - downloadFromURL(res); - }); - }} - > - ceshi - */} - - logo - - Sealos - - - | {t('License Buy')} - - - - + - + ); } export async function getServerSideProps({ req, res, locales }: any) { - const lang: string = req?.headers?.['accept-language'] || 'zh'; - const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; + const local = + req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); return { diff --git a/service/license/src/pages/pricing/components/Product.tsx b/service/license/src/pages/pricing/components/Product.tsx new file mode 100644 index 00000000000..0b6d346ab64 --- /dev/null +++ b/service/license/src/pages/pricing/components/Product.tsx @@ -0,0 +1,464 @@ +import { createCluster, createClusterAndLicense } from '@/api/cluster'; +import { checkWechatPay, createPayment, handlePaymentResult } from '@/api/payment'; +import { getSystemEnv } from '@/api/system'; +import { StripeIcon, SuccessIcon } from '@/components/Icon'; +import { company, contect, standard } from '@/constant/product'; +import { ClusterType, PaymentStatus, TPayMethod, WechatPaymentData } from '@/types'; +import { + AbsoluteCenter, + Box, + Button, + Center, + Divider, + Flex, + Modal, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + Spinner, + Text, + useDisclosure, + useToast +} from '@chakra-ui/react'; +import { loadStripe } from '@stripe/stripe-js'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; +import { QRCodeSVG } from 'qrcode.react'; +import { useCallback, useEffect, useState } from 'react'; +import ServicePackage from './ServicePackage'; +import useRouteParamsStore from '@/stores/routeParams'; +import useSessionStore from '@/stores/session'; + +export default function Product() { + const { t } = useTranslation(); + const queryClient = useQueryClient(); + const router = useRouter(); + const { isOpen, onOpen, onClose } = useDisclosure(); + // const { isOpen: isOpenStatus, onOpen: onOpenSuccess, onClose: onCloseSuccess } = useDisclosure(); + const toast = useToast({ position: 'top', duration: 2000 }); + // 整个流程跑通需要状态管理, 0 初始态, 1 创建支付单, 2 支付中, 3 支付成功 + const [complete, setComplete] = useState<0 | 1 | 2 | 3>(0); + const [payType, setPayType] = useState('wechat'); + const [clusterType, setClusterType] = useState(ClusterType.Standard); + const [orderID, setOrderID] = useState(''); + const [wechatData, setWechatData] = useState(); + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + const [remainingSeconds, setRemainingSeconds] = useState(2); // 初始值为2秒 + const { data: routeParams, setRouteParams, clearRouteParams } = useRouteParamsStore(); + const { isUserLogin } = useSessionStore(); + + const onClosePayment = useCallback(() => { + setOrderID(''); + setComplete(0); + onClose(); + }, [onClose]); + + const openPayModal = () => { + setComplete(1); + setPayType('wechat'); + paymentMutation.mutate((599 * 100).toString()); + onOpen(); + }; + + const handleStripePay = () => { + setComplete(1); + setPayType('stripe'); + paymentMutation.mutate((599 * 100).toString()); + }; + + const handleProductByType = (type: ClusterType) => { + setClusterType(type); + if (type === ClusterType.Standard) { + onOpen(); + clusterMutation.mutate({ type: ClusterType.Standard }); + } + if (type === ClusterType.Enterprise) { + openPayModal(); + } + if (type === ClusterType.Contact) { + window.open( + 'https://fael3z0zfze.feishu.cn/share/base/form/shrcnesSfEK65JZaAf2W6Fwz6Ad', + '_blank' + ); + } + }; + + const paymentMutation = useMutation( + (amount: string) => + createPayment({ + amount: amount, + payMethod: payType, + currency: 'CNY', + stripeCallBackUrl: '/pricing' + }), + { + async onSuccess(data) { + if (payType === 'stripe' && platformEnv && data?.sessionID) { + const stripe = await loadStripe(platformEnv?.stripePub); + stripe?.redirectToCheckout({ + sessionId: data.sessionID + }); + } + if (payType === 'wechat' && data?.tradeNO && data?.codeURL) { + setOrderID(data.orderID); + setWechatData({ tradeNO: data?.tradeNO, codeURL: data?.codeURL }); + setComplete(2); + } + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); + } + } + ); + + const clusterMutation = useMutation( + ({ type }: { type: ClusterType }) => createCluster({ type }), + { + onSuccess(data) { + console.log(data, 'clusterMutation'); + setComplete(3); + queryClient.invalidateQueries(['getClusterRecord']); + // onClosePayment(); + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); + } + } + ); + + const clusterAndLicenseMutation = useMutation( + ({ type, orderID }: { type: ClusterType; orderID: string }) => + createClusterAndLicense({ orderID, type: type }), + { + onSuccess(data) { + console.log(data, 'clusterAndLicenseMutation'); + setComplete(3); + queryClient.invalidateQueries(['getClusterRecord']); + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); + } + } + ); + + useQuery(['getPaymentResult', orderID], () => handlePaymentResult({ orderID }), { + refetchInterval: complete === 2 ? 3 * 1000 : false, + enabled: complete === 2 && !!orderID, + cacheTime: 0, + staleTime: 0, + onSuccess(data) { + console.log(data, 'getPaymentResult'); + if (data.status === PaymentStatus.PaymentSuccess) { + clusterAndLicenseMutation.mutate({ orderID: data.orderID, type: ClusterType.Enterprise }); + } + }, + onError(err: any) { + toast({ + status: 'error', + title: err?.message || '', + isClosable: true, + position: 'top' + }); + setComplete(0); + } + }); + + useQuery(['checkWechatPay'], () => checkWechatPay(), { + onSuccess(data) { + if (data.status === PaymentStatus.PaymentSuccess) { + toast({ + status: 'success', + title: t('License issued successfully'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + } + } + }); + + // handle stripe + useEffect(() => { + const { stripeState, orderID } = router.query; + const clearQuery = () => { + router.replace({ + pathname: '/pricing', + query: null + }); + }; + if (stripeState === 'success') { + toast({ + status: 'success', + title: t('Checking Payment Results'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + setComplete(2); + setOrderID(orderID as string); + setTimeout(clearQuery, 0); + } else if (stripeState === 'error') { + toast({ + status: 'error', + duration: 3000, + title: t('Stripe Cancel'), + isClosable: true, + position: 'top' + }); + onClosePayment(); + setTimeout(clearQuery, 0); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // handle success + useEffect(() => { + if (complete === 3) { + onOpen(); + const timer = setInterval(() => { + if (remainingSeconds > 0) { + setRemainingSeconds(remainingSeconds - 1); + } else { + clearInterval(timer); + router.push('/cluster'); + } + }, 1000); + + return () => { + clearInterval(timer); + }; + } + }, [complete, onOpen, remainingSeconds, router]); + + // handle Jump link + useEffect(() => { + const { clusterType, external } = router.query; + const isLogin = isUserLogin(); + console.log(clusterType, external); + + if (!isLogin) { + setRouteParams(external as string, clusterType as ClusterType); + } else if (routeParams.clusterType) { + handleProductByType(routeParams.clusterType as ClusterType); + clearRouteParams(); + } else { + console.log(11); + handleProductByType(clusterType as ClusterType); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + + + + + 标准版 + + + + ¥0 + +
+ 赠 ¥299 +
+
+ + 适合开发者测试,或 POC demo + + +
+ + + 企业版 + + + + ¥599 + +
+ 赠 ¥599 +
+
+ + 适合企业生产环境 + + +
+ + + 定制版 + + + 适合大规模集群与大型企业客户 + {/* Suitable for large-scale clusters and large enterprise customers */} + + + +
+ + + + + + {complete !== 3 && } + {complete === 3 ? ( + + + + {t('Cluster Pay Success', { + clusterType: t(clusterType) + })} + + + {remainingSeconds} 后跳转至集群部署页 + + + ) : ( + + {payType === 'wechat' ? ( + <> + + {t('Scan with WeChat')} + + + {complete === 2 && !!wechatData?.codeURL ? ( + + ) : ( + + )} + + + {t('Order Number')}: {wechatData?.tradeNO || ''} + + + ) : ( + + )} + + + + + 其他方式支付 + + + + + )} + + +
+ ); +} diff --git a/service/license/src/pages/pricing/components/ServicePackage.tsx b/service/license/src/pages/pricing/components/ServicePackage.tsx new file mode 100644 index 00000000000..afd9c8b5d3b --- /dev/null +++ b/service/license/src/pages/pricing/components/ServicePackage.tsx @@ -0,0 +1,34 @@ +import { CheckIcon, StarIcon } from '@/components/Icon'; +import { ServiceItem } from '@/constant/product'; +import { Divider, Flex, Text } from '@chakra-ui/react'; +import { ReactNode } from 'react'; + +type ServicePackageProps = { + items: ServiceItem[]; + children: ReactNode; +}; + +export default function ServicePackage({ items, children }: ServicePackageProps) { + return ( + + {children} + + {items?.map((item) => ( + + {item.icon === 'check' ? : } + + {item.label} + + + ))} + + ); +} diff --git a/service/license/src/pages/pricing/index.tsx b/service/license/src/pages/pricing/index.tsx index e69de29bb2d..0e55e7cfb73 100644 --- a/service/license/src/pages/pricing/index.tsx +++ b/service/license/src/pages/pricing/index.tsx @@ -0,0 +1,24 @@ +import Layout from '@/components/Layout'; +import { compareFirstLanguages } from '@/utils/tools'; +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import Product from './components/Product'; + +export default function Pricing() { + return ( + + + + ); +} + +export async function getServerSideProps({ req, res, locales }: any) { + const local = + req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); + res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); + + return { + props: { + ...(await serverSideTranslations(local, undefined, null, locales || [])) + } + }; +} diff --git a/service/license/src/pages/signin.tsx b/service/license/src/pages/signin.tsx index a50f4e28a7f..62949501a67 100644 --- a/service/license/src/pages/signin.tsx +++ b/service/license/src/pages/signin.tsx @@ -1,4 +1,5 @@ -import SigninComponent from '@/components/signin'; +import SigninComponent from '@/components/SignIn'; +import { compareFirstLanguages } from '@/utils/tools'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; export default function SigninPage() { @@ -6,8 +7,8 @@ export default function SigninPage() { } export async function getServerSideProps({ req, res, locales }: any) { - const lang: string = req?.headers?.['accept-language'] || 'zh'; - const local = lang.indexOf('zh') !== -1 ? 'zh' : 'en'; + const local = + req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); const props = { diff --git a/service/license/src/services/backend/db/cluster.ts b/service/license/src/services/backend/db/cluster.ts new file mode 100644 index 00000000000..27a120b27ca --- /dev/null +++ b/service/license/src/services/backend/db/cluster.ts @@ -0,0 +1,127 @@ +import { ClusterDB, ClusterRecordPayload, ClusterType, LicenseRecordPayload } from '@/types'; +import { createLicenseRecord, findLicenseByUIDAndOrderID } from './license'; +import { connectToDatabase } from './mongodb'; +import { getOssUrl } from './oss'; +import { v4 as uuid } from 'uuid'; + +async function connectClusterCollection() { + const client = await connectToDatabase(); + const collection = client.db().collection('cluster'); + return collection; +} + +export async function createClusterRecord(payload: ClusterRecordPayload) { + const collection = await connectClusterCollection(); + const now = new Date(); + const expirationTime = new Date(now.getTime() + 30 * 60000); // 30 minutes in milliseconds + const tarUrl = await getOssUrl({ fileName: 'sealos-cloud-dev.tar.gz' }); + const md5Url = await getOssUrl({ fileName: 'sealos-cloud-dev.tar.gz.md5' }); + + let orderID; + let licenseID; + + if (payload.type === ClusterType.Enterprise) { + // 当类型为 'company' 时,设置 orderID 和 licenseID + orderID = payload.orderID; + const _license = await findLicenseByUIDAndOrderID({ + uid: payload.uid, + orderID: payload?.orderID || '' + }); + licenseID = _license?._id; + } + + const record: ClusterDB = { + clusterId: uuid(), + uid: payload.uid, // user ID + orderID: orderID, // order ID + licenseID: licenseID, // license ID + type: payload.type, + createdAt: new Date(), + updatedAt: new Date() + }; + + const result = await collection.insertOne(record); + return result; +} + +export async function getClusterRecordsByUid({ + uid, + page, + pageSize +}: { + uid: string; + page: number; + pageSize: number; +}) { + const collection = await connectClusterCollection(); + + const skip = (page - 1) * pageSize; + + const query = { uid: uid }; + const options = { + skip: skip, + limit: pageSize + }; + + // Find records for the specified uid, skip records based on pagination, and limit the result to pageSize + const records = await collection.find(query, options).toArray(); + + // Calculate the total count of records for the given uid + const totalCount = await collection.countDocuments(query); + + const result = { + records: records, + total: totalCount + }; + + return result; +} + +export async function createClusterAndLicense({ + licensePayload, + clusterPayload +}: { + licensePayload: LicenseRecordPayload; + clusterPayload: ClusterRecordPayload; +}) { + const db = await connectToDatabase(); + const session = db.startSession(); + try { + session.startTransaction(); + // 创建许可证记录 + const licenseResult = await createLicenseRecord(licensePayload); + // 创建集群记录 + const clusterResult = await createClusterRecord({ + ...clusterPayload, + licenseID: licenseResult.insertedId + }); + + if (!clusterResult || !licenseResult) { + throw new Error('Failed to create cluster or license record'); + } + + await session.commitTransaction(); + } catch (err) { + console.log(`[Transaction] Error: ${err}`); + await session.abortTransaction(); + } finally { + session.endSession(); + } +} + +export async function findClusterByUIDAndClusterID({ + uid, + clusterId +}: { + uid: string; + clusterId: string; +}) { + const collection = await connectClusterCollection(); + + const cluster = await collection.findOne( + { uid, clusterId }, + { projection: { _id: 0, uid: 0, updatedAt: 0 } } + ); + + return cluster; +} diff --git a/service/license/src/services/backend/db/license.ts b/service/license/src/services/backend/db/license.ts index 2662107da0f..aa033e69614 100644 --- a/service/license/src/services/backend/db/license.ts +++ b/service/license/src/services/backend/db/license.ts @@ -3,7 +3,7 @@ import { base64Decode } from '@/utils/tools'; import { sign } from 'jsonwebtoken'; import { connectToDatabase } from './mongodb'; -async function connectLicenseRecordCollection() { +async function connectLicenseCollection() { const client = await connectToDatabase(); const collection = client.db().collection('license'); return collection; @@ -18,7 +18,7 @@ export async function createLicenseRecord({ payMethod, type }: LicenseRecordPayload) { - const collection = await connectLicenseRecordCollection(); + const collection = await connectLicenseCollection(); const now = Math.floor(Date.now() / 1000); // Get current timestamp in seconds const oneDayInSeconds = 3 * 24 * 60 * 60; @@ -44,6 +44,25 @@ export async function createLicenseRecord({ return result; } +export async function findLicenseByUIDAndOrderID({ + uid, + orderID +}: { + uid: string; + orderID: string; +}) { + const collection = await connectLicenseCollection(); + + const query = { + uid: uid, + orderID: orderID + }; + + const licenseRecord = await collection.findOne(query); + + return licenseRecord; +} + export async function getLicenseRecordsByUid({ uid, page, @@ -53,7 +72,7 @@ export async function getLicenseRecordsByUid({ page: number; pageSize: number; }) { - const collection = await connectLicenseRecordCollection(); + const collection = await connectLicenseCollection(); const skip = (page - 1) * pageSize; @@ -83,7 +102,7 @@ export function generateLicenseToken(payload: LicenseToken) { throw new Error('LICENSE PRIVATE KEY IS MISSING'); } const nowInSeconds = Math.floor(Date.now() / 1000); - const expirationTime = nowInSeconds + 3 * 24 * 60 * 60; + const expirationTime = nowInSeconds + 3 * 24 * 60 * 60; //默认三天有效时间 const _payload = { iss: 'Sealos', @@ -98,7 +117,7 @@ export function generateLicenseToken(payload: LicenseToken) { export async function hasIssuedLicense({ uid, orderID }: { uid: string; orderID: string }) { try { - const collection = await connectLicenseRecordCollection(); + const collection = await connectLicenseCollection(); const existingLicense = await collection.findOne({ uid: uid, diff --git a/service/license/src/services/backend/db/oss.ts b/service/license/src/services/backend/db/oss.ts new file mode 100644 index 00000000000..de49a6864ef --- /dev/null +++ b/service/license/src/services/backend/db/oss.ts @@ -0,0 +1,26 @@ +const OSS = require('ali-oss'); + +export function getOssUrl({ + fileName, + bucket = 'sealos-io', + region = 'oss-cn-hangzhou', + expires = 30 * 60 +}: { + fileName: string; + expires?: number; + bucket?: string; + region?: string; +}) { + const client = new OSS({ + region: region, + accessKeyId: process.env.ALI_OSS_KEY_ID, + accessKeySecret: process.env.ALI_OSS_KEY_SECRET, + bucket: bucket + }); + // 生成用于下载文件的签名URL。 + const url = client.signatureUrl(fileName, { + expires: expires // 默认30分钟 最长60分钟 + }); + + return url; +} diff --git a/service/license/src/services/backend/db/payment.ts b/service/license/src/services/backend/db/payment.ts index 9c0e722b51b..e87747099fc 100644 --- a/service/license/src/services/backend/db/payment.ts +++ b/service/license/src/services/backend/db/payment.ts @@ -1,6 +1,5 @@ -import { LicenseRecordPayload, LicenseType, PaymentDB, PaymentStatus, TPayMethod } from '@/types'; +import { PaymentDB, PaymentStatus, TPayMethod } from '@/types'; import { connectToDatabase } from './mongodb'; -import { createLicenseRecord, generateLicenseToken } from './license'; async function connectPaymentCollection() { const client = await connectToDatabase(); @@ -45,71 +44,77 @@ export async function updatePaymentStatus({ status: status, updatedAt: new Date() } + }, + { + projection: { + status: 1, + orderID: 1, + message: 1 + } } ); return result; } -export async function updatePaymentAndIssueLicense({ - uid, - orderID, - status, - amount, - quota, - payMethod, - type -}: { - uid: string; - orderID: string; - status: PaymentStatus; - amount: number; - quota: number; - payMethod: TPayMethod; - type: LicenseType; -}) { - const db = await connectToDatabase(); - const session = db.startSession(); - - // const transactionOptions = { - // readConcern: { level: 'majority' }, - // writeConcern: { w: 'majority' }, - // readPreference: 'primary', - // } - - try { - session.startTransaction(); - console.log('事务状态:', session.transaction); - await updatePaymentStatus({ - uid: uid, - orderID: orderID, - status: status - }); - - // 在事务中执行生成许可证记录操作 - const _token = generateLicenseToken({ type: type, data: { amount: amount } }); - const record = { - uid: uid, - amount: amount, - token: _token, - orderID: orderID, - quota: quota, - payMethod: payMethod, - type: type - }; - console.log(record, 'record'); - - await createLicenseRecord(record); - - await session.commitTransaction(); - } catch (err) { - console.log(`[MongoDB transaction] ERROR: ${err}`); - await session.abortTransaction(); - } finally { - await session.endSession(); - console.log('事务状态:', session.transaction); - } -} +// export async function updatePaymentAndIssueLicense({ +// uid, +// orderID, +// status, +// amount, +// quota, +// payMethod, +// type +// }: { +// uid: string; +// orderID: string; +// status: PaymentStatus; +// amount: number; +// quota: number; +// payMethod: TPayMethod; +// type: LicenseType; +// }) { +// const db = await connectToDatabase(); +// const session = db.startSession(); + +// // const transactionOptions = { +// // readConcern: { level: 'majority' }, +// // writeConcern: { w: 'majority' }, +// // readPreference: 'primary', +// // } + +// try { +// session.startTransaction(); +// console.log('事务状态:', session.transaction); +// await updatePaymentStatus({ +// uid: uid, +// orderID: orderID, +// status: status +// }); + +// // 在事务中执行生成许可证记录操作 +// const _token = generateLicenseToken({ type: type, data: { amount: amount } }); +// const record = { +// uid: uid, +// amount: amount, +// token: _token, +// orderID: orderID, +// quota: quota, +// payMethod: payMethod, +// type: type +// }; +// console.log(record, 'license record'); +// await createLicenseRecord(record); + +// await session.commitTransaction(); +// } catch (err) { +// console.log(`[MongoDB transaction] ERROR: ${err}`); +// await session.abortTransaction(); +// } finally { +// await session.endSession(); +// console.log('事务状态:', session.transaction); +// } +// } export async function findRecentNopayOrder({ uid, diff --git a/service/license/src/stores/routeParams.ts b/service/license/src/stores/routeParams.ts new file mode 100644 index 00000000000..0454ecbb686 --- /dev/null +++ b/service/license/src/stores/routeParams.ts @@ -0,0 +1,45 @@ +import { ClusterType } from '@/types'; +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; +import { immer } from 'zustand/middleware/immer'; + +type RouteParamsState = { + data: { + external: string | null; + clusterType: ClusterType | null; + }; + setRouteParams: (isExternal: string | null, type: ClusterType | null) => void; + clearRouteParams: () => void; +}; + +const useRouteParamsStore = create()( + persist( + immer((set, get) => ({ + data: { + clusterType: null, + external: null + }, + setRouteParams: (isExternal, type) => { + set({ + data: { + external: isExternal, + clusterType: type + } + }); + }, + clearRouteParams: () => { + set({ + data: { + external: null, + clusterType: null + } + }); + } + })), + { + name: 'routeparams' + } + ) +); + +export default useRouteParamsStore; diff --git a/service/license/src/styles/chakraTheme.ts b/service/license/src/styles/chakraTheme.ts index 17073e21deb..d9e1818b332 100644 --- a/service/license/src/styles/chakraTheme.ts +++ b/service/license/src/styles/chakraTheme.ts @@ -2,7 +2,7 @@ import { defineStyleConfig, extendTheme } from '@chakra-ui/react'; const Button = defineStyleConfig({ baseStyle: { - borderRadius: '4px' + borderRadius: '6px' }, sizes: { sm: {}, diff --git a/service/license/src/styles/prism.css b/service/license/src/styles/prism.css new file mode 100644 index 00000000000..6d311320f13 --- /dev/null +++ b/service/license/src/styles/prism.css @@ -0,0 +1,13 @@ +pre { + background-color: #24282c !important; + color: #fff; +} + +.operator { + color: #91ded9; +} + +.token.function, +.token.builtin { + color: #5ebdf2; +} diff --git a/service/license/src/types/cluster.ts b/service/license/src/types/cluster.ts new file mode 100644 index 00000000000..fe191ddca8b --- /dev/null +++ b/service/license/src/types/cluster.ts @@ -0,0 +1,48 @@ +import { ObjectId } from 'mongodb'; + +export enum ClusterType { + Standard = 'Standard', + Enterprise = 'Enterprise', + Contact = 'Contact' +} + +export type ClusterDB = { + _id?: ObjectId; // cluster ID 唯一 + clusterId: string; // cluster ID 唯一 + uid: string; // user ID 唯一 + orderID?: string; // order ID 唯一 + licenseID?: ObjectId; // license ID + // amount: number; + type: ClusterType; // license type + // ossUrl?: { + // tar: string; + // md5: string; + // creationTime: Date; + // expirationTime: Date; + // }; + createdAt: Date; // Creation timestamp + updatedAt: Date; // Modification timestamp +}; + +export type ClusterRecordPayload = { + uid: string; // user ID + orderID?: string; // order ID + licenseID?: ObjectId; // license ID + // amount: number; + // tar: string; + // md5: string; + type: ClusterType; // license type +}; + +export type CreateClusterParams = { + orderID: string; // order ID + type: ClusterType; // license type +}; + +export type ClusterResult = { + clusterId: string; // cluster ID 唯一 + uid: string; // user ID 唯一 + orderID?: string; // order ID 唯一 + licenseID?: ObjectId; // license ID + type: ClusterType; // license type +}; diff --git a/service/license/src/types/index.ts b/service/license/src/types/index.ts index 0904b1e287b..00be4f99597 100644 --- a/service/license/src/types/index.ts +++ b/service/license/src/types/index.ts @@ -5,6 +5,7 @@ export * from './payment'; export * from './system'; export * from './login'; export * from './license'; +export * from './cluster'; declare global { var mongodb: MongoClient | null; diff --git a/service/license/src/types/license.ts b/service/license/src/types/license.ts index a3e8fe6b827..1ad5d4d395b 100644 --- a/service/license/src/types/license.ts +++ b/service/license/src/types/license.ts @@ -1,10 +1,11 @@ +import { ObjectId } from 'mongodb'; import { TPayMethod } from './payment'; export type LicenseDB = { - _id?: string; - uid: string; // user id + _id?: ObjectId; // 唯一 + uid: string; // user id 唯一 token: string; // license token - orderID: string; // order number + orderID: string; // order number 唯一 payMethod: TPayMethod; service: { quota: number; // 额度 @@ -27,14 +28,6 @@ export type LicenseRecordPayload = { type: LicenseType; }; -export type LicensePayload = { - amount: number; - orderID: string; - quota: number; - payMethod: TPayMethod; - type: LicenseType; -}; - // new export type LicenseToken = { type: LicenseType; @@ -44,3 +37,7 @@ export type LicenseToken = { }; export type LicenseType = 'Account' | 'Cluster'; + +export type CreateLicenseParams = { + orderID: string; +}; diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index 5ee54bdccb9..7be21157a6e 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -1,10 +1,10 @@ export type PaymentDB = { - uid: string; + uid: string; // 用户ID 唯一 amount: number; // quota: number; codeURL?: string; currency: string; - orderID: string; + orderID: string; // 账单ID 唯一 tradeNO?: string; sessionID?: string; payMethod: TPayMethod; @@ -15,6 +15,8 @@ export type PaymentDB = { export type TPayMethod = 'stripe' | 'wechat'; +export type StripeCallBackUrl = '/pricing' | '/license'; + export enum PaymentStatus { PaymentNotPaid = 'notpaid', // 未支付 PaymentProcessing = 'processing', // 支付中 @@ -28,6 +30,11 @@ export type PaymentParams = { amount: string; currency: 'CNY'; payMethod: TPayMethod; + stripeCallBackUrl: StripeCallBackUrl; +}; + +export type PaymentResultParams = { + orderID: string; }; export type PaymentData = { diff --git a/service/license/src/types/user.ts b/service/license/src/types/user.ts index c3896d4724c..9c6cab4f6ae 100644 --- a/service/license/src/types/user.ts +++ b/service/license/src/types/user.ts @@ -1,3 +1,5 @@ +import { ObjectId } from 'mongodb'; + export type TgithubToken = { access_token: string; expires_in: number; @@ -72,8 +74,10 @@ export type OauthProvider = Exclude; export type TUserExist = { user: string; exist: boolean }; +// User DB export type User = { - uid: string; + _id?: ObjectId; // 唯一 + uid: string; // 唯一 avatar_url: string; name: string; created_time: string; diff --git a/service/license/src/utils/tools.ts b/service/license/src/utils/tools.ts index 805646ddad6..6da6b7f9ef3 100644 --- a/service/license/src/utils/tools.ts +++ b/service/license/src/utils/tools.ts @@ -96,3 +96,11 @@ export const formatMoney = (money: number) => { }; export const deFormatMoney = (money: number) => money * 100; + +export function compareFirstLanguages(acceptLanguageHeader: string) { + const indexOfZh = acceptLanguageHeader.indexOf('zh'); + const indexOfEn = acceptLanguageHeader.indexOf('en'); + if (indexOfZh === -1) return 'en'; + if (indexOfEn === -1 || indexOfZh < indexOfEn) return 'zh'; + return 'en'; +} From 1d6a67d93a547bbadd2ee489b05dd3923997c62a Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Fri, 27 Oct 2023 17:00:10 +0800 Subject: [PATCH 14/17] fix build Signed-off-by: jingyang <3161362058@qq.com> --- .../license/src/components/Account/index.tsx | 92 ++++++++ .../license/src/components/Layout/index.tsx | 2 +- .../components/Signin/auth/useAuthList.tsx | 98 +++++++++ .../components/Signin/auth/useCustomError.tsx | 61 +++++ .../components/Signin/auth/useLanguage.tsx | 27 +++ .../components/Signin/auth/usePassword.tsx | 208 ++++++++++++++++++ .../components/Signin/auth/useProtocol.tsx | 70 ++++++ .../src/components/Signin/auth/useSms.tsx | 188 ++++++++++++++++ .../src/components/Signin/background.tsx | 44 ++++ .../license/src/components/Signin/index.tsx | 201 +++++++++++++++++ .../license/src/components/signin/index.tsx | 12 +- .../license/components/CurrencySymbol.tsx | 2 +- .../pages/license/components/OuterLink.tsx | 2 +- service/license/src/pages/signin.tsx | 2 +- 14 files changed, 999 insertions(+), 10 deletions(-) create mode 100644 service/license/src/components/Account/index.tsx create mode 100644 service/license/src/components/Signin/auth/useAuthList.tsx create mode 100644 service/license/src/components/Signin/auth/useCustomError.tsx create mode 100644 service/license/src/components/Signin/auth/useLanguage.tsx create mode 100644 service/license/src/components/Signin/auth/usePassword.tsx create mode 100644 service/license/src/components/Signin/auth/useProtocol.tsx create mode 100644 service/license/src/components/Signin/auth/useSms.tsx create mode 100644 service/license/src/components/Signin/background.tsx create mode 100644 service/license/src/components/Signin/index.tsx diff --git a/service/license/src/components/Account/index.tsx b/service/license/src/components/Account/index.tsx new file mode 100644 index 00000000000..ffbd1fa5a4a --- /dev/null +++ b/service/license/src/components/Account/index.tsx @@ -0,0 +1,92 @@ +import useSessionStore from '@/stores/session'; +import { Box, Flex, Image, useDisclosure, Text, Divider } from '@chakra-ui/react'; +import { SignOutIcon } from '../Icon'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; + +export default function Account() { + const { t } = useTranslation(); + const router = useRouter(); + const { delSession, getSession } = useSessionStore(); + const userInfo = getSession(); + const accountDisclosure = useDisclosure(); + + const logout = (e: React.MouseEvent) => { + e.preventDefault(); + delSession(); + router.replace('/signin'); + }; + + return ( + + user avator + {accountDisclosure.isOpen && ( + <> + { + e.stopPropagation(); + accountDisclosure.onClose(); + }} + > + + + + user avator + {userInfo?.user?.name} + + + + + + {t('Log Out')} + + + + + )} + + ); +} diff --git a/service/license/src/components/Layout/index.tsx b/service/license/src/components/Layout/index.tsx index 18a83257e4c..65e8b312a50 100644 --- a/service/license/src/components/Layout/index.tsx +++ b/service/license/src/components/Layout/index.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'next-i18next'; import { useRouter } from 'next/router'; import { ReactNode, useState } from 'react'; import LangSelectSimple from '../LangSelect'; -import Account from '../Account'; +import Account from '@/components/Account'; export default function Layout({ children }: { children: ReactNode }) { const { t } = useTranslation(); diff --git a/service/license/src/components/Signin/auth/useAuthList.tsx b/service/license/src/components/Signin/auth/useAuthList.tsx new file mode 100644 index 00000000000..fea1a1ddeff --- /dev/null +++ b/service/license/src/components/Signin/auth/useAuthList.tsx @@ -0,0 +1,98 @@ +import { getSystemEnv } from '@/api/system'; +import { GithubIcon, GoogleIcon, WechatIcon } from '@/components/Icon'; +import useSessionStore from '@/stores/session'; +import { OauthProvider } from '@/types/user'; +import { Button, Flex, Icon } from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { MouseEventHandler } from 'react'; + +const useAuthList = () => { + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + + const { + needGithub = false, + needWechat = false, + needGoogle = false, + wechat_client_id = '', + github_client_id = '', + google_client_id = '', + callback_url = '' + } = platformEnv || {}; + const { generateState, setProvider } = useSessionStore(); + + const oauthLogin = async ({ url, provider }: { url: string; provider?: OauthProvider }) => { + setProvider(provider); + window.location.href = url; + }; + + const authList: { icon: typeof Icon; cb: MouseEventHandler; need: boolean }[] = [ + { + // src: '/images/github.svg', + icon: GithubIcon, + cb: (e) => { + e.preventDefault(); + const state = generateState(); + oauthLogin({ + provider: 'github', + url: `https://github.com/login/oauth/authorize?client_id=${github_client_id}&redirect_uri=${callback_url}&scope=user:email%20read:user&state=${state}` + }); + }, + need: needGithub + }, + { + icon: WechatIcon, + cb: (e) => { + e.preventDefault(); + const state = generateState(); + oauthLogin({ + provider: 'wechat', + url: `https://open.weixin.qq.com/connect/qrconnect?appid=${wechat_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}&scope=snsapi_login&#wechat_redirect` + }); + }, + need: needWechat + }, + { + icon: GoogleIcon, + cb: (e) => { + e.preventDefault(); + const state = generateState(); + const scope = encodeURIComponent(`https://www.googleapis.com/auth/userinfo.profile openid`); + oauthLogin({ + provider: 'google', + //https://www.googleapis.com/auth/userinfo.profile + url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${google_client_id}&redirect_uri=${callback_url}&response_type=code&state=${state}&scope=${scope}&include_granted_scopes=true` + }); + }, + need: needGoogle + } + ]; + + const AuthList = () => { + return ( + + {authList + .filter((item) => item.need) + .map((item, index) => ( + + ))} + + ); + }; + + return { + AuthList + }; +}; + +export default useAuthList; diff --git a/service/license/src/components/Signin/auth/useCustomError.tsx b/service/license/src/components/Signin/auth/useCustomError.tsx new file mode 100644 index 00000000000..7b807b71744 --- /dev/null +++ b/service/license/src/components/Signin/auth/useCustomError.tsx @@ -0,0 +1,61 @@ +import { Flex, Img, Button, Text } from '@chakra-ui/react'; +import React, { useState, useEffect } from 'react'; +import { WarningIcon, CloseIcon } from '@/components/Icon'; +import { useTranslation } from 'next-i18next'; + +const useCustomError = () => { + const { t } = useTranslation(); + const [error, setError] = useState(''); + + const showError = (errorMessage: string, duration = 5000) => { + setError(errorMessage); + setTimeout(() => { + setError(''); + }, duration); + }; + + const closeError = () => { + setError(''); + }; + + const ErrorComponent = () => { + useEffect(() => { + if (error) { + const timeout = setTimeout(() => { + closeError(); + }, 5000); // 默认 5000 毫秒(5秒)后自动关闭错误消息 + return () => clearTimeout(timeout); + } + }, []); + + return error ? ( + + + {t(error)} + + + ) : null; + }; + + return { showError, ErrorComponent }; +}; + +export default useCustomError; diff --git a/service/license/src/components/Signin/auth/useLanguage.tsx b/service/license/src/components/Signin/auth/useLanguage.tsx new file mode 100644 index 00000000000..8aaecd6e928 --- /dev/null +++ b/service/license/src/components/Signin/auth/useLanguage.tsx @@ -0,0 +1,27 @@ +import LangSelectSimple from '@/components/LangSelect'; +import { Flex, UseDisclosureReturn } from '@chakra-ui/react'; +import { I18n } from 'next-i18next'; + +type LanguageType = { disclosure: UseDisclosureReturn; i18n: I18n | null }; + +const Language = ({ disclosure, i18n }: LanguageType) => { + return ( + + + + ); +}; + +export default Language; diff --git a/service/license/src/components/Signin/auth/usePassword.tsx b/service/license/src/components/Signin/auth/usePassword.tsx new file mode 100644 index 00000000000..4e3a41bde1b --- /dev/null +++ b/service/license/src/components/Signin/auth/usePassword.tsx @@ -0,0 +1,208 @@ +import { signInByPassword } from '@/api/user'; +import { LocklIcon, PersonIcon, VectorIcon } from '@/components/Icon'; +import useSessionStore from '@/stores/session'; +import { Flex, Input, InputGroup, InputLeftAddon, Text } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { useRouter } from 'next/router'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; + +export default function usePassword({ + showError +}: { + showError: (errorMessage: string, duration?: number) => void; +}) { + const { t } = useTranslation(); + const router = useRouter(); + const [userExist, setUserExist] = useState(true); + const [isLoading, setIsLoading] = useState(false); + // 对于注册的用户,需要先验证密码 0 默认页面;1为验证密码页面 + const [pageState, setPageState] = useState(0); + + const setSession = useSessionStore((s) => s.setSession); + + const { register, handleSubmit, watch, trigger, getValues } = useForm<{ + username: string; + password: string; + confimPassword: string; + }>(); + + const login = async () => { + const deepSearch = (obj: any): string => { + if (!obj || typeof obj !== 'object') return t('Submit Error'); + if (!!obj.message) { + return obj.message; + } + return deepSearch(Object.values(obj)[0]); + }; + + handleSubmit( + async (data) => { + if (data?.username && data?.password) { + try { + setIsLoading(true); + const result = await signInByPassword(data.username, data.password); + setSession(result); + router.replace('/'); + } catch (error: any) { + console.log(error); + showError(t('Invalid username or password')); + } finally { + setIsLoading(false); + } + } + }, + (err) => { + console.log(err); + showError(deepSearch(err)); + } + )(); + }; + + const PasswordComponent = () => { + if (pageState === 0) { + return ; + } else { + return ; + } + }; + + const PasswordModal = () => { + return ( + <> + + + + + + + + + + + + + + ); + }; + + const ConfirmPasswordModal = () => { + return ( + <> + + setPageState(0)} + /> + {t('Verify password')} + + + + + + + + + ); + }; + + return { + PasswordComponent, + login, + userExist, + pageState, + isLoading + }; +} diff --git a/service/license/src/components/Signin/auth/useProtocol.tsx b/service/license/src/components/Signin/auth/useProtocol.tsx new file mode 100644 index 00000000000..36574dab25c --- /dev/null +++ b/service/license/src/components/Signin/auth/useProtocol.tsx @@ -0,0 +1,70 @@ +import { Checkbox, Flex, Link, Text, TextProps } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import { useState } from 'react'; + +const useProtocol = ({ + service_protocol, + private_protocol +}: { + service_protocol: string; + private_protocol: string; +}) => { + const { t, i18n } = useTranslation(); + const [isAgree, setIsAgree] = useState(false); + const [isInvalid, setIsInvalid] = useState(false); + + const Protocol = () => ( + + { + setIsInvalid(false); + setIsAgree(e.target.checked); + }} + /> + + {t('agree policy')} + + {t('Service Agreement')} + + {t('and')} + + {t('Privacy Policy')} + + + + ); + return { + Protocol, + isAgree, + setIsInvalid + }; +}; + +export default useProtocol; diff --git a/service/license/src/components/Signin/auth/useSms.tsx b/service/license/src/components/Signin/auth/useSms.tsx new file mode 100644 index 00000000000..c98b2e127d5 --- /dev/null +++ b/service/license/src/components/Signin/auth/useSms.tsx @@ -0,0 +1,188 @@ +import { sendCodeByPhone, signInByPhone } from '@/api/user'; +import { CodeDoneIcon, SafetyIcon } from '@/components/Icon'; +import useSessionStore from '@/stores/session'; +import { Input, InputGroup, InputLeftAddon, InputRightAddon, Link, Text } from '@chakra-ui/react'; +import { useTranslation } from 'next-i18next'; +import NextLink from 'next/link'; +import { useRouter } from 'next/router'; +import { MouseEventHandler, useEffect, useRef, useState } from 'react'; +import { useForm } from 'react-hook-form'; + +export default function useSms({ + showError +}: { + showError: (errorMessage: string, duration?: number) => void; +}) { + const { t } = useTranslation(); + const _remainTime = useRef(0); + const router = useRouter(); + const { setSession } = useSessionStore(); + const [isLoading, setIsLoading] = useState(false); + + const { register, handleSubmit, trigger, getValues } = useForm<{ + phoneNumber: string; + verifyCode: string; + }>(); + + const login = async () => { + const deepSearch = (obj: any): string => { + if (!obj || typeof obj !== 'object') return t('Submit Error'); + if (!!obj.message) { + return obj.message; + } + return deepSearch(Object.values(obj)[0]); + }; + + handleSubmit( + async (data) => { + try { + setIsLoading(true); + const result = await signInByPhone(data.phoneNumber, data.verifyCode); + setSession(result); + router.replace('/'); + } catch (error) { + console.log(error); + showError(t('Invalid verification code') || 'Invalid verification code'); + } finally { + setIsLoading(false); + } + }, + (err) => { + showError(deepSearch(err)); + } + )(); + }; + + const SmsModal = () => { + const [remainTime, setRemainTime] = useState(_remainTime.current); + + useEffect(() => { + if (remainTime <= 0) return; + const interval = setInterval(() => { + setRemainTime(remainTime - 1); + }, 1000); + return () => clearInterval(interval); + }, [remainTime]); + + const getCode: MouseEventHandler = async (e) => { + e.preventDefault(); + + if (!(await trigger('phoneNumber'))) { + showError(t('Invalid phone number') || 'Invalid phone number'); + return; + } + setRemainTime(60); + _remainTime.current = 60; + + try { + await sendCodeByPhone(getValues('phoneNumber')); + } catch (err) { + showError(t('Get code failed') || 'Get code failed'); + setRemainTime(0); + _remainTime.current = 0; + } + }; + + return ( + <> + + + + +86 + + + + + + {remainTime <= 0 ? ( + + {t('Get Code')} + + ) : ( + {remainTime} s + )} + + + + + + + + + + {getValues('verifyCode')?.length === 6 && } + + + + ); + }; + + return { + SmsModal, + login, + isLoading + }; +} diff --git a/service/license/src/components/Signin/background.tsx b/service/license/src/components/Signin/background.tsx new file mode 100644 index 00000000000..7fd3f1b4761 --- /dev/null +++ b/service/license/src/components/Signin/background.tsx @@ -0,0 +1,44 @@ +import { Box, Flex, Image, Text } from '@chakra-ui/react'; + +export default function Background() { + return ( + <> + bg + bg + bg + + logo + + Sealos + + + | License + + + + ); +} diff --git a/service/license/src/components/Signin/index.tsx b/service/license/src/components/Signin/index.tsx new file mode 100644 index 00000000000..214ecc35a41 --- /dev/null +++ b/service/license/src/components/Signin/index.tsx @@ -0,0 +1,201 @@ +import { getSystemEnv } from '@/api/system'; +import useAuthList from '@/components/Signin/auth/useAuthList'; +import useCustomError from '@/components/Signin/auth/useCustomError'; +import Language from '@/components/Signin/auth/useLanguage'; +import usePassword from '@/components/Signin/auth/usePassword'; +import useProtocol from '@/components/Signin/auth/useProtocol'; +import useSms from '@/components/Signin/auth/useSms'; +import useSessionStore from '@/stores/session'; +import { LoginType } from '@/types'; +import { + Box, + Button, + Flex, + Img, + Tab, + TabIndicator, + TabList, + Tabs, + Image, + useDisclosure +} from '@chakra-ui/react'; +import { useQuery } from '@tanstack/react-query'; +import { debounce } from 'lodash'; +import { useTranslation } from 'next-i18next'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import sealosTitle from 'public/images/sealos-title.png'; +import { useEffect, useMemo, useState } from 'react'; +import Background from './background'; + +export default function SigninComponent() { + const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + + const { + service_protocol = '', + private_protocol = '', + needPassword = false, + needSms = false + } = platformEnv || {}; + + const needTabs = needPassword && needSms; + + const disclosure = useDisclosure(); + const { t, i18n } = useTranslation(); + const [tabIndex, setTabIndex] = useState(LoginType.NONE); + + const { ErrorComponent, showError } = useCustomError(); + + const { Protocol, isAgree, setIsInvalid } = useProtocol({ service_protocol, private_protocol }); + const { SmsModal, login: smsSubmit, isLoading: smsLoading } = useSms({ showError }); + const { + PasswordComponent, + pageState, + login: passwordSubmit, + isLoading: passwordLoading + } = usePassword({ showError }); + const isLoading = useMemo(() => passwordLoading || smsLoading, [passwordLoading, smsLoading]); + const isSignIn = useSessionStore((s) => s.isUserLogin); + const router = useRouter(); + + useEffect(() => { + if (isSignIn()) { + router.push('/pricing'); + } + }, [isSignIn, router]); + + const { AuthList } = useAuthList(); + + const loginConfig = useMemo(() => { + return { + [LoginType.SMS]: { + login: smsSubmit, + component: + }, + [LoginType.PASSWORD]: { + login: passwordSubmit, + component: + }, + [LoginType.NONE]: null + }; + }, [PasswordComponent, SmsModal, passwordSubmit, smsSubmit]); + + useEffect(() => { + setTabIndex(needSms ? LoginType.SMS : needPassword ? LoginType.PASSWORD : LoginType.NONE); + }, [needPassword, needSms]); + + const LoginComponent = useMemo( + () => (tabIndex !== LoginType.NONE ? loginConfig[tabIndex].component : null), + [loginConfig, tabIndex] + ); + + const handleLogin = debounce(() => { + const selectedConfig = loginConfig[tabIndex]; + if (isAgree && selectedConfig) { + const { login } = selectedConfig; + login(); + } else { + setIsInvalid(true); + showError(t('Read and agree')); + } + }, 500); + + return ( + + + + sealos Cloud + + + + + + + + + + {pageState === 0 && needTabs && ( + setTabIndex(idx)} + variant="unstyled" + p={'0'} + width={'full'} + > + + + {t('Verification Code Login')} + + + {t('Password Login')} + + + + + )} + + {LoginComponent} + + + + + + + + + + ); +} diff --git a/service/license/src/components/signin/index.tsx b/service/license/src/components/signin/index.tsx index 01c0e7fba67..214ecc35a41 100644 --- a/service/license/src/components/signin/index.tsx +++ b/service/license/src/components/signin/index.tsx @@ -1,10 +1,10 @@ import { getSystemEnv } from '@/api/system'; -import useAuthList from '@/components/SignIn/auth/useAuthList'; -import useCustomError from '@/components/SignIn/auth/useCustomError'; -import Language from '@/components/SignIn/auth/useLanguage'; -import usePassword from '@/components/SignIn/auth/usePassword'; -import useProtocol from '@/components/SignIn/auth/useProtocol'; -import useSms from '@/components/SignIn/auth/useSms'; +import useAuthList from '@/components/Signin/auth/useAuthList'; +import useCustomError from '@/components/Signin/auth/useCustomError'; +import Language from '@/components/Signin/auth/useLanguage'; +import usePassword from '@/components/Signin/auth/usePassword'; +import useProtocol from '@/components/Signin/auth/useProtocol'; +import useSms from '@/components/Signin/auth/useSms'; import useSessionStore from '@/stores/session'; import { LoginType } from '@/types'; import { diff --git a/service/license/src/pages/license/components/CurrencySymbol.tsx b/service/license/src/pages/license/components/CurrencySymbol.tsx index 2c6c5e5b8d7..81be6a82531 100644 --- a/service/license/src/pages/license/components/CurrencySymbol.tsx +++ b/service/license/src/pages/license/components/CurrencySymbol.tsx @@ -1,5 +1,5 @@ import { Text, Icon, IconProps } from '@chakra-ui/react'; -export default function currencysymbol({ +export default function Currencysymbol({ type = 'shellCoin', ...props }: { diff --git a/service/license/src/pages/license/components/OuterLink.tsx b/service/license/src/pages/license/components/OuterLink.tsx index 9b347bc4364..dcd73f0f314 100644 --- a/service/license/src/pages/license/components/OuterLink.tsx +++ b/service/license/src/pages/license/components/OuterLink.tsx @@ -1,7 +1,7 @@ import { Flex, Link } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; -export default function Index({ text, href }: { text: string; href?: string }) { +export default function OuterLink({ text, href }: { text: string; href?: string }) { const { t } = useTranslation(); return ( diff --git a/service/license/src/pages/signin.tsx b/service/license/src/pages/signin.tsx index 62949501a67..ea8dab7689e 100644 --- a/service/license/src/pages/signin.tsx +++ b/service/license/src/pages/signin.tsx @@ -1,4 +1,4 @@ -import SigninComponent from '@/components/SignIn'; +import SigninComponent from '@/components/Signin'; import { compareFirstLanguages } from '@/utils/tools'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; From 290f36f59f699cbde1079b6aed93b1de31367f31 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Fri, 27 Oct 2023 22:00:34 +0800 Subject: [PATCH 15/17] fix oss && only zh Signed-off-by: jingyang <3161362058@qq.com> --- .../license/src/components/Layout/index.tsx | 3 +- service/license/src/pages/_app.tsx | 3 +- .../src/pages/api/payment/checkWechat.ts | 21 ++++------- service/license/src/pages/callback.tsx | 2 +- .../src/pages/cluster/components/Tutorial.tsx | 11 ++++-- service/license/src/pages/cluster/index.tsx | 7 ++-- service/license/src/pages/index.tsx | 14 -------- .../src/pages/license/components/Recharge.tsx | 35 +++++++++++-------- service/license/src/pages/license/index.tsx | 2 +- .../src/pages/pricing/components/Product.tsx | 27 +++++++------- service/license/src/pages/pricing/index.tsx | 2 +- service/license/src/pages/signin.tsx | 2 +- .../license/src/services/backend/db/oss.ts | 3 +- service/license/src/stores/payment.ts | 23 +++++++----- service/license/src/stores/routeParams.ts | 2 +- 15 files changed, 79 insertions(+), 78 deletions(-) delete mode 100644 service/license/src/pages/index.tsx diff --git a/service/license/src/components/Layout/index.tsx b/service/license/src/components/Layout/index.tsx index 65e8b312a50..f485b89f52e 100644 --- a/service/license/src/components/Layout/index.tsx +++ b/service/license/src/components/Layout/index.tsx @@ -73,7 +73,8 @@ export default function Layout({ children }: { children: ReactNode }) { ); })} - + {/* */} +
{children} diff --git a/service/license/src/pages/_app.tsx b/service/license/src/pages/_app.tsx index 8e2a26791e6..3312455bb62 100644 --- a/service/license/src/pages/_app.tsx +++ b/service/license/src/pages/_app.tsx @@ -7,7 +7,7 @@ import '@stripe/stripe-js'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { appWithTranslation, useTranslation } from 'next-i18next'; import type { AppProps } from 'next/app'; -import Router from 'next/router'; +import Router, { useRouter } from 'next/router'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; import { useEffect } from 'react'; @@ -27,6 +27,7 @@ Router.events.on('routeChangeError', () => NProgress.done()); const App = ({ Component, pageProps }: AppProps) => { const { i18n } = useTranslation(); + const router = useRouter(); useEffect(() => { const lang = getCookie('NEXT_LOCALE'); diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts index f3fa3b8c435..37883831022 100644 --- a/service/license/src/pages/api/payment/checkWechat.ts +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -1,5 +1,5 @@ import { authSession } from '@/services/backend/auth'; -import { findRecentNopayOrder } from '@/services/backend/db/payment'; +import { findRecentNopayOrder, updatePaymentStatus } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; import { PaymentResult, PaymentStatus } from '@/types'; @@ -40,21 +40,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }) }).then((res) => res.json()); - // if (result.status === PaymentStatus.PaymentSuccess) { - // await updatePaymentAndIssueLicense({ - // uid: userInfo.uid, - // amount: payment.amount, - // quota: payment.amount, - // payMethod: payment.payMethod, - // // pay status - // orderID: payment?.orderID, - // status: result.status, - // type: 'Account' - // }); - // } + const updateStatusResult = await updatePaymentStatus({ + orderID: payment?.orderID, + status: result.status, + uid: userInfo.uid + }); return jsonRes(res, { - data: result + data: updateStatusResult }); } catch (error) { console.error(error, '===payment error===\n'); diff --git a/service/license/src/pages/callback.tsx b/service/license/src/pages/callback.tsx index 75401bd1a98..e1b7d4545e7 100644 --- a/service/license/src/pages/callback.tsx +++ b/service/license/src/pages/callback.tsx @@ -26,7 +26,7 @@ const Callback: NextPage = () => { const data = await signInByProvider(provider, code); setSession(data); - router.replace('/'); + router.replace('/pricing'); } catch (error) { router.replace('/signin'); } diff --git a/service/license/src/pages/cluster/components/Tutorial.tsx b/service/license/src/pages/cluster/components/Tutorial.tsx index d5359764ad5..c2e8e5fac06 100644 --- a/service/license/src/pages/cluster/components/Tutorial.tsx +++ b/service/license/src/pages/cluster/components/Tutorial.tsx @@ -22,7 +22,13 @@ import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'next-i18next'; import { useState } from 'react'; -export default function Tutorial({ clusterId }: { clusterId: string }) { +export default function Tutorial({ + clusterId, + ossFileName +}: { + clusterId: string; + ossFileName: string; +}) { const { t } = useTranslation(); const { copyData } = useCopyData(); const [ossLink, setOssLink] = useState(''); @@ -35,8 +41,7 @@ export default function Tutorial({ clusterId }: { clusterId: string }) { { async onSuccess(data) { if (data?.orderID && data.type === ClusterType.Enterprise) { - const _link = await getFileByName('/cloud/sealos-cloud-dev.tar.gz'); - console.log(_link); + const _link = await getFileByName(ossFileName); setOssLink(_link); } } diff --git a/service/license/src/pages/cluster/index.tsx b/service/license/src/pages/cluster/index.tsx index e4c6cef3993..05d7c85a459 100644 --- a/service/license/src/pages/cluster/index.tsx +++ b/service/license/src/pages/cluster/index.tsx @@ -10,7 +10,7 @@ import { useEffect, useState } from 'react'; import ClusterRecord from './components/Record'; import Tutorial from './components/Tutorial'; -export default function MyCluster() { +export default function MyCluster({ ossFileName }: { ossFileName: string }) { const [clusterId, setClusterId] = useState(''); const { t } = useTranslation(); @@ -66,7 +66,7 @@ export default function MyCluster() { - + ); @@ -75,10 +75,11 @@ export default function MyCluster() { export async function getServerSideProps({ req, res, locales }: any) { const local = req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); - res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); + res.setHeader('Set-Cookie', `NEXT_LOCALE=zh; Max-Age=2592000; Secure; SameSite=None`); return { props: { + ossFileName: process.env?.OSS_FILE_NAME || '/cloud/sealos-cloud-dev.tar.gz', ...(await serverSideTranslations(local, undefined, null, locales || [])) } }; diff --git a/service/license/src/pages/index.tsx b/service/license/src/pages/index.tsx deleted file mode 100644 index 4a2c13d2467..00000000000 --- a/service/license/src/pages/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { useEffect } from 'react'; -import { useRouter } from 'next/router'; - -const NonePage = () => { - const router = useRouter(); - - useEffect(() => { - router.push('/pricing'); - }, [router]); - - return
; -}; - -export default NonePage; diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index fdeefbecabf..513a53f6015 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -25,6 +25,7 @@ import { useRouter } from 'next/router'; import { useCallback, useEffect, useState } from 'react'; import WechatPayment from '@/components/WechatPayment'; import { createLicense } from '@/api/license'; +import usePaymentDataStore from '@/stores/payment'; export default function RechargeComponent() { const router = useRouter(); @@ -41,6 +42,8 @@ export default function RechargeComponent() { const [orderID, setOrderID] = useState(''); const [wechatPaymentData, setWechatPaymentData] = useState(); const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); + // 用于避免微信支付,窗口关闭后感知不到的问题 + // const { paymentData, setPaymentData, deletePaymentData } = usePaymentDataStore(); const onClosePayment = useCallback(() => { setOrderID(''); @@ -113,7 +116,7 @@ export default function RechargeComponent() { onClosePayment(); toast({ status: 'success', - title: t('Payment Successful'), // 这里改为license 签发成功 + title: t('License issued successfully'), isClosable: true, position: 'top' }); @@ -153,23 +156,25 @@ export default function RechargeComponent() { } }); - useQuery(['checkWechatPay'], () => checkWechatPay(), { - onSuccess(data) { - if (data.status === PaymentStatus.PaymentSuccess) { - toast({ - status: 'success', - title: t('License issued successfully'), // 这里改为license 签发成功 - isClosable: true, - duration: 9000, - position: 'top' - }); - } - } - }); + // checkWechatPay + // useQuery(['checkWechatPay'], () => checkWechatPay(), { + // enabled: !!paymentData?.orderId, + // onSuccess(data) { + // console.log(data, '------'); + // if (data.status === PaymentStatus.PaymentSuccess) { + // toast({ + // status: 'success', + // title: t('Payment Successful'), // 这里改为license 签发成功 + // isClosable: true, + // duration: 9000, + // position: 'top' + // }); + // } + // } + // }); useEffect(() => { const { stripeState, orderID } = router.query; - console.log(stripeState, orderID); const clearQuery = () => { router.replace({ pathname: '/license', diff --git a/service/license/src/pages/license/index.tsx b/service/license/src/pages/license/index.tsx index d418957425b..f439f25a6dc 100644 --- a/service/license/src/pages/license/index.tsx +++ b/service/license/src/pages/license/index.tsx @@ -38,7 +38,7 @@ export default function LicensePage() { export async function getServerSideProps({ req, res, locales }: any) { const local = req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); - res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); + res.setHeader('Set-Cookie', `NEXT_LOCALE=zh; Max-Age=2592000; Secure; SameSite=None`); return { props: { diff --git a/service/license/src/pages/pricing/components/Product.tsx b/service/license/src/pages/pricing/components/Product.tsx index 0b6d346ab64..c98cfc88f84 100644 --- a/service/license/src/pages/pricing/components/Product.tsx +++ b/service/license/src/pages/pricing/components/Product.tsx @@ -183,19 +183,20 @@ export default function Product() { } }); - useQuery(['checkWechatPay'], () => checkWechatPay(), { - onSuccess(data) { - if (data.status === PaymentStatus.PaymentSuccess) { - toast({ - status: 'success', - title: t('License issued successfully'), // 这里改为license 签发成功 - isClosable: true, - duration: 9000, - position: 'top' - }); - } - } - }); + // checkWechatPay + // useQuery(['checkWechatPay'], () => checkWechatPay(), { + // onSuccess(data) { + // if (data.status === PaymentStatus.PaymentSuccess) { + // toast({ + // status: 'success', + // title: t('License issued successfully'), // 这里改为license 签发成功 + // isClosable: true, + // duration: 9000, + // position: 'top' + // }); + // } + // } + // }); // handle stripe useEffect(() => { diff --git a/service/license/src/pages/pricing/index.tsx b/service/license/src/pages/pricing/index.tsx index 0e55e7cfb73..c55168d6358 100644 --- a/service/license/src/pages/pricing/index.tsx +++ b/service/license/src/pages/pricing/index.tsx @@ -14,7 +14,7 @@ export default function Pricing() { export async function getServerSideProps({ req, res, locales }: any) { const local = req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); - res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); + res.setHeader('Set-Cookie', `NEXT_LOCALE=zh; Max-Age=2592000; Secure; SameSite=None`); return { props: { diff --git a/service/license/src/pages/signin.tsx b/service/license/src/pages/signin.tsx index ea8dab7689e..235dd488fdb 100644 --- a/service/license/src/pages/signin.tsx +++ b/service/license/src/pages/signin.tsx @@ -9,7 +9,7 @@ export default function SigninPage() { export async function getServerSideProps({ req, res, locales }: any) { const local = req?.cookies?.NEXT_LOCALE || compareFirstLanguages(req?.headers?.['accept-language'] || 'zh'); - res.setHeader('Set-Cookie', `NEXT_LOCALE=${local}; Max-Age=2592000; Secure; SameSite=None`); + res.setHeader('Set-Cookie', `NEXT_LOCALE=zh; Max-Age=2592000; Secure; SameSite=None`); const props = { ...(await serverSideTranslations(local, undefined, null, locales || [])) diff --git a/service/license/src/services/backend/db/oss.ts b/service/license/src/services/backend/db/oss.ts index de49a6864ef..0205b4056e2 100644 --- a/service/license/src/services/backend/db/oss.ts +++ b/service/license/src/services/backend/db/oss.ts @@ -15,7 +15,8 @@ export function getOssUrl({ region: region, accessKeyId: process.env.ALI_OSS_KEY_ID, accessKeySecret: process.env.ALI_OSS_KEY_SECRET, - bucket: bucket + bucket: bucket, + secure: true }); // 生成用于下载文件的签名URL。 const url = client.signatureUrl(fileName, { diff --git a/service/license/src/stores/payment.ts b/service/license/src/stores/payment.ts index 6c553d7d580..0ac0b503f2b 100644 --- a/service/license/src/stores/payment.ts +++ b/service/license/src/stores/payment.ts @@ -1,19 +1,26 @@ -import { PaymentData } from '@/types'; import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; type PaymentDataState = { - paymentData: PaymentData | undefined; - setPaymentData: (data: PaymentData) => void; + paymentData?: { + orderId: string; + }; + setPaymentData: (data: { orderId: string }) => void; deletePaymentData: () => void; }; export const usePaymentDataStore = create( - immer((set) => ({ - paymentData: undefined, - setPaymentData: (data) => set({ paymentData: data }), - deletePaymentData: () => set({ paymentData: undefined }) - })) + persist( + immer((set) => ({ + paymentData: undefined, + setPaymentData: (data) => set({ paymentData: data }), + deletePaymentData: () => set({ paymentData: undefined }) + })), + { + name: 'paymentData' + } + ) ); export default usePaymentDataStore; diff --git a/service/license/src/stores/routeParams.ts b/service/license/src/stores/routeParams.ts index 0454ecbb686..1b7eef10988 100644 --- a/service/license/src/stores/routeParams.ts +++ b/service/license/src/stores/routeParams.ts @@ -37,7 +37,7 @@ const useRouteParamsStore = create()( } })), { - name: 'routeparams' + name: 'routeParams' } ) ); From be8ab21df47cf4f84898d66b793b7b5a1d0ad932 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Mon, 30 Oct 2023 11:09:08 +0800 Subject: [PATCH 16/17] feat checkout wechat Signed-off-by: jingyang <3161362058@qq.com> --- service/license/src/api/payment.ts | 11 +- .../src/components/Pagination/index.tsx | 2 +- .../src/pages/api/payment/checkWechat.ts | 53 +++++++-- .../src/pages/cluster/components/Record.tsx | 8 +- .../src/pages/license/components/Recharge.tsx | 38 +++--- .../src/pages/license/components/Record.tsx | 6 +- .../src/pages/pricing/components/Product.tsx | 40 ++++--- .../src/services/backend/db/payment.ts | 111 +++++++++--------- service/license/src/stores/payment.ts | 27 ++++- service/license/src/types/payment.ts | 1 + 10 files changed, 193 insertions(+), 104 deletions(-) diff --git a/service/license/src/api/payment.ts b/service/license/src/api/payment.ts index 7a8ad5f48d1..36f8d38a9dd 100644 --- a/service/license/src/api/payment.ts +++ b/service/license/src/api/payment.ts @@ -1,5 +1,11 @@ import { GET, POST } from '@/services/request'; -import { PaymentData, PaymentParams, PaymentResult, PaymentResultParams } from '@/types'; +import { + CheckWeChatType, + PaymentData, + PaymentParams, + PaymentResult, + PaymentResultParams +} from '@/types'; export const createPayment = (payload: PaymentParams) => POST('/api/payment/create', payload); @@ -7,4 +13,5 @@ export const createPayment = (payload: PaymentParams) => export const handlePaymentResult = (payload: PaymentResultParams) => POST('/api/payment/result', payload); -export const checkWechatPay = () => GET('/api/payment/checkWechat'); +export const checkWechatPay = (type: CheckWeChatType) => + GET('/api/payment/checkWechat', { type }); diff --git a/service/license/src/components/Pagination/index.tsx b/service/license/src/components/Pagination/index.tsx index a2aaaa36c22..a9fc3639fc5 100644 --- a/service/license/src/components/Pagination/index.tsx +++ b/service/license/src/components/Pagination/index.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; type PaginationProps = { totalItems: number; itemsPerPage: number; - onPageChange: any; + onPageChange: (page: number) => void; }; export default function Pagination({ totalItems, itemsPerPage, onPageChange }: PaginationProps) { diff --git a/service/license/src/pages/api/payment/checkWechat.ts b/service/license/src/pages/api/payment/checkWechat.ts index 37883831022..8b1fdade555 100644 --- a/service/license/src/pages/api/payment/checkWechat.ts +++ b/service/license/src/pages/api/payment/checkWechat.ts @@ -1,12 +1,21 @@ import { authSession } from '@/services/backend/auth'; -import { findRecentNopayOrder, updatePaymentStatus } from '@/services/backend/db/payment'; +import { createClusterAndLicense } from '@/services/backend/db/cluster'; +import { generateLicenseToken } from '@/services/backend/db/license'; +import { findRecentNopayOrder, updatePaymentAndIssueLicense } from '@/services/backend/db/payment'; import { jsonRes } from '@/services/backend/response'; import { getSealosPay } from '@/services/pay'; -import { PaymentResult, PaymentStatus } from '@/types'; +import { + CheckWeChatType, + ClusterType, + LicenseRecordPayload, + PaymentResult, + PaymentStatus +} from '@/types'; import type { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { try { + const { type } = req.query as { type: CheckWeChatType }; const userInfo = await authSession(req.headers); if (!userInfo) { return jsonRes(res, { code: 401, message: 'token verify error' }); @@ -40,14 +49,42 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }) }).then((res) => res.json()); - const updateStatusResult = await updatePaymentStatus({ - orderID: payment?.orderID, - status: result.status, - uid: userInfo.uid - }); + if (type === 'license' && result.status === PaymentStatus.PaymentSuccess) { + await updatePaymentAndIssueLicense({ + uid: userInfo.uid, + status: result.status, + amount: payment.amount, + quota: payment.amount, + orderID: payment.orderID, + payMethod: payment.payMethod, + type: 'Account' + }); + } + + if (type === 'cluster' && result.status === PaymentStatus.PaymentSuccess) { + const _token = generateLicenseToken({ type: 'Account', data: { amount: payment.amount } }); + const record: LicenseRecordPayload = { + uid: userInfo.uid, + amount: payment.amount, + token: _token, + orderID: payment.orderID, + quota: payment.amount, + payMethod: payment.payMethod, + type: 'Account' + }; + await createClusterAndLicense({ + licensePayload: record, + clusterPayload: { + uid: userInfo.uid, + orderID: payment.orderID, + type: ClusterType.Enterprise + } + }); + } + console.log('Handle wechat shutdown situation'); return jsonRes(res, { - data: updateStatusResult + data: result }); } catch (error) { console.error(error, '===payment error===\n'); diff --git a/service/license/src/pages/cluster/components/Record.tsx b/service/license/src/pages/cluster/components/Record.tsx index 867a9cface4..aa69fe5d6c7 100644 --- a/service/license/src/pages/cluster/components/Record.tsx +++ b/service/license/src/pages/cluster/components/Record.tsx @@ -104,7 +104,13 @@ export default function ClusterRecord({ changeClusterId, clusterId }: TClusterRe
)} - {}} /> + { + setPage(page); + }} + /> ); diff --git a/service/license/src/pages/license/components/Recharge.tsx b/service/license/src/pages/license/components/Recharge.tsx index 513a53f6015..1e8c296672d 100644 --- a/service/license/src/pages/license/components/Recharge.tsx +++ b/service/license/src/pages/license/components/Recharge.tsx @@ -43,7 +43,7 @@ export default function RechargeComponent() { const [wechatPaymentData, setWechatPaymentData] = useState(); const { data: platformEnv } = useQuery(['getPlatformEnv'], getSystemEnv); // 用于避免微信支付,窗口关闭后感知不到的问题 - // const { paymentData, setPaymentData, deletePaymentData } = usePaymentDataStore(); + const { paymentData, setPaymentData, deletePaymentData, isExpired } = usePaymentDataStore(); const onClosePayment = useCallback(() => { setOrderID(''); @@ -94,6 +94,7 @@ export default function RechargeComponent() { setOrderID(data.orderID); setWechatPaymentData({ tradeNO: data?.tradeNO, codeURL: data?.codeURL }); setComplete(2); + setPaymentData(data.orderID); } }, onError(err: any) { @@ -121,6 +122,7 @@ export default function RechargeComponent() { position: 'top' }); queryClient.invalidateQueries(['getLicenseActive']); + deletePaymentData(); }, onError(err: any) { toast({ @@ -156,22 +158,24 @@ export default function RechargeComponent() { } }); - // checkWechatPay - // useQuery(['checkWechatPay'], () => checkWechatPay(), { - // enabled: !!paymentData?.orderId, - // onSuccess(data) { - // console.log(data, '------'); - // if (data.status === PaymentStatus.PaymentSuccess) { - // toast({ - // status: 'success', - // title: t('Payment Successful'), // 这里改为license 签发成功 - // isClosable: true, - // duration: 9000, - // position: 'top' - // }); - // } - // } - // }); + // checkWechatPay; + useQuery(['checkWechatPay'], () => checkWechatPay('license'), { + enabled: !isExpired() && !!paymentData?.orderId, + onSuccess(data) { + console.log(data, 'Handle wechat shutdown situation'); + if (data.status === PaymentStatus.PaymentSuccess) { + toast({ + status: 'success', + title: t('Payment Successful'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + queryClient.invalidateQueries(['getLicenseActive']); + deletePaymentData(); + } + } + }); useEffect(() => { const { stripeState, orderID } = router.query; diff --git a/service/license/src/pages/license/components/Record.tsx b/service/license/src/pages/license/components/Record.tsx index 60ac515c7bb..d77de18227c 100644 --- a/service/license/src/pages/license/components/Record.tsx +++ b/service/license/src/pages/license/components/Record.tsx @@ -98,7 +98,11 @@ export default function History() { )} - {}} /> + setPage(page)} + /> ); diff --git a/service/license/src/pages/pricing/components/Product.tsx b/service/license/src/pages/pricing/components/Product.tsx index c98cfc88f84..bd17f454775 100644 --- a/service/license/src/pages/pricing/components/Product.tsx +++ b/service/license/src/pages/pricing/components/Product.tsx @@ -30,6 +30,7 @@ import { useCallback, useEffect, useState } from 'react'; import ServicePackage from './ServicePackage'; import useRouteParamsStore from '@/stores/routeParams'; import useSessionStore from '@/stores/session'; +import usePaymentDataStore from '@/stores/payment'; export default function Product() { const { t } = useTranslation(); @@ -48,6 +49,7 @@ export default function Product() { const [remainingSeconds, setRemainingSeconds] = useState(2); // 初始值为2秒 const { data: routeParams, setRouteParams, clearRouteParams } = useRouteParamsStore(); const { isUserLogin } = useSessionStore(); + const { paymentData, setPaymentData, deletePaymentData, isExpired } = usePaymentDataStore(); const onClosePayment = useCallback(() => { setOrderID(''); @@ -58,7 +60,7 @@ export default function Product() { const openPayModal = () => { setComplete(1); setPayType('wechat'); - paymentMutation.mutate((599 * 100).toString()); + paymentMutation.mutate((1 * 100).toString()); onOpen(); }; @@ -105,6 +107,7 @@ export default function Product() { setOrderID(data.orderID); setWechatData({ tradeNO: data?.tradeNO, codeURL: data?.codeURL }); setComplete(2); + setPaymentData(data.orderID); } }, onError(err: any) { @@ -126,7 +129,7 @@ export default function Product() { console.log(data, 'clusterMutation'); setComplete(3); queryClient.invalidateQueries(['getClusterRecord']); - // onClosePayment(); + deletePaymentData(); }, onError(err: any) { toast({ @@ -148,6 +151,7 @@ export default function Product() { console.log(data, 'clusterAndLicenseMutation'); setComplete(3); queryClient.invalidateQueries(['getClusterRecord']); + deletePaymentData(); }, onError(err: any) { toast({ @@ -184,19 +188,24 @@ export default function Product() { }); // checkWechatPay - // useQuery(['checkWechatPay'], () => checkWechatPay(), { - // onSuccess(data) { - // if (data.status === PaymentStatus.PaymentSuccess) { - // toast({ - // status: 'success', - // title: t('License issued successfully'), // 这里改为license 签发成功 - // isClosable: true, - // duration: 9000, - // position: 'top' - // }); - // } - // } - // }); + useQuery(['checkWechatPay'], () => checkWechatPay('cluster'), { + enabled: !isExpired() && !!paymentData?.orderId, + onSuccess(data) { + console.log(data, 'Handle wechat shutdown situation'); + if (data.status === PaymentStatus.PaymentSuccess) { + toast({ + status: 'success', + title: t('Payment Successful'), // 这里改为license 签发成功 + isClosable: true, + duration: 9000, + position: 'top' + }); + deletePaymentData(); + queryClient.invalidateQueries(['getClusterRecord']); + setComplete(3); + } + } + }); // handle stripe useEffect(() => { @@ -273,6 +282,7 @@ export default function Product() { void; + setPaymentData: (orderId: string) => void; deletePaymentData: () => void; + isExpired: () => boolean; }; export const usePaymentDataStore = create( persist( - immer((set) => ({ + immer((set, get) => ({ paymentData: undefined, - setPaymentData: (data) => set({ paymentData: data }), - deletePaymentData: () => set({ paymentData: undefined }) + setPaymentData: (id) => { + const currentTime = new Date().getTime(); // 获取当前时间戳 + const expirationTime = currentTime + 5 * 60000; // 10 minutes in milliseconds + set({ + paymentData: { + orderId: id, + expirationTime: expirationTime + } + }); + }, + deletePaymentData: () => set({ paymentData: undefined }), + isExpired: () => { + const paymentData = get().paymentData; + if (paymentData && paymentData.expirationTime) { + const currentTime = new Date().getTime(); + return currentTime > paymentData.expirationTime; + } + return false; + } })), { name: 'paymentData' diff --git a/service/license/src/types/payment.ts b/service/license/src/types/payment.ts index 7be21157a6e..ab3e1055783 100644 --- a/service/license/src/types/payment.ts +++ b/service/license/src/types/payment.ts @@ -13,6 +13,7 @@ export type PaymentDB = { updatedAt: Date; // Modification timestamp }; +export type CheckWeChatType = 'license' | 'cluster'; export type TPayMethod = 'stripe' | 'wechat'; export type StripeCallBackUrl = '/pricing' | '/license'; From 114825dc7011278e78d3cbc2e39cd550e88217e9 Mon Sep 17 00:00:00 2001 From: jingyang <3161362058@qq.com> Date: Mon, 30 Oct 2023 14:53:16 +0800 Subject: [PATCH 17/17] fix ci Signed-off-by: jingyang <3161362058@qq.com> --- service/license/src/pages/api/payment/result.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/service/license/src/pages/api/payment/result.ts b/service/license/src/pages/api/payment/result.ts index 4b4e7ef99c1..618067d18a2 100644 --- a/service/license/src/pages/api/payment/result.ts +++ b/service/license/src/pages/api/payment/result.ts @@ -46,7 +46,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) status: result.status, uid: userInfo.uid }); - console.log(updateStatusResult, 'updateStatusResult'); return jsonRes(res, { data: updateStatusResult