diff --git a/admin-ui/.dockerignore b/admin-ui/.dockerignore new file mode 100644 index 0000000..891b902 --- /dev/null +++ b/admin-ui/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.git +.gitignore +README.md +.env.local +*.zip \ No newline at end of file diff --git a/admin-ui/.gitattributes b/admin-ui/.gitattributes new file mode 100644 index 0000000..33f3c22 --- /dev/null +++ b/admin-ui/.gitattributes @@ -0,0 +1,14 @@ +# 统一使用 LF,避免跨平台协作时产生整文件 diff +* text=auto eol=lf + +# 二进制文件不做行尾转换 +*.png binary +*.jpg binary +*.gif binary +*.ico binary +*.woff binary +*.woff2 binary +*.ttf binary +*.pdf binary +*.exe binary +*.xlsx binary diff --git a/admin-ui/.gitea/workflows/mirror-to-gitee.yml b/admin-ui/.gitea/workflows/mirror-to-gitee.yml new file mode 100644 index 0000000..b8f8b52 --- /dev/null +++ b/admin-ui/.gitea/workflows/mirror-to-gitee.yml @@ -0,0 +1,64 @@ +name: mirror-to-gitee + +# 把本仓同步到 Gitee 企业仓 snowgoat/<同名仓库>。 +# 触发:main 分支推送、v* tag 推送、手动;另有每日兜底重试。 +on: + push: + branches: + - main + tags: + - 'v*' + schedule: + # Gitea Actions 的 cron 用 UTC:18:30 UTC = 次日 02:30 北京时间 + - cron: '30 18 * * *' + workflow_dispatch: + +concurrency: + group: mirror-${{ github.ref }} + cancel-in-progress: true + +jobs: + mirror: + runs-on: host + steps: + - name: 同步到 Gitee + env: + SRC_TOKEN: ${{ secrets.SRC_GIT_TOKEN }} + DST_TOKEN: ${{ secrets.GITEE_TOKEN }} + DST_OWNER: ${{ secrets.GITEE_OWNER }} + DST_USER: ${{ secrets.GITEE_USER }} + REPO_NAME: ${{ github.event.repository.name }} + run: | + set -u + + if [ -z "${REPO_NAME:-}" ]; then + echo "未取到仓库名,退出"; exit 1 + fi + + WORK=$(mktemp -d) + trap 'rm -rf "$WORK"' EXIT + + echo "源:git.5iot.com/iotlcm-public/$REPO_NAME" + echo "目标:gitee.com/$DST_OWNER/$REPO_NAME" + + git clone --mirror "https://jenkins:${SRC_TOKEN}@git.5iot.com/iotlcm-public/${REPO_NAME}.git" "$WORK/repo.git" + cd "$WORK/repo.git" + echo "本地 ref:$(git for-each-ref --format='%(refname:short)' | tr '\n' ' ')" + + # Gitee 在推送密集时会返回 429 Pending queue overflowed / 408 Authorization server timeout, + # 属服务端限流,退避重试即可。 + attempt=0 + while [ "$attempt" -lt 5 ]; do + attempt=$((attempt + 1)) + echo "----- 推送尝试 $attempt/5" + if git push --mirror "https://${DST_USER}:${DST_TOKEN}@gitee.com/${DST_OWNER}/${REPO_NAME}.git" 2>&1; then + echo "✅ 已同步到 Gitee" + exit 0 + fi + wait_s=$((attempt * 30)) + echo "推送失败,${wait_s}s 后重试" + sleep "$wait_s" + done + + echo "❌ 连续 5 次推送失败,请检查 Gitee 状态或令牌" + exit 1 diff --git a/admin-ui/.gitea/workflows/trigger-jenkins.yml b/admin-ui/.gitea/workflows/trigger-jenkins.yml new file mode 100644 index 0000000..f58a800 --- /dev/null +++ b/admin-ui/.gitea/workflows/trigger-jenkins.yml @@ -0,0 +1,80 @@ +name: trigger-jenkins-oss + +# 打 tag 时触发 Jenkins 构建开源镜像并推送到镜像仓库。 +# 仅在 tag 推送时触发;main 分支的日常提交不触发。 +on: + push: + tags: + - 'v*' + workflow_dispatch: + +# 同一 ref 连续触发时取消旧任务,只跑最新的 +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + trigger: + runs-on: host + steps: + - name: 触发 Jenkins 镜像构建 + env: + JU: ${{ secrets.JENKINS_USER }} + JT: ${{ secrets.JENKINS_API_TOKEN }} + JURL: ${{ secrets.JENKINS_URL }} + JOB_PATH: ${{ secrets.JENKINS_JOB_PATH }} + REPO_NAME: ${{ github.event.repository.name }} + TAG_NAME: ${{ github.ref_name }} + run: | + set -eu + + # 只有 tag 推送才构建;手动触发时按 tag 取,没有就退出 + case "${GITHUB_REF:-}" in + refs/tags/v*) ;; + *) + if [ "${GITHUB_EVENT_NAME:-}" != "workflow_dispatch" ]; then + echo "非 tag 推送,跳过:${GITHUB_REF:-unknown}" + exit 0 + fi + ;; + esac + + if [ -z "${TAG_NAME:-}" ]; then + echo "未取到 tag 名,退出" + exit 1 + fi + + # job 在 Jenkins 文件夹下的路径(组织密钥 JENKINS_JOB_PATH), + # 例如 job/iotlcm-opensrc/job/iotlcm-oss-build。 + # 用密钥而非硬编码,Jenkins 里移动 job 时不用改 11 个仓。 + JP="${JOB_PATH:-job/iotlcm-oss-build}" + + echo "仓库:$REPO_NAME 版本:$TAG_NAME job:$JP" + + WORK=$(mktemp -d) + trap 'rm -rf "$WORK"' EXIT + + # 取 CSRF crumb + curl -s -c "$WORK/cj" -u "$JU:$JT" "$JURL/crumbIssuer/api/json" -o "$WORK/crumb.json" + CR=$(python3 -c "import json;print(json.load(open('$WORK/crumb.json'))['crumb'])") + + # 触发参数化任务:SERVICES=仓库名,VERSION=tag + code=$(curl -s -o "$WORK/out" -w '%{http_code}' -X POST -b "$WORK/cj" -u "$JU:$JT" \ + -H "Jenkins-Crumb: $CR" \ + --data-urlencode "SERVICES=$REPO_NAME" \ + --data-urlencode "VERSION=$TAG_NAME" \ + --data-urlencode "FORCE=true" \ + "$JURL/$JP/buildWithParameters") + + echo "Jenkins 触发 HTTP $code" + if [ "$code" != "201" ] && [ "$code" != "200" ] && [ "$code" != "302" ] && [ "$code" != "303" ]; then + echo "触发失败:" + cat "$WORK/out" + exit 1 + fi + + LINK="$JURL/$JP/" + echo "==========================================" + echo "Jenkins 构建:$LINK" + echo "==========================================" + echo "::notice title=Jenkins 镜像构建::[$LINK]($LINK)" diff --git a/admin-ui/.gitignore b/admin-ui/.gitignore new file mode 100644 index 0000000..72ef840 --- /dev/null +++ b/admin-ui/.gitignore @@ -0,0 +1,66 @@ +node_modules +.DS_Store +dist +dist-ssr +dist.zip +dist.tar +dist.war +.nitro +.output +*-dist.zip +*-dist.tar +*-dist.war +coverage +*.local +**/.vitepress/cache +.cache +.turbo +.temp +dev-dist +.stylelintcache +yarn.lock +package-lock.json +.VSCodeCounter +**/backend-mock/data +.omx +.pnpm-store +# local env files +.env.local +.env.*.local +.eslintcache + +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +vite.config.mts.* +vite.config.mjs.* +vite.config.js.* +vite.config.ts.* + +# Editor directories and files +.idea +# .vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.history +.cursor + +# AI +.agent +.agents +.claude +.codex +skills-lock.json +.atomcode +datalog + +# local-only placeholder lefthook config (silences "No config found" popup) +# NOTE: only ignores the GIT-ROOT placeholder; vue/lefthook.yml stays tracked. +/lefthook.yml \ No newline at end of file diff --git a/admin-ui/LICENSE b/admin-ui/LICENSE new file mode 100644 index 0000000..2e83190 --- /dev/null +++ b/admin-ui/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021-PRESENT Vben Admin (https://github.com/vbenjs/vue-vben-admin) +Copyright (c) 2026 The iotLCM Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/admin-ui/Makefile b/admin-ui/Makefile new file mode 100644 index 0000000..1170237 --- /dev/null +++ b/admin-ui/Makefile @@ -0,0 +1,21 @@ +.PHONY: build +build: + docker build --rm -f vue/build/Dockerfile --progress=plain --platform linux/amd64 -t docker_iotlcmadminui:v0 . + +.PHONY: vue +vue: + cd vue + cd vue && npm i -g corepack + cd vue && CI=true pnpm install + cd vue && CI=true pnpm build + +.PHONY: build-no-build +build-no-build: + docker build --rm -f vue/build/DockerfileNoBuild --progress=plain --platform linux/amd64 -t docker_iotlcmadminui:v0 . + + +dockerbuild: build-no-build + echo "docker build success" +dockerpush: + docker tag docker_iotlcmadminui:v0 ${REGISTRY}/docker_iotlcmadminui:v0 + docker push ${REGISTRY}/docker_iotlcmadminui:v0 \ No newline at end of file diff --git a/admin-ui/README.md b/admin-ui/README.md new file mode 100644 index 0000000..ed3d167 --- /dev/null +++ b/admin-ui/README.md @@ -0,0 +1,90 @@ +# iotlcm-admin-ui + +iotLCM 物联网卡全生命周期管理平台的**管理前端** —— 卡资产、通信管理、资费交易、告警工单、统计分析、账号治理。 + +配套后端:[iotlcm-admin-svr](https://git.5iot.com/iotlcm-public/iotlcm-admin-svr)。 + +## 上游与许可 + +本项目基于 **[Vben Admin](https://github.com/vbenjs/vue-vben-admin) 5.5.9**(MIT License)二次开发。 + +- 上游版权与许可声明完整保留在 [`LICENSE`](./LICENSE) 与各源文件的 `@Author` / `@Copyright` 头中 +- iotLCM 相关的业务页面、API 封装与配置为本项目新增 +- 上游仓库:[vbenjs/vue-vben-admin](https://github.com/vbenjs/vue-vben-admin) +- 上游自带的说明文档保留在 [`vue/README.md`](./vue/README.md) + +## 技术栈 + +- Vue 3 + Vite + TypeScript +- Vben Admin 5.5.9(Ant Design Vue 版:`apps/web-antd`) +- Pinia(状态)、Vue Router、TailwindCSS + UnoCSS(原子化样式) +- pnpm workspace + Turborepo(monorepo) + +## 快速开始 + +```bash +cd vue +pnpm install +pnpm dev:antd +``` + +开发服务器默认监听 `http://127.0.0.1:5666/`。 + +构建: + +```bash +pnpm build:antd +``` + +产物在 `vue/apps/web-antd/dist/`。 + +## 配置 + +环境变量文件在 `vue/apps/web-antd/`: + +| 文件 | 用途 | +| --- | --- | +| `.env` | 通用配置(应用标题、命名空间、客户端 ID、store 加密密钥) | +| `.env.development` | 开发环境(端口、API 地址) | +| `.env.production` | 生产环境(压缩策略、路由模式、PWA) | + +**公开版里的凭据是占位符**: + +| 变量 | 占位 | 说明 | +| --- | --- | --- | +| `VITE_GLOB_CLIENT_ID` | `your-client-id` | OAuth 客户端 ID | +| `VITE_APP_STORE_SECURE_KEY` | `please-replace-me-with-your-own-key` | localStorage 加密密钥 | +| `TIANDITU_CONFIG.API_KEY` | `YOUR_TIANDITU_KEY` | 天地图 API Key(`src/config/tianditu.ts`) | + +> ⚠️ `VITE_APP_STORE_SECURE_KEY` 必须是自己的随机值——它用于加密持久化的 store,换设备时 store 数据将无法解密。 + +## 目录结构 + +```text +iotlcm-admin-ui/ +├── Makefile # 容器构建与推送 +└── vue/ # Vben Admin monorepo + ├── apps/web-antd/ # iotLCM 管理端应用(主应用) + │ ├── src/api/iotlcm/ # iotLCM 业务 API 封装 + │ ├── src/views/iotlcm/ # iotLCM 业务页面 + │ ├── src/config/ # 应用配置(含天地图配置) + │ └── .env* # 环境变量 + ├── packages/ # 内部共享包 + └── internal/ # 构建期工具 +``` + +## 容器化构建 + +```bash +docker build --rm -f vue/build/Dockerfile --platform linux/amd64 -t iotlcm-admin-ui:latest . +``` + +推送到自己的镜像仓库: + +```bash +REGISTRY= make dockerpush +``` + +## License + +[MIT](./LICENSE) —— 含 Vben Admin 上游的 MIT 声明。 diff --git a/admin-ui/vue/.browserslistrc b/admin-ui/vue/.browserslistrc new file mode 100644 index 0000000..dc3bc09 --- /dev/null +++ b/admin-ui/vue/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 diff --git a/admin-ui/vue/.commitlintrc.js b/admin-ui/vue/.commitlintrc.js new file mode 100644 index 0000000..02e33fa --- /dev/null +++ b/admin-ui/vue/.commitlintrc.js @@ -0,0 +1 @@ +export { default } from '@vben/commitlint-config'; diff --git a/admin-ui/vue/.dockerignore b/admin-ui/vue/.dockerignore new file mode 100644 index 0000000..52b833a --- /dev/null +++ b/admin-ui/vue/.dockerignore @@ -0,0 +1,7 @@ +node_modules +.git +.gitignore +*.md +dist +.turbo +dist.zip diff --git a/admin-ui/vue/.editorconfig b/admin-ui/vue/.editorconfig new file mode 100644 index 0000000..179aec6 --- /dev/null +++ b/admin-ui/vue/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset=utf-8 +end_of_line=lf +insert_final_newline=true +indent_style=space +indent_size=2 +max_line_length = 100 +trim_trailing_whitespace = true +quote_type = single + +[*.{yml,yaml,json}] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/admin-ui/vue/.husky/commit-msg b/admin-ui/vue/.husky/commit-msg new file mode 100755 index 0000000..270ebb8 --- /dev/null +++ b/admin-ui/vue/.husky/commit-msg @@ -0,0 +1,6 @@ +echo Start running commit-msg hook... + +# Check whether the git commit information is standardized +pnpm exec commitlint --edit "$1" + +echo Run commit-msg hook done. diff --git a/admin-ui/vue/.husky/post-merge b/admin-ui/vue/.husky/post-merge new file mode 100644 index 0000000..83fa775 --- /dev/null +++ b/admin-ui/vue/.husky/post-merge @@ -0,0 +1,3 @@ +# 每次 git pull 之后, 安装依赖 + +pnpm install diff --git a/admin-ui/vue/.husky/pre-commit b/admin-ui/vue/.husky/pre-commit new file mode 100755 index 0000000..5dccee2 --- /dev/null +++ b/admin-ui/vue/.husky/pre-commit @@ -0,0 +1,7 @@ +# update `.vscode/vben-admin.code-workspace` file +pnpm vsh code-workspace --auto-commit + +# Format and submit code according to lintstagedrc.js configuration +pnpm exec lint-staged + +echo Run pre-commit hook done. diff --git a/admin-ui/vue/.lintstagedrc.mjs b/admin-ui/vue/.lintstagedrc.mjs new file mode 100644 index 0000000..94b0192 --- /dev/null +++ b/admin-ui/vue/.lintstagedrc.mjs @@ -0,0 +1,20 @@ +export default { + '*.md': ['prettier --cache --ignore-unknown --write'], + '*.vue': [ + 'prettier --write', + 'eslint --cache --fix', + 'stylelint --fix --allow-empty-input', + ], + '*.{js,jsx,ts,tsx}': [ + 'prettier --cache --ignore-unknown --write', + 'eslint --cache --fix', + ], + '*.{scss,less,styl,html,vue,css}': [ + 'prettier --cache --ignore-unknown --write', + 'stylelint --fix --allow-empty-input', + ], + 'package.json': ['prettier --cache --write'], + '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [ + 'prettier --cache --write--parser json', + ], +}; diff --git a/admin-ui/vue/.node-version b/admin-ui/vue/.node-version new file mode 100644 index 0000000..ee5c244 --- /dev/null +++ b/admin-ui/vue/.node-version @@ -0,0 +1 @@ +22.1.0 diff --git a/admin-ui/vue/.npmrc b/admin-ui/vue/.npmrc new file mode 100644 index 0000000..aeac1ae --- /dev/null +++ b/admin-ui/vue/.npmrc @@ -0,0 +1,13 @@ +registry=https://registry.npmmirror.com +public-hoist-pattern[]=lefthook +public-hoist-pattern[]=eslint +public-hoist-pattern[]=prettier +public-hoist-pattern[]=prettier-plugin-tailwindcss +public-hoist-pattern[]=stylelint +public-hoist-pattern[]=*postcss* +public-hoist-pattern[]=@commitlint/* +public-hoist-pattern[]=czg + +strict-peer-dependencies=false +auto-install-peers=true +dedupe-peer-dependents=true diff --git a/admin-ui/vue/.prettierignore b/admin-ui/vue/.prettierignore new file mode 100644 index 0000000..d0b0ca1 --- /dev/null +++ b/admin-ui/vue/.prettierignore @@ -0,0 +1,18 @@ +dist +dev-dist +.local +.output.js +node_modules +.nvmrc +coverage +CODEOWNERS +.nitro +.output + + +**/*.svg +**/*.sh + +public +.npmrc +*-lock.yaml diff --git a/admin-ui/vue/.prettierrc.mjs b/admin-ui/vue/.prettierrc.mjs new file mode 100644 index 0000000..3e25d2c --- /dev/null +++ b/admin-ui/vue/.prettierrc.mjs @@ -0,0 +1 @@ +export { default } from '@vben/prettier-config'; diff --git a/admin-ui/vue/.stylelintignore b/admin-ui/vue/.stylelintignore new file mode 100644 index 0000000..f4b2db2 --- /dev/null +++ b/admin-ui/vue/.stylelintignore @@ -0,0 +1,4 @@ +dist +public +__tests__ +coverage diff --git a/admin-ui/vue/.vscode/settings.json b/admin-ui/vue/.vscode/settings.json new file mode 100644 index 0000000..3f572bd --- /dev/null +++ b/admin-ui/vue/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "cSpell.words": [ + "iccid", + "imei", + "imsi", + "IOTLCM", + "msisdn" + ] +} \ No newline at end of file diff --git a/admin-ui/vue/README.md b/admin-ui/vue/README.md new file mode 100644 index 0000000..e84c839 --- /dev/null +++ b/admin-ui/vue/README.md @@ -0,0 +1,152 @@ +
VbenAdmin Logo

+ +[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE) + +

Vue Vben Admin

+
+ +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg) + +**English** | [中文](./README.zh-CN.md) | [日本語](./README.ja-JP.md) + +## Introduction + +Vue Vben Admin is a free and open source middle and back-end template. Using the latest `vue3`, `vite`, `TypeScript` and other mainstream technology development, the out-of-the-box middle and back-end front-end solutions can also be used for learning reference. + +## Upgrade Notice + +This is the latest version, 5.0, and it is not compatible with previous versions. If you are starting a new project, it is recommended to use the latest version. If you wish to view the old version, please use the [v2 branch](https://github.com/vbenjs/vue-vben-admin/tree/v2). + +## Feature + +- **Latest Technology Stack**: Developed with cutting-edge front-end technologies like Vue 3 and Vite +- **TypeScript**: A language for application-scale JavaScript +- **Themes**: Multiple theme colors available with customizable options +- **Internationalization**: Comprehensive built-in internationalization support +- **Permissions**: Built-in solution for dynamic route-based permission generation + +## Preview + +- [Vben Admin](https://vben.pro/) - Full version Chinese site + +Test Account: vben/123456 + +

+ VbenAdmin Logo + VbenAdmin Logo + VbenAdmin Logo +

+ +### Use Gitpod + +Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin) + +## Documentation + +[Document](https://doc.vben.pro/) + +## Install and use + +- Get the project code + +```bash +git clone https://github.com/vbenjs/vue-vben-admin.git +``` + +- Installation dependencies + +```bash +cd vue-vben-admin + +corepack enable + +pnpm install +``` + +- run + +```bash +pnpm dev +``` + +- build + +```bash +pnpm build +``` + +## Change Log + +[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases) + +## How to contribute + +You are very welcome to join![Raise an issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) Or submit a Pull Request。 + +**Pull Request:** + +1. Fork code! +2. Create your own branch: `git checkout -b feat/xxxx` +3. Submit your changes: `git commit -am 'feat(function): add xxxxx'` +4. Push your branch: `git push origin feat/xxxx` +5. submit`pull request` + +## Git Contribution submission specification + +- reference [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) specification ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)) + + - `feat` Add new features + - `fix` Fix the problem/BUG + - `style` The code style is related and does not affect the running result + - `perf` Optimization/performance improvement + - `refactor` Refactor + - `revert` Undo edit + - `test` Test related + - `docs` Documentation/notes + - `chore` Dependency update/scaffolding configuration modification etc. + - `ci` Continuous integration + - `types` Type definition file changes + - `wip` In development + +## Browser support + +The `Chrome 80+` browser is recommended for local development + +Support modern browsers, not IE + +| [ Edge](http://godban.github.io/browsers-support-badges/)
IE | [ Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | +| :-: | :-: | :-: | :-: | :-: | +| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + +## Maintainer + +[@Vben](https://github.com/anncwb) + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date) + +## Donate + +If you think this project is helpful to you, you can help the author buy a cup of coffee to show your support! + +![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png) + +Paypal Me + +## Contributor + + + Contributors + + +## Discord + +- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions) + +## License + +[MIT © Vben-2020](./LICENSE) diff --git a/admin-ui/vue/README.zh-CN.md b/admin-ui/vue/README.zh-CN.md new file mode 100644 index 0000000..e2f05bb --- /dev/null +++ b/admin-ui/vue/README.zh-CN.md @@ -0,0 +1,152 @@ +
VbenAdmin Logo

+ +[![license](https://img.shields.io/github/license/anncwb/vue-vben-admin.svg)](LICENSE) + +

Vue Vben Admin

+
+ +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg) + +**中文** | [English](./README.md) | [日本語](./README.ja-JP.md) + +## 简介 + +Vue Vben Admin 是 Vue Vben Admin 的升级版本。作为一个免费开源的中后台模板,它采用了最新的 Vue 3、Vite、TypeScript 等主流技术开发,开箱即用,可用于中后台前端开发,也适合学习参考。 + +## 升级提示 + +该版本为最新版本`5.0`, 与其他版本不兼容,如果你是新项目,建议使用最新版本。如果你想查看旧版本,请使用 [v2 分支](https://github.com/vbenjs/vue-vben-admin/tree/v2) + +## 特性 + +- **最新技术栈**:使用 Vue3/vite 等前端前沿技术开发 +- **TypeScript**: 应用程序级 JavaScript 的语言 +- **主题**:提供多套主题色彩,可配置自定义主题 +- **国际化**:内置完善的国际化方案 +- **权限** 内置完善的动态路由权限生成方案 + +## 预览 + +- [Vben Admin](https://vben.pro/) - 完整版中文站点 + +测试账号: vben/123456 + +

+ VbenAdmin Logo + VbenAdmin Logo + VbenAdmin Logo +

+ +### 使用 Gitpod + +在 Gitpod(适用于 GitHub 的免费在线开发环境)中打开项目,并立即开始编码. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/vbenjs/vue-vben-admin) + +## 文档 + +[文档地址](https://doc.vben.pro/) + +## 安装使用 + +- 获取项目代码 + +```bash +git clone https://github.com/vbenjs/vue-vben-admin.git +``` + +- 安装依赖 + +```bash +cd vue-vben-admin + +corepack enable + +pnpm install +``` + +- 运行 + +```bash +pnpm dev +``` + +- 打包 + +```bash +pnpm build +``` + +## 更新日志 + +[CHANGELOG](https://github.com/vbenjs/vue-vben-admin/releases) + +## 如何贡献 + +非常欢迎你的加入![提一个 Issue](https://github.com/anncwb/vue-vben-admin/issues/new/choose) 或者提交一个 Pull Request。 + +**Pull Request:** + +1. Fork 代码! +2. 创建自己的分支: `git checkout -b feature/xxxx` +3. 提交你的修改: `git commit -am 'feat(function): add xxxxx'` +4. 推送您的分支: `git push origin feature/xxxx` +5. 提交`pull request` + +## Git 贡献提交规范 + +- 参考 [vue](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md) 规范 ([Angular](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular)) + + - `feat` 增加新功能 + - `fix` 修复问题/BUG + - `style` 代码风格相关无影响运行结果的 + - `perf` 优化/性能提升 + - `refactor` 重构 + - `revert` 撤销修改 + - `test` 测试相关 + - `docs` 文档/注释 + - `chore` 依赖更新/脚手架配置修改等 + - `ci` 持续集成 + - `types` 类型定义文件更改 + - `wip` 开发中 + +## 浏览器支持 + +本地开发推荐使用`Chrome 80+` 浏览器 + +支持现代浏览器, 不支持 IE + +| [ Edge](http://godban.github.io/browsers-support-badges/)
IE | [ Edge](http://godban.github.io/browsers-support-badges/)
Edge | [Firefox](http://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](http://godban.github.io/browsers-support-badges/)
Chrome | [Safari](http://godban.github.io/browsers-support-badges/)
Safari | +| :-: | :-: | :-: | :-: | :-: | +| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions | + +## 维护者 + +[@Vben](https://github.com/anncwb) + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=vbenjs/vue-vben-admin&type=Date)](https://star-history.com/#vbenjs/vue-vben-admin&Date) + +## 捐赠 + +如果你觉得这个项目对你有帮助,你可以帮作者买一杯咖啡表示支持! + +![donate](https://unpkg.com/@vbenjs/static-source@0.1.7/source/sponsor.png) + +Paypal Me + +## Contributor + + + Contributors + + +## Discord + +- [Github Discussions](https://github.com/anncwb/vue-vben-admin/discussions) + +## License + +[MIT © Vben-2020](./LICENSE) diff --git a/admin-ui/vue/apps/.gitignore b/admin-ui/vue/apps/.gitignore new file mode 100644 index 0000000..cadf95f --- /dev/null +++ b/admin-ui/vue/apps/.gitignore @@ -0,0 +1 @@ +backend-mock/nitro.config.ts diff --git a/admin-ui/vue/apps/web-antd/.env b/admin-ui/vue/apps/web-antd/.env new file mode 100644 index 0000000..5a5584d --- /dev/null +++ b/admin-ui/vue/apps/web-antd/.env @@ -0,0 +1,9 @@ +# 应用标题 +VITE_APP_TITLE=物联网全生命周期管理平台 +VBEN_LOGO_URL=/images/logo.png +# 应用命名空间,用于缓存、store等功能的前缀,确保隔离 +VITE_APP_NAMESPACE=iotlcm-admin-web +# 客户端ID +VITE_GLOB_CLIENT_ID=your-client-id +# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密 +VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key diff --git a/admin-ui/vue/apps/web-antd/.env.analyze b/admin-ui/vue/apps/web-antd/.env.analyze new file mode 100644 index 0000000..ffafa8d --- /dev/null +++ b/admin-ui/vue/apps/web-antd/.env.analyze @@ -0,0 +1,7 @@ +# public path +VITE_BASE=/ + +# Basic interface address SPA +VITE_GLOB_API_URL=/api + +VITE_VISUALIZER=true diff --git a/admin-ui/vue/apps/web-antd/.env.development b/admin-ui/vue/apps/web-antd/.env.development new file mode 100644 index 0000000..0e2c2ca --- /dev/null +++ b/admin-ui/vue/apps/web-antd/.env.development @@ -0,0 +1,19 @@ +# 端口号 +VITE_PORT=5666 + +VITE_BASE=/ + +# 接口地址 +VITE_GLOB_API_URL=/api + +# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 +VITE_NITRO_MOCK=false + +# 是否打开 devtools,true 为打开,false 为关闭 +VITE_DEVTOOLS=false + +# 是否注入全局loading +VITE_INJECT_APP_LOADING=true + +# 客户端ID +VITE_GLOB_CLIENT_ID=your-client-id diff --git a/admin-ui/vue/apps/web-antd/.env.production b/admin-ui/vue/apps/web-antd/.env.production new file mode 100644 index 0000000..87a0f8e --- /dev/null +++ b/admin-ui/vue/apps/web-antd/.env.production @@ -0,0 +1,22 @@ +VITE_BASE=/ + +# 接口地址 +VITE_GLOB_API_URL=/api + +# 是否开启压缩,可以设置为 none, brotli, gzip +VITE_COMPRESS=none + +# 是否开启 PWA +VITE_PWA=false + +# vue-router 的模式 +VITE_ROUTER_HISTORY=hash + +# 是否注入全局loading +VITE_INJECT_APP_LOADING=true + +# 打包后是否生成dist.zip +VITE_ARCHIVER=true + +# 客户端ID +VITE_GLOB_CLIENT_ID=your-client-id \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/index.html b/admin-ui/vue/apps/web-antd/index.html new file mode 100644 index 0000000..6b58bda --- /dev/null +++ b/admin-ui/vue/apps/web-antd/index.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/admin-ui/vue/apps/web-antd/loading.html b/admin-ui/vue/apps/web-antd/loading.html new file mode 100644 index 0000000..7461939 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/loading.html @@ -0,0 +1,290 @@ + +
+ +
+
正在初始化应用...
+
+ 请稍候,系统正在准备运行环境 +
+
智联·云
+
+
+ diff --git a/admin-ui/vue/apps/web-antd/package.json b/admin-ui/vue/apps/web-antd/package.json new file mode 100644 index 0000000..f04c7ef --- /dev/null +++ b/admin-ui/vue/apps/web-antd/package.json @@ -0,0 +1,60 @@ +{ + "name": "@vben/web-antd", + "version": "5.5.9", + "homepage": "https://vben.pro", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "apps/web-antd" + }, + "license": "MIT", + "author": { + "name": "vben", + "email": "xxx@example.com", + "url": "https://github.com/anncwb" + }, + "type": "module", + "scripts": { + "build": "pnpm vite build --mode production", + "build:analyze": "pnpm vite build --mode analyze", + "dev": "pnpm vite --mode development", + "preview": "vite preview", + "typecheck": "vue-tsc --noEmit --skipLibCheck" + }, + "imports": { + "#/*": "./src/*" + }, + "dependencies": { + "@highlightjs/vue-plugin": "^2.1.0", + "@tinymce/tinymce-vue": "^6.1.0", + "@vben/access": "workspace:*", + "@vben/common-ui": "workspace:*", + "@vben/constants": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/layouts": "workspace:*", + "@vben/locales": "workspace:*", + "@vben/plugins": "workspace:*", + "@vben/preferences": "workspace:*", + "@vben/request": "workspace:*", + "@vben/stores": "workspace:*", + "@vben/styles": "workspace:*", + "@vben/types": "workspace:*", + "@vben/utils": "workspace:*", + "@vueuse/core": "catalog:", + "ant-design-vue": "catalog:", + "cropperjs": "^1.6.2", + "dayjs": "catalog:", + "highlight.js": "^11.11.1", + "js-md5": "^0.8.3", + "lodash-es": "^4.17.21", + "pinia": "catalog:", + "tinymce": "^7.3.0", + "vue": "catalog:", + "vue-router": "catalog:" + }, + "devDependencies": { + "@types/lodash-es": "^4.17.12" + } +} diff --git a/admin-ui/vue/apps/web-antd/plugins/api-type-generator.ts b/admin-ui/vue/apps/web-antd/plugins/api-type-generator.ts new file mode 100644 index 0000000..19de09b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/plugins/api-type-generator.ts @@ -0,0 +1,427 @@ +import type { IncomingMessage, ServerResponse } from 'node:http'; +import type { PluginOption } from 'vite'; + +import { Buffer } from 'node:buffer'; +import { constants as fsConstants } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; + +interface ApiTypeGeneratorOptions { + apiRoot: string; +} + +interface DirNode { + children?: DirNode[]; + key: string; + title: string; + value: string; +} + +interface WriteTypePayload { + autoImport?: boolean; + content?: string; + dir?: string; + fileName?: string; + overwrite?: boolean; +} + +interface CheckTypeFilePayload { + items?: CheckTypeFileItem[]; +} + +interface CheckTypeFileItem { + dir?: string; + fileName?: string; + key?: string; +} + +const API_TYPE_GENERATOR_PREFIX = '/__api-type-generator__'; + +export function apiTypeGeneratorPlugin( + options: ApiTypeGeneratorOptions, +): PluginOption { + const apiRoot = path.resolve(options.apiRoot); + + return { + apply: 'serve', + configureServer(server) { + server.middlewares.use(async (request, response, next) => { + const url = request.url?.split('?')[0] ?? ''; + + if (!url.startsWith(API_TYPE_GENERATOR_PREFIX)) { + next(); + return; + } + + try { + if ( + request.method === 'GET' && + url === `${API_TYPE_GENERATOR_PREFIX}/dirs` + ) { + const data = await scanApiDirs(apiRoot); + + sendJson(response, 200, { data, success: true }); + return; + } + + if ( + request.method === 'POST' && + url === `${API_TYPE_GENERATOR_PREFIX}/exists` + ) { + const payload = await readJsonBody(request); + const data = await checkTypeFiles(apiRoot, payload); + + sendJson(response, 200, { data, success: true }); + return; + } + + if ( + request.method === 'POST' && + url === `${API_TYPE_GENERATOR_PREFIX}/write` + ) { + const payload = await readJsonBody(request); + const data = await writeTypeFile(apiRoot, payload); + + sendJson(response, 200, { data, success: true }); + return; + } + + sendJson(response, 404, { + message: '接口不存在', + success: false, + }); + } catch (error) { + const statusCode = + error instanceof ApiTypeGeneratorError ? error.status : 500; + + sendJson(response, statusCode, { + code: + error instanceof ApiTypeGeneratorError ? error.code : 'UNKNOWN', + message: error instanceof Error ? error.message : '生成失败', + success: false, + }); + } + }); + }, + name: 'web-antd:api-type-generator', + }; +} + +class ApiTypeGeneratorError extends Error { + constructor( + message: string, + public status = 400, + public code = 'BAD_REQUEST', + ) { + super(message); + } +} + +async function accessFile(filePath: string) { + try { + await fs.access(filePath, fsConstants.F_OK); + return true; + } catch { + return false; + } +} + +function ensureInApiRoot(apiRoot: string, targetPath: string) { + const relativePath = path.relative(apiRoot, targetPath); + + if ( + relativePath.startsWith('..') || + path.isAbsolute(relativePath) || + relativePath === '' + ) { + if (relativePath === '') { + return; + } + + throw new ApiTypeGeneratorError('目标路径不在 src/api 目录下'); + } +} + +function extractTypeNames(content: string) { + const names = new Set(); + const regex = /export\s+(?:interface|type)\s+([A-Za-z_$][\w$]*)/g; + const results = content.matchAll(regex); + + for (const result of results) { + const typeName = result[1]; + + if (!/(?:Param|Res)$/u.test(typeName)) { + continue; + } + + names.add(typeName); + } + + return [...names]; +} + +function formatTypeImport(typeNames: string[], importPath: string) { + const sortedNames = [...new Set(typeNames)].toSorted(); + + if (sortedNames.length === 0) { + return ''; + } + + if (sortedNames.length === 1) { + return `import type { ${sortedNames[0]} } from '${importPath}';`; + } + + return `import type {\n ${sortedNames.join(',\n ')},\n} from '${importPath}';`; +} + +function getImportPath(fileName: string) { + return `./${fileName.replace(/\.ts$/u, '')}`; +} + +function getSafeFileName(fileName?: string) { + const safeFileName = fileName?.trim() || 'type.ts'; + + if ( + !/^[\w.-]+\.ts$/u.test(safeFileName) || + safeFileName.includes('..') || + safeFileName.includes('/') || + safeFileName.includes('\\') + ) { + throw new ApiTypeGeneratorError('文件名必须是单个 .ts 文件名'); + } + + return safeFileName; +} + +function getSafeRelativeDir(dir?: string) { + const safeDir = (dir ?? '').trim().replaceAll('\\', '/'); + + if (!safeDir || safeDir === '.') { + return ''; + } + + if (path.isAbsolute(safeDir) || safeDir.split('/').includes('..')) { + throw new ApiTypeGeneratorError('目录路径不合法'); + } + + return safeDir.split('/').filter(Boolean).join('/'); +} + +function mergeTypeImport( + source: string, + importPath: string, + typeNames: string[], +) { + const importRegex = new RegExp( + String.raw`import\s+type\s+\{([\s\S]*?)\}\s+from\s+['"]${escapeRegExp( + importPath, + )}['"];?`, + 'u', + ); + const matchedImport = source.match(importRegex); + + if (matchedImport) { + const existedNames = matchedImport[1] + .split(',') + .map((item) => item.trim()) + .filter(Boolean); + const nextImport = formatTypeImport( + [...existedNames, ...typeNames], + importPath, + ); + + return source.replace(importRegex, nextImport); + } + + const importStatement = formatTypeImport(typeNames, importPath); + + if (!importStatement) { + return source; + } + + return `${importStatement}\n\n${source}`; +} + +function escapeRegExp(value: string) { + return value.replaceAll(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`); +} + +async function readJsonBody(request: IncomingMessage) { + const chunks: Buffer[] = []; + + for await (const chunk of request) { + chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); + } + + const content = Buffer.concat(chunks).toString('utf8'); + + if (!content) { + return {} as T; + } + + try { + return JSON.parse(content) as T; + } catch { + throw new ApiTypeGeneratorError('请求体必须是合法 JSON'); + } +} + +async function scanApiDirs(apiRoot: string) { + async function scan(currentDir: string): Promise { + const dirents = await fs.readdir(currentDir, { withFileTypes: true }); + const nodes = await Promise.all( + dirents + .filter((dirent) => dirent.isDirectory()) + .toSorted((prev, next) => prev.name.localeCompare(next.name)) + .map(async (dirent) => { + const fullPath = path.join(currentDir, dirent.name); + const relativePath = path + .relative(apiRoot, fullPath) + .replaceAll(path.sep, '/'); + const children = await scan(fullPath); + + return { + children: children.length > 0 ? children : undefined, + key: relativePath, + title: dirent.name, + value: relativePath, + }; + }), + ); + + return nodes; + } + + return [ + { + children: await scan(apiRoot), + key: '.', + title: 'api', + value: '.', + }, + ]; +} + +async function checkTypeFiles( + apiRoot: string, + payload: CheckTypeFilePayload, +) { + const items = payload.items ?? []; + + if (!Array.isArray(items)) { + throw new ApiTypeGeneratorError('检查参数必须是数组'); + } + + return Promise.all( + items.map(async (item, index) => { + const relativeDir = getSafeRelativeDir(item.dir); + const fileName = getSafeFileName(item.fileName); + const targetDir = path.resolve(apiRoot, relativeDir); + + ensureInApiRoot(apiRoot, targetDir); + + const targetPath = path.resolve(targetDir, fileName); + + ensureInApiRoot(apiRoot, targetPath); + + return { + dir: relativeDir || '.', + exists: await accessFile(targetPath), + fileName, + filePath: path.relative(apiRoot, targetPath).replaceAll(path.sep, '/'), + key: item.key ?? String(index), + }; + }), + ); +} + +function sendJson(response: ServerResponse, statusCode: number, data: unknown) { + response.statusCode = statusCode; + response.setHeader('Content-Type', 'application/json;charset=utf-8'); + response.end(JSON.stringify(data)); +} + +async function updateIndexTypeImport( + targetDir: string, + fileName: string, + content: string, +) { + const indexPath = path.join(targetDir, 'index.ts'); + const hasIndexFile = await accessFile(indexPath); + + if (!hasIndexFile) { + return { + importSkipped: true, + importUpdated: false, + }; + } + + const typeNames = extractTypeNames(content); + + if (typeNames.length === 0) { + return { + importSkipped: true, + importUpdated: false, + }; + } + + const source = await fs.readFile(indexPath, 'utf8'); + const nextSource = mergeTypeImport( + source, + getImportPath(fileName), + typeNames, + ); + + if (nextSource !== source) { + await fs.writeFile(indexPath, nextSource, 'utf8'); + } + + return { + importSkipped: false, + importUpdated: nextSource !== source, + }; +} + +async function writeTypeFile(apiRoot: string, payload: WriteTypePayload) { + const relativeDir = getSafeRelativeDir(payload.dir); + const fileName = getSafeFileName(payload.fileName); + const content = payload.content ?? ''; + + if (!content.trim()) { + throw new ApiTypeGeneratorError('类型定义内容不能为空'); + } + + const targetDir = path.resolve(apiRoot, relativeDir); + + ensureInApiRoot(apiRoot, targetDir); + + const targetPath = path.resolve(targetDir, fileName); + + ensureInApiRoot(apiRoot, targetPath); + + const exists = await accessFile(targetPath); + + if (exists && !payload.overwrite) { + throw new ApiTypeGeneratorError('目标文件已存在', 409, 'FILE_EXISTS'); + } + + await fs.mkdir(targetDir, { recursive: true }); + await fs.writeFile( + targetPath, + content.endsWith('\n') ? content : `${content}\n`, + 'utf8', + ); + + const importResult = payload.autoImport + ? await updateIndexTypeImport(targetDir, fileName, content) + : { + importSkipped: false, + importUpdated: false, + }; + + return { + exists, + filePath: path.relative(apiRoot, targetPath).replaceAll(path.sep, '/'), + ...importResult, + }; +} diff --git a/admin-ui/vue/apps/web-antd/postcss.config.mjs b/admin-ui/vue/apps/web-antd/postcss.config.mjs new file mode 100644 index 0000000..3d80704 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config/postcss'; diff --git a/admin-ui/vue/apps/web-antd/public/config.json b/admin-ui/vue/apps/web-antd/public/config.json new file mode 100644 index 0000000..e69de29 diff --git a/admin-ui/vue/apps/web-antd/public/favicon.ico b/admin-ui/vue/apps/web-antd/public/favicon.ico new file mode 100644 index 0000000..17edf34 Binary files /dev/null and b/admin-ui/vue/apps/web-antd/public/favicon.ico differ diff --git a/admin-ui/vue/apps/web-antd/public/logo.png b/admin-ui/vue/apps/web-antd/public/logo.png new file mode 100644 index 0000000..c93fb6d Binary files /dev/null and b/admin-ui/vue/apps/web-antd/public/logo.png differ diff --git a/admin-ui/vue/apps/web-antd/public/menu-setting.json b/admin-ui/vue/apps/web-antd/public/menu-setting.json new file mode 100644 index 0000000..ba683e7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/public/menu-setting.json @@ -0,0 +1,18 @@ +{ + "tDashboard": { + "businessAlert": true, + "businessVolume": true, + "dataSharing": true, + "feeSituation": true, + "lifeCycle": true, + "locationDistribution": true, + "myPanel": true, + "myPanelNew": true, + "myPanelSimActive": true, + "myPanelSimCount": true, + "myPanelUseData": true, + "myPanelUseMsg": true, + "quickAccessBorder": true, + "trafficPool": true + } +} diff --git a/admin-ui/vue/apps/web-antd/public/mini-program-code.png b/admin-ui/vue/apps/web-antd/public/mini-program-code.png new file mode 100644 index 0000000..ab9ef56 Binary files /dev/null and b/admin-ui/vue/apps/web-antd/public/mini-program-code.png differ diff --git a/admin-ui/vue/apps/web-antd/public/setting.json b/admin-ui/vue/apps/web-antd/public/setting.json new file mode 100644 index 0000000..7ea1074 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/public/setting.json @@ -0,0 +1,14 @@ +{ + "appTitle": "物联网全生命周期管理平台", + "appIcon": "/logo.png", + "loginPageTitle": "物联网设备上云首选", + "loginPageDescription": "新一代物联网设备统一接入平台", + "loginSloganImage": "", + "copyright": { + "companyName": "示例智联", + "companySiteLink": "https://example.com", + "date": "2024-2025", + "icp": "", + "icpLink": "https://beian.miit.gov.cn/" + } +} diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/antd.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/antd.ts new file mode 100644 index 0000000..ec537dc --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/antd.ts @@ -0,0 +1,102 @@ +import { defineAsyncComponent } from 'vue'; + +/** + * Ant Design Vue 基础组件统一在这里异步引入。 + * + * adapter 层只关心组件映射关系,避免把具体 UI 库的 import 细节散落到注册文件中。 + */ +export const AutoComplete = defineAsyncComponent( + () => import('ant-design-vue/es/auto-complete'), +); + +export const Button = defineAsyncComponent( + () => import('ant-design-vue/es/button'), +); + +export const Checkbox = defineAsyncComponent( + () => import('ant-design-vue/es/checkbox'), +); + +export const CheckboxGroup = defineAsyncComponent(() => + import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup), +); + +export const DatePicker = defineAsyncComponent( + () => import('ant-design-vue/es/date-picker'), +); + +export const Divider = defineAsyncComponent( + () => import('ant-design-vue/es/divider'), +); + +export const Image = defineAsyncComponent( + () => import('ant-design-vue/es/image'), +); + +export const Input = defineAsyncComponent( + () => import('ant-design-vue/es/input'), +); + +export const InputNumber = defineAsyncComponent( + () => import('ant-design-vue/es/input-number'), +); + +export const InputPassword = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.InputPassword), +); + +export const Mentions = defineAsyncComponent( + () => import('ant-design-vue/es/mentions'), +); + +export const PreviewGroup = defineAsyncComponent(() => + import('ant-design-vue/es/image').then((res) => res.ImagePreviewGroup), +); + +export const Radio = defineAsyncComponent( + () => import('ant-design-vue/es/radio'), +); + +export const RadioGroup = defineAsyncComponent(() => + import('ant-design-vue/es/radio').then((res) => res.RadioGroup), +); + +export const RangePicker = defineAsyncComponent(() => + import('ant-design-vue/es/date-picker').then((res) => res.RangePicker), +); + +export const Rate = defineAsyncComponent( + () => import('ant-design-vue/es/rate'), +); + +export const Select = defineAsyncComponent( + () => import('ant-design-vue/es/select'), +); + +export const Space = defineAsyncComponent( + () => import('ant-design-vue/es/space'), +); + +export const Switch = defineAsyncComponent( + () => import('ant-design-vue/es/switch'), +); + +export const Textarea = defineAsyncComponent(() => + import('ant-design-vue/es/input').then((res) => res.Textarea), +); + +export const TimePicker = defineAsyncComponent( + () => import('ant-design-vue/es/time-picker'), +); + +export const TreeSelect = defineAsyncComponent( + () => import('ant-design-vue/es/tree-select'), +); + +export const Cascader = defineAsyncComponent( + () => import('ant-design-vue/es/cascader'), +); + +export const Upload = defineAsyncComponent( + () => import('ant-design-vue/es/upload'), +); diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/message.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/message.ts new file mode 100644 index 0000000..81d7282 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/message.ts @@ -0,0 +1,20 @@ +import { globalShareState } from '@vben/common-ui'; + +import { notification } from 'ant-design-vue'; + +/** + * 框架共享消息适配。 + * + * common-ui 内部只声明消息场景,这里绑定到当前 UI 库的 notification 实现。 + */ +export function defineComponentAdapterMessage() { + globalShareState.defineMessage({ + copyPreferencesSuccess: (title, content) => { + notification.success({ + description: content, + message: title, + placement: 'bottomRight', + }); + }, + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/upload-preview.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/upload-preview.ts new file mode 100644 index 0000000..2ab25b1 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/upload-preview.ts @@ -0,0 +1,125 @@ +import type { UploadFile, UploadProps } from 'ant-design-vue'; + +import type { Ref } from 'vue'; + +import { h, render, unref } from 'vue'; + +import { Image, PreviewGroup } from '../antd'; + +/** + * UploadFile 没有稳定的图片标识字段时,通过 url/name/type 组合判断是否走图片预览。 + */ +function isImageFile(file: UploadFile): boolean { + const imageExtensions = new Set(['bmp', 'gif', 'jpeg', 'jpg', 'png', 'webp']); + + if (file.url) { + const ext = file.url?.split('.').pop()?.toLowerCase(); + return ext ? imageExtensions.has(ext) : false; + } + + if (!file.type) { + const ext = file.name?.split('.').pop()?.toLowerCase(); + return ext ? imageExtensions.has(ext) : false; + } + + return file.type.startsWith('image/'); +} + +/** + * 本地待上传图片没有 url 时,需要转成 base64 才能进入 ImagePreviewGroup。 + */ +function getBase64(file: File) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.addEventListener('load', () => resolve(reader.result)); + reader.addEventListener('error', (error) => reject(error)); + }); +} + +/** + * 基于 Ant Design Vue ImagePreviewGroup 创建一次性预览容器。 + * + * 预览关闭后会卸载并移除临时 DOM,避免多次预览后残留节点。 + */ +export const previewImage = async ( + file: UploadFile, + visible: Ref, + fileList: Ref, +) => { + // 非图片沿用文件打开行为,不进入图片预览组 + if (!isImageFile(file)) { + if (file.url) { + window.open(file.url, '_blank'); + } else if (file.preview) { + window.open(file.preview, '_blank'); + } else { + console.warn('无法打开文件,没有可用的URL或预览地址'); + } + return; + } + + // Image 与 PreviewGroup 只有预览时才加载,保持基础表单渲染轻量 + const [ImageComponent, PreviewGroupComponent] = await Promise.all([ + Image, + PreviewGroup, + ]); + + const imageFiles = (unref(fileList) || []).filter((element) => + isImageFile(element), + ); + + // 同一上传列表中的图片都加入预览组,支持左右切换 + for (const imgFile of imageFiles) { + if (!imgFile.url && !imgFile.preview && imgFile.originFileObj) { + imgFile.preview = (await getBase64(imgFile.originFileObj)) as string; + } + } + + const container: HTMLElement | null = document.createElement('div'); + document.body.append(container); + + // 避免关闭动画期间重复触发卸载 + let isUnmounted = false; + + const PreviewWrapper = { + setup() { + return () => { + if (isUnmounted) return null; + + return h( + PreviewGroupComponent, + { + class: 'hidden', + preview: { + visible: visible.value, + current: imageFiles.findIndex((f) => f.uid === file.uid), + onVisibleChange: (value: boolean) => { + visible.value = value; + if (!value) { + // 等待预览关闭动画结束后再卸载临时容器 + setTimeout(() => { + if (!isUnmounted && container) { + isUnmounted = true; + render(null, container); + container.remove(); + } + }, 300); + } + }, + }, + }, + () => + imageFiles.map((imgFile) => + h(ImageComponent, { + key: imgFile.uid, + src: imgFile.url || imgFile.preview, + }), + ), + ); + }; + }, + }; + + render(h(PreviewWrapper), container); +}; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/with-default-placeholder.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/with-default-placeholder.ts new file mode 100644 index 0000000..c19be18 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/with-default-placeholder.ts @@ -0,0 +1,46 @@ +import type { Component } from 'vue'; + +import type { Recordable } from '@vben/types'; + +import { defineComponent, h, ref } from 'vue'; + +import { $t } from '@vben/locales'; + +/** + * 为输入类/选择类组件补齐统一占位文案,并保留原组件暴露的方法。 + */ +export const withDefaultPlaceholder = ( + component: T, + type: 'input' | 'select', + componentProps: Recordable = {}, +) => { + return defineComponent({ + name: component.name, + inheritAttrs: false, + setup: (props: any, { attrs, expose, slots }) => { + const placeholder = + props?.placeholder || + attrs?.placeholder || + $t(`ui.placeholder.${type}`); + const innerRef = ref(); + + // 透传内部组件实例方法,避免包装后影响外部通过 ref 调用 focus 等能力 + expose( + new Proxy( + {}, + { + get: (_target, key) => innerRef.value?.[key], + has: (_target, key) => key in (innerRef.value || {}), + }, + ), + ); + + return () => + h( + component, + { ...componentProps, placeholder, ...props, ...attrs, ref: innerRef }, + slots, + ); + }, + }); +}; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/with-preview-upload.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/with-preview-upload.ts new file mode 100644 index 0000000..305ffe8 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/helpers/with-preview-upload.ts @@ -0,0 +1,114 @@ +import type { + UploadChangeParam, + UploadFile, + UploadProps, +} from 'ant-design-vue'; + +import { defineComponent, h, ref, watch } from 'vue'; + +import { IconifyIcon } from '@vben/icons'; +import { $t } from '@vben/locales'; +import { isEmpty } from '@vben/utils'; + +import { Button, Upload } from '../antd'; +import { previewImage } from './upload-preview'; + +/** + * Upload 未提供自定义插槽时,补齐项目统一的默认上传按钮。 + */ +function createDefaultSlotsWithUpload(listType: string, placeholder: string) { + switch (listType) { + case 'picture-card': { + return { + default: () => placeholder, + }; + } + default: { + return { + default: () => + h( + Button, + { + icon: h(IconifyIcon, { + icon: 'ant-design:upload-outlined', + class: 'mb-1 size-4', + }), + }, + () => placeholder, + ), + }; + } + } +} + +/** + * 适配 Ant Design Vue Upload 到 Vben Form: + * - 使用 modelValue 与表单值同步 + * - 上传列表为空时回写 undefined + * - 内置图片预览,非图片文件直接打开地址 + */ +export const withPreviewUpload = () => { + return defineComponent({ + name: Upload.name, + emits: ['change', 'update:modelValue'], + setup: ( + props: any, + { attrs, slots, emit }: { attrs: any; emit: any; slots: any }, + ) => { + const previewVisible = ref(false); + const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`); + const listType = attrs?.listType || attrs?.['list-type'] || 'text'; + const fileList = ref( + attrs?.fileList || attrs?.['file-list'] || [], + ); + + const handleChange = async (event: UploadChangeParam) => { + fileList.value = event.fileList; + emit('change', event); + emit( + 'update:modelValue', + event.fileList?.length ? fileList.value : undefined, + ); + }; + + const handlePreview = async (file: UploadFile) => { + previewVisible.value = true; + await previewImage(file, previewVisible, fileList); + }; + + const renderUploadButton = (): any => { + const isDisabled = attrs.disabled; + + // 禁用状态下只展示文件列表,不再渲染上传入口 + if (isDisabled) { + return null; + } + + return isEmpty(slots) + ? createDefaultSlotsWithUpload(listType, placeholder) + : slots; + }; + + // 监听 formApi.setValues 等外部回填,保持 Upload 内部 fileList 同步 + watch( + () => attrs.modelValue, + (res) => { + fileList.value = res; + }, + ); + + return () => + h( + Upload, + { + ...props, + ...attrs, + fileList: fileList.value, + onChange: handleChange, + onPreview: handlePreview, + }, + renderUploadButton(), + ); + }, + }); +}; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/index.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/index.ts new file mode 100644 index 0000000..fb4b084 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/index.ts @@ -0,0 +1,136 @@ +import type { Component } from 'vue'; + +import type { ComponentType } from './types'; + +import { h } from 'vue'; + +import { ApiComponent, globalShareState, IconPicker } from '@vben/common-ui'; + +import { HtcRegisterComponent } from '#/components/HtCustom/FormExpand/register'; +import { Tinymce as RichTextarea } from '#/components/tinymce'; +import { FileUpload, ImageUpload } from '#/components/upload'; + +import { + AutoComplete, + Button, + Cascader, + Checkbox, + CheckboxGroup, + DatePicker, + Divider, + Input, + InputNumber, + InputPassword, + Mentions, + Radio, + RadioGroup, + RangePicker, + Rate, + Select, + Space, + Switch, + Textarea, + TimePicker, + TreeSelect, +} from './antd'; +import { defineComponentAdapterMessage } from './helpers/message'; +import { withDefaultPlaceholder } from './helpers/with-default-placeholder'; +import { withPreviewUpload } from './helpers/with-preview-upload'; + +/** + * 通用组件适配层。 + * + * 这里只维护“组件名称 -> 真实组件”的映射关系,供 vben-form、vben-modal、 + * vben-drawer 等框架组件通过 globalShareState 复用。 + */ +function createComponentAdapterMap(): Partial< + Record +> { + return { + // 如果你的组件体积比较大,可以使用异步加载 + // Button: () => + // import('xxx').then((res) => res.Button), + ApiCascader: withDefaultPlaceholder(ApiComponent, 'select', { + component: Cascader, + fieldNames: { label: 'label', value: 'value', children: 'children' }, + loadingSlot: 'suffixIcon', + modelPropName: 'value', + visibleEvent: 'onVisibleChange', + }), + ApiSelect: withDefaultPlaceholder( + { + ...ApiComponent, + name: 'ApiSelect', + }, + 'select', + { + component: Select, + loadingSlot: 'suffixIcon', + visibleEvent: 'onDropdownVisibleChange', + modelPropName: 'value', + }, + ), + ApiTreeSelect: withDefaultPlaceholder( + { + ...ApiComponent, + name: 'ApiTreeSelect', + }, + 'select', + { + component: TreeSelect, + fieldNames: { label: 'label', value: 'value', children: 'children' }, + loadingSlot: 'suffixIcon', + modelPropName: 'value', + optionsPropName: 'treeData', + visibleEvent: 'onVisibleChange', + }, + ), + AutoComplete, + Cascader, + Checkbox, + CheckboxGroup, + DatePicker, + // 弹窗、抽屉等框架组件会通过共享状态读取这两个按钮组件 + DefaultButton: (props, { attrs, slots }) => { + return h(Button, { ...props, attrs, type: 'default' }, slots); + }, + Divider, + FileUpload, + ImageUpload, + IconPicker: withDefaultPlaceholder(IconPicker, 'select', { + iconSlot: 'addonAfter', + inputComponent: Input, + modelValueProp: 'value', + }), + Input: withDefaultPlaceholder(Input, 'input'), + InputNumber: withDefaultPlaceholder(InputNumber, 'input'), + InputPassword: withDefaultPlaceholder(InputPassword, 'input'), + Mentions: withDefaultPlaceholder(Mentions, 'input'), + PrimaryButton: (props, { attrs, slots }) => { + return h(Button, { ...props, attrs, type: 'primary' }, slots); + }, + Radio, + RadioGroup, + RangePicker, + Rate, + RichTextarea, + Select: withDefaultPlaceholder(Select, 'select'), + // SelectDivision, + Space, + Switch, + Textarea: withDefaultPlaceholder(Textarea, 'input'), + TimePicker, + TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'), + Upload: withPreviewUpload(), + ...HtcRegisterComponent, + }; +} + +async function initComponentAdapter() { + // 先注册组件,再初始化 form 适配,确保 setupVbenForm 能读到完整组件表 + globalShareState.setComponents(createComponentAdapterMap()); + defineComponentAdapterMessage(); +} + +export { initComponentAdapter }; +export type { ComponentType }; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/props.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/props.ts new file mode 100644 index 0000000..09f6cc6 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/props.ts @@ -0,0 +1,19 @@ +import type { SchemaComponentType } from './types'; + +import type { HtcComponentPropsMap } from '#/components/HtCustom/FormExpand/register'; + +type ComponentPropsGetter = ( + value: Partial>, + actions: any, +) => Props; + +type ComponentPropsMap = HtcComponentPropsMap; + +type UntypedComponentProps = + | ComponentPropsGetter> + | Record; + +export type ComponentProps = + T extends keyof ComponentPropsMap + ? ComponentPropsGetter | ComponentPropsMap[T] + : UntypedComponentProps; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/component/types.ts b/admin-ui/vue/apps/web-antd/src/adapter/component/types.ts new file mode 100644 index 0000000..fbced8b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/component/types.ts @@ -0,0 +1,61 @@ +import type { BaseFormComponentType } from '@vben/common-ui'; + +import type { HtcRegisterComponentName } from '#/components/HtCustom/FormExpand/register'; + +/** + * 表单 schema 中 component 字段允许使用的组件名称。 + * + * 新增适配组件时,需要同时在这里补充名称,并在 index.ts 中注册真实组件。 + */ +export type AdapterComponentType = + | 'ApiCascader' + | 'ApiSelect' + | 'ApiTreeSelect' + | 'AutoComplete' + | 'Cascader' + | 'Checkbox' + | 'CheckboxGroup' + | 'DatePicker' + | 'DefaultButton' + | 'Divider' + | 'FileUpload' + | 'HtcFormSwitch' + | 'IconPicker' + | 'ImageUpload' + | 'Input' + | 'InputNumber' + | 'InputPassword' + | 'Mentions' + | 'PrimaryButton' + | 'Radio' + | 'RadioGroup' + | 'RangePicker' + | 'Rate' + | 'RichTextarea' + | 'Select' + | 'SelectDivision' + | 'Space' + | 'Switch' + | 'Textarea' + | 'TimePicker' + | 'TreeSelect' + | 'Upload'; + +export type BaseComponentType = + | 'DefaultButton' + | 'PrimaryButton' + | 'VbenCheckbox' + | 'VbenInput' + | 'VbenInputPassword' + | 'VbenPinInput' + | 'VbenSelect'; + +export type SchemaComponentType = + | AdapterComponentType + | BaseComponentType + | HtcRegisterComponentName; + +export type ComponentType = + | AdapterComponentType + | BaseFormComponentType + | HtcRegisterComponentName; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/form.ts b/admin-ui/vue/apps/web-antd/src/adapter/form.ts new file mode 100644 index 0000000..a6d01bd --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/form.ts @@ -0,0 +1,68 @@ +import type { + VbenFormProps as BaseVbenFormProps, + VbenFormSchema as FormSchema, +} from '@vben/common-ui'; + +import type { ComponentType } from './component'; +import type { ComponentProps } from './component/props'; +import type { SchemaComponentType } from './component/types'; + +import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui'; +import { $t } from '@vben/locales'; + +async function initSetupVbenForm() { + setupVbenForm({ + config: { + // ant design vue组件库默认都是 v-model:value + baseModelPropName: 'value', + + // 一些组件是 v-model:checked 或者 v-model:fileList + modelPropNameMap: { + Checkbox: 'checked', + Radio: 'checked', + RichTextarea: 'modelValue', + Switch: 'checked', + Upload: 'fileList', + ImageUpload: 'value', + }, + }, + defineRules: { + // 输入项目必填国际化适配 + required: (value, _params, ctx) => { + if (value === undefined || value === null || value.length === 0) { + return $t('ui.formRules.required', [ctx.label]); + } + return true; + }, + // 选择项目必填国际化适配 + selectRequired: (value, _params, ctx) => { + if (value === undefined || value === null) { + return $t('ui.formRules.selectRequired', [ctx.label]); + } + return true; + }, + }, + }); +} + +type TypedFormSchema = Omit< + FormSchema, + 'component' | 'componentProps' +> & { + component: T; + componentProps?: ComponentProps; +}; + +export type VbenFormSchema = { + [K in SchemaComponentType]: TypedFormSchema; +}[SchemaComponentType]; + +export type VbenFormProps = Omit, 'schema'> & { + schema?: VbenFormSchema[]; +}; + +const useVbenForm = (options: VbenFormProps) => { + return useForm(options as BaseVbenFormProps); +}; + +export { initSetupVbenForm, useVbenForm, z }; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/highlightedit.ts b/admin-ui/vue/apps/web-antd/src/adapter/highlightedit.ts new file mode 100644 index 0000000..5eb7d16 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/highlightedit.ts @@ -0,0 +1,124 @@ +/* eslint-disable vue/no-side-effects-in-computed-properties */ +import { computed, defineComponent, h, ref, watch } from 'vue'; + +import hljs from 'highlight.js/lib/core'; + +const component = defineComponent({ + props: { + code: { + type: String, + required: true, + }, + language: { + type: String, + default: '', + }, + autodetect: { + type: Boolean, + default: true, + }, + ignoreIllegals: { + type: Boolean, + default: true, + }, + }, + setup(props, { emit }) { + const language = ref(props.language); + const ignoreIllegals = ref(props.ignoreIllegals); + watch( + () => props.language, + (newLanguage) => { + language.value = newLanguage; + }, + ); + watch( + () => props.ignoreIllegals, + (newIgnoreIllegals) => { + ignoreIllegals.value = newIgnoreIllegals; + }, + ); + + const autodetect = computed(() => props.autodetect || !language.value); + const cannotDetectLanguage = computed( + () => !autodetect.value && !hljs.getLanguage(language.value), + ); + + const className = computed((): string => { + return cannotDetectLanguage.value ? '' : `hljs ${language.value}`; + }); + + const highlightedCode = computed((): string => { + // No idea what language to use, return raw code + if (cannotDetectLanguage.value) { + console.warn( + `The language "${language.value}" you specified could not be found.`, + ); + return props.code; + } + + if (autodetect.value) { + const result = hljs.highlightAuto(props.code); + language.value = result.language ?? ''; + return result.value; + } else { + const result = hljs.highlight(props.code, { + language: language.value, + ignoreIllegals: props.ignoreIllegals, + }); + return result.value; + } + }); + // const saveSelection = (e: any) => { + // const selection = window.getSelection(); + // if (selection && selection.rangeCount && selection.rangeCount > 0) { + // const range = selection.getRangeAt(0); + // return range; + // } + // return null; + // }; + // const restoreSelection = (range: any, el: any) => { + // if (range) { + // const selection = window.getSelection(); + // if (selection) { + // selection.removeAllRanges(); + // selection.addRange(range); + // console.log('selection range', range); + // } + // } + // }; + const updateContent = (e: any) => { + // const range = saveSelection(e) + const result = hljs.highlight(e.target.innerText, { + language: language.value, + ignoreIllegals: props.ignoreIllegals, + }); + e.target.innerHTML = result.value; + emit('update:code', e.target.innerText); + // setTimeout(() => { + // restoreSelection(range, e.target) + // }, 0) + }; + return { + className, + highlightedCode, + updateContent, + emit, + }; + }, + render() { + const updateContent = this.updateContent; + return h('pre', {}, [ + h('code', { + class: this.className, + innerHTML: this.highlightedCode, + contenteditable: true, + // onInput(e: any) {}, + onBlur(e: any) { + updateContent(e); + }, + }), + ]); + }, +}); + +export default component; diff --git a/admin-ui/vue/apps/web-antd/src/adapter/vxe-table.ts b/admin-ui/vue/apps/web-antd/src/adapter/vxe-table.ts new file mode 100644 index 0000000..e0e0d69 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/adapter/vxe-table.ts @@ -0,0 +1,69 @@ +import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; + +import { h } from 'vue'; + +import { useVbenForm } from '@vben/common-ui'; +import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; + +import { Button, Image } from 'ant-design-vue'; + +setupVbenVxeTable({ + configVxeTable: (vxeUI) => { + vxeUI.setConfig({ + grid: { + align: 'center', + border: false, + columnConfig: { + resizable: true, + }, + minHeight: 180, + formConfig: { + // 全局禁用vxe-table的表单配置,使用formOptions + enabled: false, + }, + proxyConfig: { + autoLoad: true, + response: { + result: 'items', + total: 'total', + list: 'items', + }, + showActiveMsg: true, + showResponseMsg: false, + }, + round: true, + showOverflow: true, + size: 'small', + } as VxeTableGridOptions, + }); + + // 表格配置项可以用 cellRender: { name: 'CellImage' }, + vxeUI.renderer.add('CellImage', { + renderTableDefault(renderOpts, params) { + const { props } = renderOpts; + const { column, row } = params; + return h(Image, { src: row[column.field], ...props }); + }, + }); + + // 表格配置项可以用 cellRender: { name: 'CellLink' }, + vxeUI.renderer.add('CellLink', { + renderTableDefault(renderOpts) { + const { props } = renderOpts; + return h( + Button, + { size: 'small', type: 'link' }, + { default: () => props?.text }, + ); + }, + }); + + // 这里可以自行扩展 vxe-table 的全局配置,比如自定义格式化 + // vxeUI.formats.add + }, + useVbenForm, +}); + +export { useVbenVxeGrid }; + +export type * from '@vben/plugins/vxe-table'; diff --git a/admin-ui/vue/apps/web-antd/src/api/agent/index.ts b/admin-ui/vue/apps/web-antd/src/api/agent/index.ts new file mode 100644 index 0000000..f17e913 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/agent/index.ts @@ -0,0 +1,207 @@ +import { requestClient } from '#/api/request'; + +export interface AgentDept { + deptId: number; + tenantId?: string; + deptType: number; + parentId: number; + ancestors?: string; + deptKey?: string; + deptName: string; + deptCategory?: string; + orderNum?: number; + leader?: number; + phone?: string; + email?: string; + status: string; + creditCode?: string; + areaCode?: string; + address?: string; + deptRole?: number; + userName?: string; + defaultUserName?: string; + nickName?: string; + defaultNickName?: string; + defaultUserNickName?: string; + defaultUserId?: number; + password?: string; + createdAt?: string; +} + +export interface AgentRole { + roleId: number; + tenantId?: string; + deptId: number; + deptName?: string; + roleName: string; + roleKey: string; + roleSort?: number; + dataScope?: string; + menuCheckStrictly?: number; + deptCheckStrictly?: number; + isPass?: number; + sourceRoleId?: number; + sourceDeptId?: number; + status: string; + createdAt?: string; + remark?: string; + isDefaultRole?: boolean; +} + +export interface MenuTreeItem { + title: string; + key: string; + parentId: number; + menuId: number; + menuName: string; + menuType: string; + perms?: string; + children?: MenuTreeItem[]; +} + +export interface AgentRoleView extends AgentRole { + isTemplateRole: boolean; + isDeptDefaultRole: boolean; + menuIds: number[]; + deptIds: number[]; + allowedMenuIds: number[]; + menuTree: MenuTreeItem[]; +} + +export interface AgentUser { + userId: number; + tenantId: string; + deptId: number; + userName: string; + nickName: string; + userType: string; + email: string; + phonenumber: string; + sex: string; + avatar: string; + status: string; + loginIp?: string; + loginDate?: string; + createdDept?: number; + createdBy?: number; + createdAt?: string; + remark?: string; + deptInfo?: { deptId: number; deptName: string }; + roles?: AgentRole[]; + isDefaultUser?: boolean; +} + +export interface AgentDeptListParams { + page?: number; + pageSize?: number; + deptName?: string; + status?: string; + deptType?: number; +} + +export function exportAgentDeptApi(params?: Record) { + return requestClient.get('/agent/dept/export', { + params, + responseType: 'blob', + }); +} + +export function exportAgentUserApi(params?: Record) { + return requestClient.get('/agent/user/export', { + params, + responseType: 'blob', + }); +} + +export function getAgentDeptListApi(params?: AgentDeptListParams) { + return requestClient.get<{ + items: AgentDept[]; + page: number; + pageSize: number; + total: number; + }>('/agent/dept/list', { params }); +} + +export function getAgentDeptViewApi(params: { deptId: number }) { + return requestClient.get('/agent/dept/view', { params }); +} + +export function saveAgentDeptApi(params: Partial) { + return requestClient.post<{ deptId: number }>('/agent/dept/save', { + ...params, + }); +} + +export function deleteAgentDeptApi(params: { deptId: number }) { + return requestClient.post('/agent/dept/delete', { ...params }); +} + +export function resetAgentDeptPasswordApi(params: { + deptId: number; + password: string; +}) { + return requestClient.post('/agent/dept/resetPassword', { ...params }); +} + +export function getAgentUserListApi(params?: Record) { + return requestClient.get<{ items: AgentUser[]; total: number }>( + '/agent/user/list', + { params }, + ); +} + +export function getAgentUserViewApi(params: { userId: number }) { + return requestClient.get('/agent/user/view', { params }); +} + +export function addAgentUserApi(params: Record) { + return requestClient.post('/agent/user/add', { ...params }); +} + +export function updateAgentUserApi(params: Record) { + return requestClient.post('/agent/user/update', { ...params }); +} + +export function deleteAgentUserApi(params: { + userId?: number; + userIds?: number[]; +}) { + return requestClient.post('/agent/user/delete', { ...params }); +} + +export function resetAgentUserPasswordApi(params: { + password: string; + userId: number; +}) { + return requestClient.post('/agent/user/resetPassword', { ...params }); +} + +export function getAgentRoleListApi(params?: Record) { + return requestClient.get<{ items: AgentRole[]; total: number }>( + '/agent/role/list', + { params }, + ); +} + +export function getAgentRoleViewApi(params: { roleId: number }) { + return requestClient.get('/agent/role/view', { params }); +} + +export function saveAgentRoleApi(params: Record) { + return requestClient.post<{ roleId: number }>('/agent/role/save', { + ...params, + }); +} + +export function deleteAgentRoleApi(params: { + roleId?: number; + roleIds?: number[]; +}) { + return requestClient.post('/agent/role/delete', { ...params }); +} + +export function getAgentMenuTreeApi() { + return requestClient.get<{ items: MenuTreeItem[]; menuIds: number[] }>( + '/agent/menu/tree', + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/agent/tApiGroup/index.ts b/admin-ui/vue/apps/web-antd/src/api/agent/tApiGroup/index.ts new file mode 100644 index 0000000..ff208af --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/agent/tApiGroup/index.ts @@ -0,0 +1,34 @@ +import { requestClient } from '#/api/request'; + +// 获取开放接口权限组表列表 +export function List(params:any) { + return requestClient.get('agent/tApiGroup/list', { params }); +} + +// 删除/批量删除开放接口权限组表 +export function Delete(params:any) { + return requestClient.post('agent/tApiGroup/delete', { ...params }); +} + +// 添加/编辑开放接口权限组表 +export function Edit(params:any) { + return requestClient.post('agent/tApiGroup/edit', { ...params }); +} + +// 修改开放接口权限组表状态 +export function Status(params:any) { + return requestClient.post('agent/tApiGroup/status', { ...params }); +} + +// 获取开放接口权限组表指定详情 +export function View(params:any) { + return requestClient.get('agent/tApiGroup/view', { params }); +} + +// 导出开放接口权限组表 +export function Export(params:any) { + return requestClient.post('/agent/tApiGroup/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/agent/tApiResource/index.ts b/admin-ui/vue/apps/web-antd/src/api/agent/tApiResource/index.ts new file mode 100644 index 0000000..06b89a9 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/agent/tApiResource/index.ts @@ -0,0 +1,34 @@ +import { requestClient } from '#/api/request'; + +// 获取开放接口资源表列表 +export function List(params:any) { + return requestClient.get('agent/tApiResource/list', { params }); +} + +// 删除/批量删除开放接口资源表 +export function Delete(params:any) { + return requestClient.post('agent/tApiResource/delete', { ...params }); +} + +// 添加/编辑开放接口资源表 +export function Edit(params:any) { + return requestClient.post('agent/tApiResource/edit', { ...params }); +} + +// 修改开放接口资源表状态 +export function Status(params:any) { + return requestClient.post('agent/tApiResource/status', { ...params }); +} + +// 获取开放接口资源表指定详情 +export function View(params:any) { + return requestClient.get('agent/tApiResource/view', { params }); +} + +// 导出开放接口资源表 +export function Export(params:any) { + return requestClient.post('/agent/tApiResource/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/common/downloadCenter/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/downloadCenter/index.ts new file mode 100644 index 0000000..5d4b936 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/downloadCenter/index.ts @@ -0,0 +1,98 @@ +import { message } from 'ant-design-vue'; + +import { requestClient } from '#/api/request'; + +export interface DownloadCenterListParam { + page?: number; + pageSize?: number; + keyword?: string; + bizKey?: string; + /** 多个状态用逗号分隔:0排队 2生成中 1已完成 3失败 */ + status?: string; + createdAt?: string[]; +} + +export interface DownloadCenterItem { + id: number; + taskNo: string; + bizKey: string; + bizName: string; + status: number; + totalCount: number; + fileName: string; + fileSize: number; + errorMessage?: string; + createdAt?: string; + finishTime?: string; + expireTime?: string; + deletedTime?: null | string; + deleteReason?: '' | 'expired' | 'user'; +} + +export interface DownloadCenterListResult { + items: DownloadCenterItem[]; + page: number; + pageSize: number; + total: number; +} + +export interface DownloadCenterRecentResult { + items: DownloadCenterItem[]; + runningCount: number; + finishedCount: number; +} + +/** 下载中心列表 */ +export function List(params: DownloadCenterListParam) { + return requestClient.get( + '/common/downloadCenter/list', + { + params, + }, + ); +} + +/** 右上角入口:最近任务与进行中数量。 + * 这是辅助信息,无权限或后端未就绪时静默失败,不能弹全局错误打扰用户。 */ +export function Recent(limit = 5) { + return requestClient.get( + '/common/downloadCenter/recent', + { params: { limit }, errorMessageMode: 'none' }, + ); +} + +/** 下载导出文件:业务错误可能以 HTTP 200 JSON Blob 返回,不能当作 xlsx 保存。 */ +export async function Download(taskId: number): Promise { + const response = await requestClient.download< + import('axios').AxiosResponse + >(`/common/downloadCenter/download?taskId=${taskId}`, { + timeout: 120 * 1000, + responseReturn: 'raw', + }); + const blob = response.data; + const contentType = String( + response.headers['content-type'] || blob?.type || '', + ).toLowerCase(); + if (contentType.includes('json')) { + let errorMessage = '下载失败,请稍后重试'; + try { + const payload = JSON.parse(await blob.text()); + errorMessage = payload?.message || errorMessage; + } catch { + // Malformed JSON must not be saved as a spreadsheet either. + } + message.error(errorMessage); + throw new Error(errorMessage); + } + if (!(blob instanceof Blob) || blob.size === 0) { + const errorMessage = '下载文件为空,请稍后重试'; + message.error(errorMessage); + throw new Error(errorMessage); + } + return blob; +} + +/** 删除导出任务 */ +export function Remove(taskId: number) { + return requestClient.post('/common/downloadCenter/remove', { taskId }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tAgentBalance/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tAgentBalance/index.ts new file mode 100644 index 0000000..76c1ee7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tAgentBalance/index.ts @@ -0,0 +1,70 @@ +import { requestClient } from '#/api/request'; + +// 获取企业客户财务信息列表 +export function List(params:any) { + return requestClient.get('common/tAgentBalance/list', { params }); +} + +// 获取账户余额概览 +export function GetAccountBalance(params?: any) { + return requestClient.get('common/tAgentBalance/getAccountBalance', { params }); +} + +// 获取费用总览折线图 +export function FeeTrend(params: any) { + return requestClient.get('common/tAgentBalance/feeTrend', { params }); +} + +// 获取账户总览折线图 +export function AccountTrend(params: any) { + return requestClient.get('common/tAgentBalance/accountTrend', { params }); +} + +// 删除/批量删除企业客户财务信息 +export function Delete(params:any) { + return requestClient.post('common/tAgentBalance/delete', { ...params }); +} + +// 添加/编辑企业客户财务信息 +export function Edit(params:any) { + return requestClient.post('common/tAgentBalance/edit', { ...params }); +} + +// 修改企业客户财务信息状态 +export function Status(params:any) { + return requestClient.post('common/tAgentBalance/status', { ...params }); +} + +// 获取企业客户财务信息指定详情 +export function View(params:any) { + return requestClient.get('common/tAgentBalance/view', { params }); +} + +// 导出企业客户财务信息 +export function Export(params:any) { + return requestClient.post('/common/tAgentBalance/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} + +export function AlipayPay(params: any) { + return requestClient.post('pay/alipay/pay', params); +} + +export function AlipayQuery(params: any) { + return requestClient.get('pay/alipay/query', { params }); +} + +// 转可提现申请 +export function BalanceTransferApply(params: { + amount: number; + accountType: number; + bankName?: string; + bankAccount?: string; + accountName?: string; + identityCard?: string; + remark?: string; +}) { + return requestClient.post('common/tAgentBalance/balanceTransferApply', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tBalanceDetail/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tBalanceDetail/index.ts new file mode 100644 index 0000000..202af86 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tBalanceDetail/index.ts @@ -0,0 +1,33 @@ +import { requestClient } from '#/api/request'; + +// 获取余额明细表列表 +export function List(params:any) { + return requestClient.get('common/tBalanceDetail/list', { params }); +} + +// 删除/批量删除余额明细表 +export function Delete(params:any) { + return requestClient.post('common/tBalanceDetail/delete', { ...params }); +} + +// 添加/编辑余额明细表 +export function Edit(params:any) { + return requestClient.post('common/tBalanceDetail/edit', { ...params }); +} + +// 获取余额明细表指定详情 +export function View(params:any) { + return requestClient.get('common/tBalanceDetail/view', { params }); +} + +// 导出余额明细表 +export function Export(params:any) { + return requestClient.post('/common/tBalanceDetail/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} + +export function Recharge(params:any) { + return requestClient.post('common/tBalanceDetail/recharge', { ...params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tConsumeAccountMonthBill/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tConsumeAccountMonthBill/index.ts new file mode 100644 index 0000000..8a457d9 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tConsumeAccountMonthBill/index.ts @@ -0,0 +1,34 @@ +import { requestClient } from '#/api/request'; + +// 获取消费账户月账单表列表 +export function List(params:any) { + return requestClient.get('common/tConsumeAccountMonthBill/list', { params }); +} + +// 获取消费账户月账单汇总 +export function GetConsumptionBillSummary(params:any) { + return requestClient.get('common/tConsumeAccountMonthBill/getConsumptionBillSummary', { params }); +} + +// 删除/批量删除消费账户月账单表 +export function Delete(params:any) { + return requestClient.post('common/tConsumeAccountMonthBill/delete', { ...params }); +} + +// 添加/编辑消费账户月账单表 +export function Edit(params:any) { + return requestClient.post('common/tConsumeAccountMonthBill/edit', { ...params }); +} + +// 获取消费账户月账单表指定详情 +export function View(params:any) { + return requestClient.get('common/tConsumeAccountMonthBill/view', { params }); +} + +// 导出消费账户月账单表 +export function Export(params:any) { + return requestClient.post('/common/tConsumeAccountMonthBill/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tCreditDetail/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tCreditDetail/index.ts new file mode 100644 index 0000000..a5fa756 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tCreditDetail/index.ts @@ -0,0 +1,29 @@ +import { requestClient } from '#/api/request'; + +// 获取信用额度明细表列表 +export function List(params:any) { + return requestClient.get('common/tCreditDetail/list', { params }); +} + +// 删除/批量删除信用额度明细表 +export function Delete(params:any) { + return requestClient.post('common/tCreditDetail/delete', { ...params }); +} + +// 添加/编辑信用额度明细表 +export function Edit(params:any) { + return requestClient.post('common/tCreditDetail/edit', { ...params }); +} + +// 获取信用额度明细表指定详情 +export function View(params:any) { + return requestClient.get('common/tCreditDetail/view', { params }); +} + +// 导出信用额度明细表 +export function Export(params:any) { + return requestClient.post('/common/tCreditDetail/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tFinCommissionDetail/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tFinCommissionDetail/index.ts new file mode 100644 index 0000000..295540b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tFinCommissionDetail/index.ts @@ -0,0 +1,49 @@ +import { requestClient } from '#/api/request'; + +// 获取分润明细表列表 +export function List(params: any) { + return requestClient.get('common/tFinCommissionDetail/list', { params }); +} + +// 删除/批量删除分润明细表 +export function Delete(params: any) { + return requestClient.post('common/tFinCommissionDetail/delete', { ...params }); +} + +// 添加/编辑分润明细表 +export function Edit(params: any) { + return requestClient.post('common/tFinCommissionDetail/edit', { ...params }); +} + +// 获取分润明细表指定详情 +export function View(params: any) { + return requestClient.get('common/tFinCommissionDetail/view', { params }); +} + +// 获取分层分润概览 +export function GetCommissionOverview(params: any) { + return requestClient.get( + 'common/tFinCommissionDetail/getCommissionOverview', + { params }, + ); +} + +// 获取层级汇总表 +export function GetLevelSummary(params: any) { + return requestClient.get( + 'common/tFinCommissionDetail/getLevelSummary', + { params }, + ); +} + +// 导出分润明细表 +export function Export(params: any) { + return requestClient.post( + '/common/tFinCommissionDetail/export', + { ...params }, + { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tFinWithdrawableChange/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tFinWithdrawableChange/index.ts new file mode 100644 index 0000000..75f4be1 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tFinWithdrawableChange/index.ts @@ -0,0 +1,29 @@ +import { requestClient } from '#/api/request'; + +// 获取可提现变动明细表列表 +export function List(params:any) { + return requestClient.get('common/tFinWithdrawableChange/list', { params }); +} + +// 删除/批量删除可提现变动明细表 +export function Delete(params:any) { + return requestClient.post('common/tFinWithdrawableChange/delete', { ...params }); +} + +// 添加/编辑可提现变动明细表 +export function Edit(params:any) { + return requestClient.post('common/tFinWithdrawableChange/edit', { ...params }); +} + +// 获取可提现变动明细表指定详情 +export function View(params:any) { + return requestClient.get('common/tFinWithdrawableChange/view', { params }); +} + +// 导出可提现变动明细表 +export function Export(params:any) { + return requestClient.post('/common/tFinWithdrawableChange/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tFinanceApply/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tFinanceApply/index.ts new file mode 100644 index 0000000..030f58f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tFinanceApply/index.ts @@ -0,0 +1,38 @@ +import { requestClient } from '#/api/request'; + +// 获取财务申请表列表 +export function List(params:any) { + return requestClient.get('common/tFinanceApply/list', { params }); +} + +// 删除/批量删除财务申请表 +export function Delete(params:any) { + return requestClient.post('common/tFinanceApply/delete', { ...params }); +} + +// 添加/编辑财务申请表 +export function Edit(params:any) { + return requestClient.post('common/tFinanceApply/edit', { ...params }); +} + +// 获取财务申请表指定详情 +export function View(params:any) { + return requestClient.get('common/tFinanceApply/view', { params }); +} + +// 导出财务申请表 +export function Export(params:any) { + return requestClient.post('/common/tFinanceApply/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} + +// 审核余额转可提现申请 +export function BalanceTransferAudit(params: { + applyNo: string; + auditResult: number; + auditOpinion?: string; +}) { + return requestClient.post('common/tAgentBalance/balanceTransferAudit', params); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tFinanceAuditRecord/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tFinanceAuditRecord/index.ts new file mode 100644 index 0000000..8fe376b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tFinanceAuditRecord/index.ts @@ -0,0 +1,29 @@ +import { requestClient } from '#/api/request'; + +// 获取财务审核记录表列表 +export function List(params:any) { + return requestClient.get('common/tFinanceAuditRecord/list', { params }); +} + +// 删除/批量删除财务审核记录表 +export function Delete(params:any) { + return requestClient.post('common/tFinanceAuditRecord/delete', { ...params }); +} + +// 添加/编辑财务审核记录表 +export function Edit(params:any) { + return requestClient.post('common/tFinanceAuditRecord/edit', { ...params }); +} + +// 获取财务审核记录表指定详情 +export function View(params:any) { + return requestClient.get('common/tFinanceAuditRecord/view', { params }); +} + +// 导出财务审核记录表 +export function Export(params:any) { + return requestClient.post('/common/tFinanceAuditRecord/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tMessageLog/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tMessageLog/index.ts new file mode 100644 index 0000000..467075f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tMessageLog/index.ts @@ -0,0 +1,63 @@ +import { requestClient } from '#/api/request'; + +// 获取消息日志列表 +export function List(params:any) { + return requestClient.get('common/tMessageLog/list', { params }); +} + +// 删除/批量删除消息日志 +export function Delete(params:any) { + return requestClient.post('common/tMessageLog/delete', { ...params }); +} + +// 添加/编辑消息日志 +export function Edit(params:any) { + return requestClient.post('common/tMessageLog/edit', { ...params }); +} + +// 获取消息日志指定详情 +export function View(params:any) { + return requestClient.get('common/tMessageLog/view', { params }); +} + +// 导出消息日志 +export function Export(params:any) { + return requestClient.post('/common/tMessageLog/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} + +// 未读消息通知(右上角消息提醒) +export interface TMessageLogUnreadItem { + messageLogId: number; + messageType: number; + sendUserType: number; + messageTitle: string; + messageContent: string; + messageLink: string; + sendTime: string; + isRead: number; +} + +export interface TMessageLogUnreadResult { + items: TMessageLogUnreadItem[]; + total: number; +} + +// 获取当前登录用户未读消息通知(右上角消息提醒) +export function UnreadList(params?: { limit?: number }) { + return requestClient.get('common/tMessageLog/unreadList', { + params, + }); +} + +// 标记当前登录用户指定消息已读 +export function Read(params: { messageLogId: number | string }) { + return requestClient.post('common/tMessageLog/read', { ...params }); +} + +// 标记当前登录用户全部消息已读 +export function ReadAll() { + return requestClient.post('common/tMessageLog/readAll', {}); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tNotifyLog/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tNotifyLog/index.ts new file mode 100644 index 0000000..857001e --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tNotifyLog/index.ts @@ -0,0 +1,29 @@ +import { requestClient } from '#/api/request'; + +// 获取通知日志列表 +export function List(params:any) { + return requestClient.get('common/tNotifyLog/list', { params }); +} + +// 删除/批量删除通知日志 +export function Delete(params:any) { + return requestClient.post('common/tNotifyLog/delete', { ...params }); +} + +// 添加/编辑通知日志 +export function Edit(params:any) { + return requestClient.post('common/tNotifyLog/edit', { ...params }); +} + +// 获取通知日志指定详情 +export function View(params:any) { + return requestClient.get('common/tNotifyLog/view', { params }); +} + +// 导出通知日志 +export function Export(params:any) { + return requestClient.post('/common/tNotifyLog/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tProfitAccountMonthBill/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tProfitAccountMonthBill/index.ts new file mode 100644 index 0000000..2bbcd5e --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tProfitAccountMonthBill/index.ts @@ -0,0 +1,63 @@ +import { requestClient } from '#/api/request'; + +// 获取盈利账户月账单表列表 +export function List(params: any) { + return requestClient.get('common/tProfitAccountMonthBill/list', { params }); +} + +// 获取盈利账户月账单汇总 +export function GetProfitBillSummary(params: any) { + return requestClient.get( + 'common/tProfitAccountMonthBill/getProfitBillSummary', + { params }, + ); +} + +// 获取核心财务指标 +export function GetCoreFinancialData(params: any) { + return requestClient.get( + 'common/tProfitAccountMonthBill/getCoreFinancialData', + { params }, + ); +} + +// 获取财务趋势 +export function GetFinancialTrend(params: any) { + return requestClient.get( + 'common/tProfitAccountMonthBill/getFinancialTrend', + { params }, + ); +} + +// 删除/批量删除盈利账户月账单表 +export function Delete(params: any) { + return requestClient.post('common/tProfitAccountMonthBill/delete', { + ...params, + }); +} + +// 添加/编辑盈利账户月账单表 +export function Edit(params: any) { + return requestClient.post('common/tProfitAccountMonthBill/edit', { + ...params, + }); +} + +// 获取盈利账户月账单表指定详情 +export function View(params: any) { + return requestClient.get('common/tProfitAccountMonthBill/view', { + params, + }); +} + +// 导出盈利账户月账单表 +export function Export(params: any) { + return requestClient.post( + '/common/tProfitAccountMonthBill/export', + { ...params }, + { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tWoCommunication/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tWoCommunication/index.ts new file mode 100644 index 0000000..3601433 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tWoCommunication/index.ts @@ -0,0 +1,34 @@ +import { requestClient } from '#/api/request'; + +// 获取工单问题沟通表列表 +export function List(params:any) { + return requestClient.get('/common/tWoCommunication/list', { params }); +} + +// 删除/批量删除工单问题沟通表 +export function Delete(params:any) { + return requestClient.post('common/tWoCommunication/delete', { ...params }); +} + +// 添加/编辑工单问题沟通表 +export function Edit(params:any) { + return requestClient.post('common/tWoCommunication/edit', { ...params }); +} + +// 获取工单问题沟通表指定详情 +export function View(params:any) { + return requestClient.get('common/tWoCommunication/view', { params }); +} + +// 发送工单沟通消息 +export function Message(params:any) { + return requestClient.post('common/tWoCommunication/message', { ...params }); +} + +// 导出工单问题沟通表 +export function Export(params:any) { + return requestClient.post('/common/tWoCommunication/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tWoMain/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tWoMain/index.ts new file mode 100644 index 0000000..2738dec --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tWoMain/index.ts @@ -0,0 +1,54 @@ +import { requestClient } from '#/api/request'; + +// 获取工单主表列表 +export function List(params:any) { + return requestClient.get('common/tWoMain/list', { params }); +} + +// 删除/批量删除工单主表 +export function Delete(params:any) { + return requestClient.post('common/tWoMain/delete', { ...params }); +} + +// 添加/编辑工单主表 +export function Edit(params:any) { + return requestClient.post('common/tWoMain/edit', { ...params }); +} + +// 获取工单主表指定详情 +export function View(params:any) { + return requestClient.get('common/tWoMain/view', { params }); +} + +// 工单转单 +export function Transfer(params:any) { + return requestClient.post('common/tWoMain/transfer', { ...params }); +} + +// 工单完成 +export function Resolve(params:any) { + return requestClient.post('common/tWoMain/resolve', { ...params }); +} + +// 工单取消/关闭 +export function Cancel(params:any) { + return requestClient.post('common/tWoMain/cancel', { ...params }); +} + +// 关闭工单 +export function Close(params:any) { + return requestClient.post('common/tWoMain/close', { ...params }); +} + +// 工单评价 +export function Evaluate(params:any) { + return requestClient.post('common/tWoMain/evaluate', { ...params }); +} + +// 导出工单主表 +export function Export(params:any) { + return requestClient.post('/common/tWoMain/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/common/tWoRecord/index.ts b/admin-ui/vue/apps/web-antd/src/api/common/tWoRecord/index.ts new file mode 100644 index 0000000..ed7cfa8 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/common/tWoRecord/index.ts @@ -0,0 +1,29 @@ +import { requestClient } from '#/api/request'; + +// 获取工单记录表列表 +export function List(params:any) { + return requestClient.get('common/tWoRecord/list', { params }); +} + +// 删除/批量删除工单记录表 +export function Delete(params:any) { + return requestClient.post('common/tWoRecord/delete', { ...params }); +} + +// 添加/编辑工单记录表 +export function Edit(params:any) { + return requestClient.post('common/tWoRecord/edit', { ...params }); +} + +// 获取工单记录表指定详情 +export function View(params:any) { + return requestClient.get('common/tWoRecord/view', { params }); +} + +// 导出工单记录表 +export function Export(params:any) { + return requestClient.post('/common/tWoRecord/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/core/auth.ts b/admin-ui/vue/apps/web-antd/src/api/core/auth.ts new file mode 100644 index 0000000..b15abf2 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/core/auth.ts @@ -0,0 +1,185 @@ +/** + * @description 认证相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { baseRequestClient, requestClient } from '#/api/request'; + +/** + * 登录类型 + * password 密码 + * sms 短信 + * social 第三方oauth + * email 邮箱 + * xcx 小程序 + */ +type GrantType = 'email' | 'password' | 'sms' | 'social' | 'xcx'; + +export namespace AuthApi { + /** 登录接口参数 */ + export interface LoginParams { + password?: string; + username?: string; + } + + /** 登录接口返回值 */ + export interface LoginResult { + accessToken: string; + } + /** 注册接口参数 */ + export interface RegisterParams { + tenantId?: string; + username?: string; + password?: string; + captchaID?: string; + captchaValue?: string; + } + export type RegisterResult = Record; + + export interface RefreshTokenResult { + data: string; + status: number; + } + + export interface BaseLoginParams { + clientId?: string; + grantType: GrantType; + tenantId: string; + } + + export interface OAuthLoginParams extends BaseLoginParams { + socialCode: string; + socialState: string; + source: string; + } +} + +/** + * @param companyName 租户/公司名称 + * @param domain 绑定域名(不带http(s)://) 可选 + * @param tenantId 租户id + */ +export interface TenantOption { + companyName: string; + domain?: string; + tenantId: string; +} + +/** + * @param tenantEnabled 是否启用租户 + * @param voList 租户列表 + */ +export interface TenantResp { + tenantEnabled: boolean; + voList: TenantOption[]; +} + +/** + * 获取用户权限码 + */ +export interface GetAccessCodesResult { + data: string[]; +} + +/** + * 登录 + */ +export async function loginApi(data: AuthApi.LoginParams) { + return requestClient.post('/system/auth/login', data); +} + +/** + * 发送手机验证码登录短信 + */ +export async function sendSmsLoginCodeApi(phone: string) { + return requestClient.post('/system/auth/sms-code', { phone }); +} + +/** + * 手机验证码登录 + */ +export async function smsLoginApi(data: { code: string; phone: string }) { + return requestClient.post( + '/system/auth/sms-login', + data, + ); +} +/** + * 注册register + */ + +export async function registerApi(data: AuthApi.RegisterParams) { + return requestClient.post( + '/system/user/register', + data, + ); +} + +/** + * 刷新accessToken + */ +export async function refreshTokenApi() { + return baseRequestClient.post( + '/system/auth/refresh', + undefined, + { + withCredentials: true, + }, + ); +} + +/** + * 退出登录 + */ +export async function logoutApi() { + return requestClient.post('/system/auth/logout', undefined, { + withCredentials: true, + }); +} + +/** + * 获取用户权限码 + */ +export async function getAccessCodesApi() { + return requestClient.get('/system/auth/codes'); +} + +/** + * 绑定第三方账号 + * @param source 绑定的来源 + * @returns 跳转url + */ +export function authBinding(source: string, tenantId: string) { + return requestClient.get(`/auth/binding/${source}`, { + params: { + domain: window.location.host, + tenantId, + }, + }); +} + +/** + * 取消绑定 + * @param id id + */ +export function authUnbinding(id: string) { + return requestClient.delete(`/auth/unlock/${id}`); +} + +/** + * oauth授权回调 + * @param data oauth授权 + * @returns void + */ +export function authCallback(data: AuthApi.OAuthLoginParams) { + return requestClient.post('/auth/social/callback', data); +} + +// 获取租户列表 +export function tenantList() { + return requestClient.get('/system/auth/getTenantList'); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/core/captcha.ts b/admin-ui/vue/apps/web-antd/src/api/core/captcha.ts new file mode 100644 index 0000000..bead42e --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/core/captcha.ts @@ -0,0 +1,21 @@ +/** + * @description 验证码相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export namespace CaptchaApi { + export interface GetCaptchaResult { + captchaID: string; + captchaImage: string; + } +} + +export async function getCaptchaApi() { + return requestClient.get('/system/captcha'); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/core/index.ts b/admin-ui/vue/apps/web-antd/src/api/core/index.ts new file mode 100644 index 0000000..fdb5dfe --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/core/index.ts @@ -0,0 +1,14 @@ +/** + * @description 核心模块接口导出 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +export * from './auth'; +export * from './menu'; +export * from './user'; +export * from './captcha'; +export * from './upload'; diff --git a/admin-ui/vue/apps/web-antd/src/api/core/menu.ts b/admin-ui/vue/apps/web-antd/src/api/core/menu.ts new file mode 100644 index 0000000..ac62587 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/core/menu.ts @@ -0,0 +1,20 @@ +/** + * @description 菜单相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import type { RouteRecordStringComponent } from '@vben/types'; + +import { requestClient } from '#/api/request'; + +/** + * 获取用户所有菜单 + */ +export async function getAllMenusApi() { + return requestClient.get('/system/menu/all'); +} + diff --git a/admin-ui/vue/apps/web-antd/src/api/core/upload.ts b/admin-ui/vue/apps/web-antd/src/api/core/upload.ts new file mode 100644 index 0000000..0684294 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/core/upload.ts @@ -0,0 +1,57 @@ +/** + * @description 文件上传相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import type { AxiosRequestConfig } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +/** + * Axios上传进度事件 + */ +export type AxiosProgressEvent = AxiosRequestConfig['onUploadProgress']; + +/** + * 通过单文件上传接口 + * @param file 上传的文件 + * @param onUploadProgress 上传进度事件 非必传 + * @param isDevice 不知道这是什么,但是不敢动 + * @param newFileType 新文件类型 1:用户文件 2:用户图片 3:设备文件 4:iot配置图片 5:iot固件文件 6:项目图片 7:项目文件 + * @param subDirName 文件父目录 + * @param params 额外上传参数 + * @returns 上传结果 + */ +export function uploadApi( + file: Blob | File, + onUploadProgress?: AxiosProgressEvent, + isDevice?: boolean | undefined, + newFileType?: number, + subDirName?: string, + params?: Record, +) { + return requestClient.upload( + '/common/oss/upload', + { + ...params, + file, + fileType: 'file', + ...(isDevice ? { isDevice } : {}), + ...(newFileType ? { newFileType } : {}), + ...(subDirName ? { subDirName } : {}), + }, + { onUploadProgress, timeout: 60_000 }, + ); +} +/** + * 默认上传结果 + */ +export interface UploadResult { + url: string; + fileName: string; + ossId: string; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/core/user.ts b/admin-ui/vue/apps/web-antd/src/api/core/user.ts new file mode 100644 index 0000000..6b98722 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/core/user.ts @@ -0,0 +1,20 @@ +/** + * @description 用户信息相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import type { UserInfo } from '@vben/types'; + +import { requestClient } from '#/api/request'; + +/** + * 获取用户信息 + */ +export async function getUserInfoApi() { + return requestClient.get('/system/user/info'); +} + diff --git a/admin-ui/vue/apps/web-antd/src/api/gen/testCategory/index.ts b/admin-ui/vue/apps/web-antd/src/api/gen/testCategory/index.ts new file mode 100644 index 0000000..4d2c380 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/gen/testCategory/index.ts @@ -0,0 +1,39 @@ +import { requestClient } from '#/api/request'; + +// 获取测试分类列表 +export function List(params:any) { + return requestClient.get('gen/testCategory/list', { params }); +} + +// 删除/批量删除测试分类 +export function Delete(params:any) { + return requestClient.post('gen/testCategory/delete', { ...params }); +} + +// 添加/编辑测试分类 +export function Edit(params:any) { + return requestClient.post('gen/testCategory/edit', { ...params }); +} + +// 修改测试分类状态 +export function Status(params:any) { + return requestClient.post('gen/testCategory/status', { ...params }); +} + +// 获取测试分类指定详情 +export function View(params:any) { + return requestClient.get('gen/testCategory/view', { params }); +} + +// 获取测试分类最大排序 +export function MaxSort(params:any) { + return requestClient.get('gen/testCategory/maxSort', { params }); +} + +// 导出测试分类 +export function Export(params:any) { + return requestClient.post('/gen/testCategory/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/gen/testDemo/index.ts b/admin-ui/vue/apps/web-antd/src/api/gen/testDemo/index.ts new file mode 100644 index 0000000..ac15492 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/gen/testDemo/index.ts @@ -0,0 +1,38 @@ +/** + * @description 测试单表相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +// 获取测试单表列表 +export function List(params:any) { + return requestClient.get('gen/testDemo/list', { params }); +} + +// 删除/批量删除测试单表 +export function Delete(params:any) { + return requestClient.post('gen/testDemo/delete', { ...params }); +} + +// 添加/编辑测试单表 +export function Edit(params:any) { + return requestClient.post('gen/testDemo/edit', { ...params }); +} + +// 获取测试单表指定详情 +export function View(params:any) { + return requestClient.get('gen/testDemo/view', { params }); +} + +// 导出测试单表 +export function Export(params:any) { + return requestClient.post('/gen/testDemo/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/gen_codes/gen_table.ts b/admin-ui/vue/apps/web-antd/src/api/gen_codes/gen_table.ts new file mode 100644 index 0000000..c898490 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/gen_codes/gen_table.ts @@ -0,0 +1,325 @@ +/** + * @description 代码生成器表格相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; +import type { DictOption } from '#/store/dict'; + +export interface SysGenTableListReq { + page: number; + pageSize: number; + genType: number; + varName: string; + status: string; +} +export interface SysGenTableListModel { + tableId: number; // 生成ID + genType: number; // 生成类型 + genTemplate: number; // 生成模板 + varName: string; // 实体命名 + options: string; // 配置选项 + dbName: string; // 数据库名称 + tableName: string; // 主表名称 + tableComment: string; // 主表注释 + daoName: string; // 主表dao模型 + masterColumns: string; // 主表字段 + addonName: string; // 插件名称 + status: string; // 生成状态(0成功 + createdDept: number; // 创建组织 + createdBy: number; // 创建者 + createdAt: string; // 创建时间 +} +export interface SysGenTableListRes { + items: SysGenTableListModel[]; + total: number; +} + +export async function getSysGenTableListApi(params: SysGenTableListReq) { + return requestClient.get('/genCodes/genTable/list', { params }); +} + + +export interface SysGenTableAddReq { + genType: number; + genTemplate: number; + varName: string; + options: string; + dbName: string; + tableName: string; + tableComment: string; + daoName: string; + masterColumns: string; + addonName: string; +} +export interface SysGenTableAddRes { + tableId: number; +} +export interface SysGenTableEditReq { + tableId: number; + genType?: number; + genTemplate?: number; + varName?: string; + options?: any; + dbName?: string; + tableName?: string; + tableComment?: string; + daoName?: string; + masterColumns?: any; + addonName?: string; +} + +export interface SysGenTableEditRes { + tableId: number; +} + +export interface SysGenTableDeleteReq { + tableIds: number[]; +} +export interface SysGenTableDeleteRes { + tableIds: number[]; +} +export interface SysGenTableJoinModel { + uuid: string; + dbName: string; + masterTableName: string; + linkTable: string; + alias: string; + linkMode: number; + field: string; + masterField: string; + daoName: string; + columns: GenCodesColumn[]; +} + +export interface SysGenTableTreeModel { + titleColumn: string; + styleType: number; +} +export interface SysGenTableMenuModel { + icon: string; + pid: number; + sort: number; +} +export interface SysGenTableFuncDictModel { + valueColumn: string|null ; + labelColumn: string|null; +} +export interface SysGenTablePresetStepModel { + formGridCols: number; +} +export interface SysGenTableOptionsModel { + headOps?: string[]; + columnOps?: string[]; + autoOps?: string[]; + join?:any[]; + menu?:SysGenTableMenuModel; + funcDict?: SysGenTableFuncDictModel; + presetStep?:SysGenTablePresetStepModel; + tree?:SysGenTableTreeModel; +} + +export interface SysGenTableViewReq { + tableId: number; +} + + +export interface SysGenTableViewRes { + tableId: number; + genType: number; + genTemplate: number; + varName: string; + options: SysGenTableOptionsModel|string; + dbName: string; + tableName: string; + tableComment: string; + daoName: string; + masterColumns: GenCodesColumn[]|string; + addonName: string; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; +} + +export async function addSysGenTableApi(params: SysGenTableAddReq | { + [x: string]: any; +}) { + return requestClient.post('/genCodes/genTable/add', { ...params }); +} + + +export async function deleteSysGenTableApi(params: SysGenTableDeleteReq) { + return requestClient.post('/genCodes/genTable/delete', { ...params }); +} + +export async function editSysGenTableApi(params: SysGenTableEditReq) { + return requestClient.post('/genCodes/genTable/edit', { ...params }); +} + +export async function getSysGenTableViewApi(params: SysGenTableViewReq) { + return requestClient.get('/genCodes/genTable/view', { params }); +} + + +export interface SelectItemModel { + value: string|number; + label: string; + name: string; + disabled?: boolean; +} + +export interface SelectGenTypeModel extends SelectItemModel,DictOption { + templates: SelectGenTemplateModel[]; +} + +export interface SelectGenTemplateModel extends SelectItemModel { + isAddon: boolean; +} + +export interface GenCodesSelect { + genType: SelectGenTypeModel[]; + db: SelectItemModel[]; + status: SelectItemModel[]; + linkMode: SelectItemModel[]; + buildMethod: SelectItemModel[]; + formMode: SelectItemModel[]; + formRole: SelectItemModel[]; + whereMode: SelectItemModel[]; + addons: SelectItemModel[]; + tableAlign: SelectItemModel[]; + treeStyleType: SelectItemModel[]; + dictMode: SelectItemModel[]; +} + + +export interface GenCodesSelectsReq { +} + +export interface GenCodesSelectsRes extends GenCodesSelect { + +} + +export async function getGenCodesSelectsApi(params: GenCodesSelectsReq) { + return requestClient.get('/genCodes/genTable/selects', { params }); +} + +export interface DbTableSelectModel { + value: string; + label: string; + name: string; + daoName: string; + defVarName: string; + defAlias: string; + defTableComment: string; +} +export interface GenCodesTableSelectReq { + dbGroup: string; +} + +export interface GenCodesTableSelectRes { + items: DbTableSelectModel[]; +} + +export async function getGenCodesTableSelectApi(params: GenCodesTableSelectReq) { + return requestClient.get('/genCodes/genTable/tableSelect', { params }); +} + +export interface DbColumnSelectModel { + value: string; + label: string; + name: string; +} + +export interface GenCodesColumnSelectReq { + dbGroup: string; + tableName: string; +} +export interface GenCodesColumnSelectRes { + items: DbColumnSelectModel[]; +} + +export async function getGenCodesColumnSelectApi(params: GenCodesColumnSelectReq) { + return requestClient.get('/genCodes/genTable/columnSelect', { params }); +} + +export interface GenCodesColumn { + id: number; + name: string; + dc: string; + dataType: string; + sqlType: string; + length: number; + isAllowNull: boolean; + defaultValue: any; + index: string; + extra: string; + goName: string; + goType: string; + tsName: string; + tsType: string; + isList: boolean; + isExport: boolean; + isSort: boolean; + isQuery: boolean; + queryWhere: string; + isEdit: boolean; + required: boolean; + unique: boolean; + formMode: string; + formRole: string; + formGridSpan: number; + dictType: number; + align: string; + width: number; +} +export interface GenCodesColumnListModel extends GenCodesColumn { + +} + +export interface GenCodesColumnListParam { + dbGroup: string; + tableName: string; + isLink: number; + alias: string; +} +export interface GenCodesColumnListRes { + items: GenCodesColumnListModel[]; +} + +export async function getGenCodesColumnListApi(params: GenCodesColumnListParam) { + return requestClient.get('/genCodes/genTable/columnList', { params }); +} + +export interface GenCodesPreviewReq extends SysGenTableListModel { + +} +export interface GenFile { + content: string; + path: string; + meth: number; + required: boolean; +} +export interface GenCodesPreviewRes { + views: Record; + config?: any; +} + +export async function postGenCodesPreviewApi(params: GenCodesPreviewReq) { + return requestClient.post('/genCodes/genTable/preview', { ...params }); +} + +export interface GenCodesBuildReq extends GenCodesPreviewReq { + +} +export interface GenCodesBuildRes { + +} + +export async function postGenCodesBuildApi(params: GenCodesBuildReq) { + return requestClient.post('/genCodes/genTable/build', { ...params }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/index.ts b/admin-ui/vue/apps/web-antd/src/api/index.ts new file mode 100644 index 0000000..e826da0 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/index.ts @@ -0,0 +1,11 @@ +/** + * @description API接口统一导出 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +export * from './core'; +export * from './system'; \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tApi/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tApi/index.ts new file mode 100644 index 0000000..96f976c --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tApi/index.ts @@ -0,0 +1,47 @@ +import type { + TApiDeleteParam, + TApiEditParam, + TApiExportParam, + TApiListParam, + TApiListRes, + TApiViewParam, + TApiViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取API集成列表 +export function List(params: TApiListParam) { + return requestClient.get('agent/tApi/list', { params }); +} + +// 删除/批量删除API集成 +export function Delete(params: TApiDeleteParam) { + return requestClient.post('agent/tApi/delete', { ...params }); +} + +// 添加/编辑API集成 +export function Edit(params: TApiEditParam) { + return requestClient.post('agent/tApi/edit', { ...params }); +} + +// 获取API集成指定详情 +export function View(params: TApiViewParam) { + return requestClient.get('agent/tApi/view', { + params, + }); +} + +// 导出API集成 +export function Export(params: TApiExportParam) { + return requestClient.post( + '/agent/tApi/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tApi/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tApi/type.ts new file mode 100644 index 0000000..71c57dc --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tApi/type.ts @@ -0,0 +1,105 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** API集成列表项 */ +export interface TApiModel { + /** ID */ + id: number; + /** APPKey */ + appKey: string; + /** APPSecret */ + appSecret: string; + /** API分组 */ + groupId: number; + /** 限流周期(秒,0:不限流) */ + rateLimitPeriod: number; + /** 限流次数 */ + rateLimitCount: number; + /** 所属机构 */ + deptId: number; + /** 客户编号 */ + deptKey: string; + /** 客户名称 */ + deptName: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取API集成列表 请求参数 */ +export interface TApiListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** ID */ + id?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取API集成列表 响应 */ +export type TApiListRes = GlobalListRes; + +/** 导出API集成列表 请求参数 */ +export type TApiExportParam = TApiListParam; + +/** 修改/新增API集成 请求参数 */ +export interface TApiEditParam { + /** ID */ + id?: number; + /** APPKey */ + appKey?: string; + /** APPSecret */ + appSecret?: string; + /** API分组 */ + groupId?: number; + /** 限流周期(秒,0:不限流) */ + rateLimitPeriod?: number; + /** 限流次数 */ + rateLimitCount?: number; + /** 所属机构 */ + deptId?: number; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取API集成指定信息 请求参数 */ +export interface TApiViewParam { + /** APPKey */ + appKey: string; +} + +/** 获取API集成指定信息 响应 */ +export type TApiViewRes = TApiModel; + +/** 删除API集成 请求参数 */ +export interface TApiDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/index.ts new file mode 100644 index 0000000..9f03fb3 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/index.ts @@ -0,0 +1,53 @@ +import type { + TSimChannelTemplateDeleteParam, + TSimChannelTemplateEditParam, + TSimChannelTemplateExportParam, + TSimChannelTemplateListParam, + TSimChannelTemplateListRes, + TSimChannelTemplateViewParam, + TSimChannelTemplateViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取通道模板列表 +export function List(params: TSimChannelTemplateListParam) { + return requestClient.get( + 'iot/tSimChannelTemplate/list', + { params }, + ); +} + +// 删除/批量删除通道模板 +export function Delete(params: TSimChannelTemplateDeleteParam) { + return requestClient.post('iot/tSimChannelTemplate/delete', { ...params }); +} + +// 添加/编辑通道模板 +export function Edit(params: TSimChannelTemplateEditParam) { + return requestClient.post('iot/tSimChannelTemplate/edit', { ...params }); +} + +// 获取通道模板指定详情 +export function View(params: TSimChannelTemplateViewParam) { + return requestClient.get( + 'iot/tSimChannelTemplate/view', + { + params, + }, + ); +} + +// 导出通道模板 +export function Export(params: TSimChannelTemplateExportParam) { + return requestClient.post( + '/iot/tSimChannelTemplate/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/type.ts new file mode 100644 index 0000000..ed4e4b7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/type.ts @@ -0,0 +1,141 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 通道模板列表项 */ +export interface TSimChannelTemplateModel { + /** ID */ + id: number; + /** 模板标识 */ + tempKey: string; + /** 模板名称 */ + tempName: string; + /** 模板模型 */ + tempModel: string; + /** 模板配置 */ + tempConfig: string; + /** 模板状态(0未启用,1启用) */ + tempStatus: number; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取通道模板指定信息响应项 */ +export interface TSimChannelTemplateViewModel { + /** ID */ + id: number; + /** 模板标识 */ + tempKey: string; + /** 模板名称 */ + tempName: string; + /** 模板模型 */ + tempModel: string; + /** 模板配置 */ + tempConfig: string; + /** 模板状态(0未启用,1启用) */ + tempStatus: number; + /** 备注 */ + remark: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取通道模板列表 请求参数 */ +export interface TSimChannelTemplateListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** ID */ + id?: number; + /** 模板标识 */ + tempKey?: string; + /** 模板名称 */ + tempName?: string; + /** 模板模型 */ + tempModel?: string; + /** 模板状态(0未启用,1启用) */ + tempStatus?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取通道模板列表 响应 */ +export type TSimChannelTemplateListRes = GlobalListRes; + +/** 导出通道模板列表 请求参数 */ +export type TSimChannelTemplateExportParam = TSimChannelTemplateListParam; + +/** 修改/新增通道模板 请求参数 */ +export interface TSimChannelTemplateEditParam { + /** ID */ + id?: number; + /** 模板标识 */ + tempKey?: string; + /** 模板名称 */ + tempName?: string; + /** 模板模型 */ + tempModel?: string; + /** 模板配置 */ + tempConfig?: string; + /** 模板状态(0未启用,1启用) */ + tempStatus?: number; + /** 备注 */ + remark?: string; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取通道模板指定信息 请求参数 */ +export interface TSimChannelTemplateViewParam { + /** ID */ + id: number; +} + +/** 获取通道模板指定信息 响应 */ +export type TSimChannelTemplateViewRes = TSimChannelTemplateViewModel; + +/** 删除通道模板 请求参数 */ +export interface TSimChannelTemplateDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/index.ts new file mode 100644 index 0000000..c425fc9 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/index.ts @@ -0,0 +1,62 @@ +import type { + TSimChannelsDeleteParam, + TSimChannelsEditParam, + TSimChannelsExportParam, + TSimChannelsListParam, + TSimChannelsListRes, + TSimChannelsTestParam, + TSimChannelsTestRes, + TSimChannelsViewParam, + TSimChannelsViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取通道管理列表 +export function List(params: TSimChannelsListParam) { + return requestClient.get('iot/tSimChannels/list', { + params, + }); +} + +// 删除/批量删除通道管理 +export function Delete(params: TSimChannelsDeleteParam) { + return requestClient.post('iot/tSimChannels/delete', { ...params }); +} + +// 添加/编辑通道管理 +export function Edit(params: TSimChannelsEditParam) { + return requestClient.post('iot/tSimChannels/edit', { ...params }); +} + +// 获取通道管理指定详情 +export function View(params: TSimChannelsViewParam) { + return requestClient.get('iot/tSimChannels/view', { + params, + }); +} + +// 导出通道管理 +export function Export(params: TSimChannelsExportParam) { + return requestClient.post( + '/iot/tSimChannels/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} + +export function Test(params: TSimChannelsTestParam) { + return requestClient.post('iot/tSimChannels/test', { + ...params, + }); +} + +/** 刷新通道卡数量统计 */ +export function RefreshCardCount() { + return requestClient.post('iot/tSimChannels/refresh-card-count'); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/type.ts new file mode 100644 index 0000000..2311b9d --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/type.ts @@ -0,0 +1,306 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 通道管理列表项 */ +export interface TSimChannelsModel { + /** 库存卡数量 */ + stockCardCount: number; + /** 卡信息数量 */ + cardInfoCount: number; + /** 销户卡数量 */ + cancellationCardCount: number; + /** ID */ + id: number; + /** 运营商:1移动,2联通,3电信 */ + operator: number; + /** 模板标识 */ + tempKey: string; + /** 是否允许同步:0否 1是 */ + syncEnabled: number; + /** 模板名称 */ + tempName: string; + /** 模板模型,用于识别共享 Token 能力 */ + tempModel?: string; + /** 通道编号 */ + chanKey: string; + /** 通道名称 */ + chanName: string; + /** 通道配置 */ + chanConfig: string; + /** 通道状态(0未启用,1启用) */ + chanStatus: number; + /** 是否开放共享Token(0否,1是) */ + shareEnabled: number; + /** 是否正常(0是,1否) */ + isNormal: null | number; + /** 对接信息 */ + dockingStatus: null | number; + /** 通道别名 */ + chanAlias: string; + /** 通道行政区域代码(省市) */ + regionCode: string; + /** 应用标识 */ + appKey: string; + /** 应用密钥 */ + appSecret: string; + /** 接口调用凭证 */ + accessToken: string; + /** 凭证申请时间 */ + accessTokenCreated: string; + /** 凭证过期时间 */ + accessTokenExpire: string; + /** 刷新凭证 */ + refreshToken: string; + /** 刷新凭证申请时间 */ + refreshTokenCreated: string; + /** 刷新凭证过期时间 */ + refreshTokenExpire: string; + /** 备注 */ + remark: string; + /** 登录账号 */ + loginUser: string; + /** 登录密码 */ + loginPassword: string; + /** 登录地址 */ + loginUrl: string; + /** 登录状态(0未启用,1启用) */ + loginState: number; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取通道管理指定信息响应项 */ +export interface TSimChannelsViewModel { + /** ID */ + id: number; + /** 运营商:1移动,2联通,3电信 */ + operator: number; + /** 模板标识 */ + tempKey: string; + /** 是否允许同步:0否 1是 */ + syncEnabled: number; + /** 模板模型,用于识别共享 Token 能力 */ + tempModel?: string; + /** 通道编号 */ + chanKey: string; + /** 通道名称 */ + chanName: string; + /** 通道配置 */ + chanConfig: string; + /** 通道状态(0启用,1停用) */ + chanStatus: number; + /** 是否开放共享Token(0否,1是) */ + shareEnabled: number; + /** 是否正常(0是,1否) */ + isNormal: null | number; + /** 对接信息 */ + dockingStatus: null | number; + /** 通道别名 */ + chanAlias: string; + /** 通道行政区域代码(省市) */ + regionCode: string; + /** 应用标识 */ + appKey: string; + /** 应用密钥 */ + appSecret: string; + /** 接口调用凭证 */ + accessToken: string; + /** 凭证申请时间 */ + accessTokenCreated: string; + /** 凭证过期时间 */ + accessTokenExpire: string; + /** 刷新凭证 */ + refreshToken: string; + /** 备注 */ + remark: string; + /** 登录账号 */ + loginUser: string; + /** 登录密码 */ + loginPassword: string; + /** 登录地址 */ + loginUrl: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 模板名称 */ + tempName: string; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取通道管理列表 请求参数 */ +export interface TSimChannelsListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** ID */ + id?: number; + /** 运营商:1移动,2联通,3电信 */ + operator?: number; + /** 模板标识 */ + tempKey?: string; + /** 通道编号 */ + chanKey?: string; + /** 通道名称 */ + chanName?: string; + /** 通道别名 */ + chanAlias?: string; + /** 通道状态(0未启用,1启用) */ + chanStatus?: number; + shareEnabled?: number; + isNormal?: number | null; + dockingStatus?: number | null; + syncEnabled?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取通道管理列表 响应 */ +export type TSimChannelsListRes = GlobalListRes; + +/** 导出通道管理列表 请求参数 */ +export type TSimChannelsExportParam = TSimChannelsListParam; + +/** 修改/新增通道管理 请求参数 */ +export interface TSimChannelsEditParam { + /** ID */ + id?: number; + /** 运营商:1移动,2联通,3电信 */ + operator?: number; + /** 模板标识 */ + tempKey?: string; + /** 通道编号 */ + chanKey?: string; + /** 通道名称 */ + chanName?: string; + /** 通道配置 */ + chanConfig?: string; + /** 通道状态(0未启用,1启用) */ + chanStatus?: number; + /** 是否开放共享Token(0否,1是) */ + shareEnabled?: number; + /** 是否正常(0是,1否) */ + isNormal?: null | number; + /** 对接信息 */ + dockingStatus?: null | number; + /** 通道别名 */ + chanAlias?: string; + /** 通道行政区域代码(省市) */ + regionCode?: string; + /** 应用标识 */ + appKey?: string; + /** 应用密钥 */ + appSecret?: string; + /** 接口调用凭证 */ + accessToken?: string; + /** 凭证申请时间 */ + accessTokenCreated?: string; + /** 凭证过期时间 */ + accessTokenExpire?: string; + /** 刷新凭证 */ + refreshToken?: string; + /** 刷新凭证申请时间 */ + refreshTokenCreated?: string; + /** 刷新凭证过期时间 */ + refreshTokenExpire?: string; + /** 备注 */ + remark?: string; + /** 登录账号 */ + loginUser?: string; + /** 登录密码 */ + loginPassword?: string; + /** 登录地址 */ + loginUrl?: string; + /** 登录状态(0未启用,1启用) */ + loginState?: number; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取通道管理指定信息 请求参数 */ +export interface TSimChannelsViewParam { + /** ID */ + id: number; +} + +/** 获取通道管理指定信息 响应 */ +export type TSimChannelsViewRes = TSimChannelsViewModel; + +/** 删除通道管理 请求参数 */ +export interface TSimChannelsDeleteParam { + /** 主键ID */ + id: number | number[]; +} + +/** 通道测试请求参数 */ +export interface TSimChannelsTestParam { + channelId: number; + inputMode: 'complete' | 'direct_single' | 'single'; + cardValueType?: 'iccid' | 'imsi' | 'msisdn'; + cardValue?: string; + iccid?: string; + imsi?: string; + msisdn?: string; + /** 未传时执行全部查询项 */ + items?: string[]; +} + +export type TSimChannelsTestItemStatus = 'failed' | 'success' | 'timeout'; + +/** 单项测试结果 */ +export interface TSimChannelsTestItem { + key: string; + name: string; + status: TSimChannelsTestItemStatus; + durationMs: number; + errorCode?: number; + message?: string; + data?: unknown; + /** 完整通道测试响应 JSON,归属当前单项展示 */ + responseJson?: string; +} + +/** 通道测试响应 */ +export interface TSimChannelsTestRes { + items: TSimChannelsTestItem[]; + /** Unmodified response body from the channel gateway test endpoint. */ + gatewayResponseRaw?: string; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/index.ts new file mode 100644 index 0000000..8fe9809 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/index.ts @@ -0,0 +1,52 @@ +import type { + TSimCardAllocateBatchSubmitParam, + TSimCardAllocateBatchSubmitRes, + TSimCardAllocateExcelSubmitParam, + TSimCardAllocateInputPrepareParam, + TSimCardAllocatePrepareRes, + TSimCardAllocateTarget, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardAllocate/excel/template', { + responseReturn: 'raw', + }); +} + +export function ListTargets(keyword = '') { + return requestClient.get<{ items: TSimCardAllocateTarget[] }>( + '/iot/tSimCardAllocate/targets', + { params: { keyword } }, + ); +} + +export function InputPrepare(params: TSimCardAllocateInputPrepareParam) { + return requestClient.post( + '/iot/tSimCardAllocate/input/prepare', + params, + ); +} + +export function ExcelSubmit(params: TSimCardAllocateExcelSubmitParam) { + const data: Record & { file: File } = { + file: params.file, + remark: params.remark ?? '', + }; + if (params.targetDeptId) { + data.targetDeptId = String(params.targetDeptId); + } + return requestClient.upload( + '/iot/tSimCardAllocate/excel/submit', + data, + { timeout: 10 * 60_000 }, + ); +} + +export function BatchSubmit(params: TSimCardAllocateBatchSubmitParam) { + return requestClient.post( + '/iot/tSimCardAllocate/batch/submit', + params, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/type.ts new file mode 100644 index 0000000..ec0052f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/type.ts @@ -0,0 +1,49 @@ +export interface TSimCardAllocateTarget { + deptId: number; + parentId: number; + deptKey?: string; + deptName: string; + deptCategory?: string; +} + +export interface TSimCardAllocateInputPrepareParam { + input: string; + targetDeptId: number; +} + +export interface TSimCardAllocateExcelSubmitParam { + file: File; + targetDeptId?: number; + remark?: string; +} + +export interface TSimCardAllocateBatchSubmitParam { + batchNo: string; + targetDeptId?: number; + remark?: string; +} + +export interface TSimCardAllocateBatchDetail { + rowNo: number; + itemId: string; + targetDeptId?: number; + targetDeptKey?: string; + targetDeptName?: string; + status: string; + errorReason?: string; +} + +export interface TSimCardAllocatePrepareRes { + batchNo: string; + batchType: number; + batchAsyncStatus?: number; + target?: TSimCardAllocateTarget; + totalCount: number; + validCount: number; + failCount: number; + failReason?: string; + status: string; + details: TSimCardAllocateBatchDetail[]; +} + +export type TSimCardAllocateBatchSubmitRes = TSimCardAllocatePrepareRes; diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/index.ts new file mode 100644 index 0000000..2ebfdd3 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/index.ts @@ -0,0 +1,94 @@ +import type { + TSimAddPackageBatchConfirmParam, + TSimAddPackageBatchConfirmRes, + TSimAddPackageOptionsRes, + TSimAddPackagePrepareResult, + TSimBindPackageAddPackageExcelSubmitParam, + TSimBindPackageAddPackageInputPrepareParam, + TSimBindPackageAddPackageInputPrepareRes, + TSimBindPackageAddPackageInputSubmitParam, + TSimBindPackageAddPackageSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取卡绑定套餐列表 +export function List(params: any) { + return requestClient.get('iot/tSimCardBindPkg/list', { params }); +} + +// 获取卡套餐详情 +export function GetPkgInfo(params: any) { + return requestClient.get('iot/tSimCardBindPkg/getPkgInfo', { params }); +} + +// 获取变更套餐 +export function GetChangePkg(params: any) { + return requestClient.get('iot/tSimCardBindPkg/getChangePkg', { params }); +} + +export function DownloadAddPackageTemplate() { + return requestClient.download( + '/iot/tSimCardBindPkg/addPackage/excel/template', + { + responseReturn: 'raw', + }, + ); +} + +export function AddPackageExcelSubmit( + params: TSimBindPackageAddPackageExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardBindPkg/addPackage/excel/submit', + { + file: params.file, + manualConfirm: params.manualConfirm, + }, + { + timeout: 60_000, + }, + ); +} + +export function AddPackageOptions(params: { + iccids: string[]; +}): Promise { + return requestClient.post('/iot/tSimCardBindPkg/addPackage/options', params); +} + +export function AddPackagePaymentContext(): Promise { + return requestClient.post('/iot/tSimCardBindPkg/addPackage/payment-context'); +} + +export function AddPackageInputSubmit( + params: TSimBindPackageAddPackageInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardBindPkg/addPackage/input/submit', { + ...params, + }); +} + +export function AddPackageInputPrepare( + params: TSimBindPackageAddPackageInputPrepareParam, +): Promise { + return requestClient.post('/iot/tSimCardBindPkg/addPackage/input/prepare', { + ...params, + }); +} + +export function AddPackagePrepareResult( + batchNo: string, +): Promise { + return requestClient.get('/iot/tSimCardBindPkg/addPackage/prepare/result', { + params: { batchNo }, + }); +} + +export function AddPackageBatchConfirm( + params: TSimAddPackageBatchConfirmParam, +): Promise { + return requestClient.post('/iot/tSimCardBindPkg/addPackage/batch/confirm', { + ...params, + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/type.ts new file mode 100644 index 0000000..615fabe --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/type.ts @@ -0,0 +1,119 @@ +export type AddPackageEffectiveMode = 'current_month'; +export type AddPackagePaymentMode = 'balance' | 'offline'; + +export interface TSimBindPackageAddPackageExcelSubmitParam { + file: File; + paymentMode?: AddPackagePaymentMode; + offlineContractCompleted?: boolean; + manualConfirm?: boolean; +} + +export interface TSimBindPackageAddPackageInputSubmitParam { + input: string; + packageCode?: string; + effectiveMode?: AddPackageEffectiveMode | string; + remark?: string; + paymentMode?: AddPackagePaymentMode; + offlineContractCompleted?: boolean; + [property: string]: any; +} + +export interface TSimBindPackageAddPackageInputPrepareParam { + input: string; + packageCode?: string; + effectiveMode?: AddPackageEffectiveMode | string; + remark?: string; + [property: string]: any; +} + +export interface TSimBindPackageAddPackageSubmitRes { + batchAsyncStatus?: number; + batchNo?: string; + batchType?: number; + targetBatchType?: number; + total?: number; + validCount?: number; + failCount?: number; + [property: string]: any; +} + +export type TSimBindPackageAddPackageInputPrepareRes = + TSimAddPackagePrepareResult; + +export interface TSimAddPackageBatchConfirmParam { + batchNo: string; + packageCode?: string; + effectiveMode?: AddPackageEffectiveMode | string; + remark?: string; + paymentMode?: AddPackagePaymentMode | string; + offlineContractCompleted?: boolean; + [property: string]: any; +} + +export interface TSimAddPackageBatchConfirmRes { + batchAsyncStatus?: number; + batchNo?: string; + batchType?: number; + effectiveMode?: AddPackageEffectiveMode | string; + packageCode?: string; + status?: string; + [property: string]: any; +} + +export interface TSimAddPackagePaymentAccount { + payerDeptId: number; + targetCount: number; + requiredAmount: number | string; + availableBalance: number | string; + balanceEnough: boolean; +} + +export interface TSimAddPackageOption { + flowMb: number; + packageCode: string; + packageName: string; + unitPrice?: number | string; + totalAmount?: number | string; + priceAvailable?: boolean; + priceReason?: string; + paymentAccounts?: TSimAddPackagePaymentAccount[]; +} + +export interface TSimAddPackageOptionsRes { + items: TSimAddPackageOption[]; + isTopDept?: boolean; + defaultPaymentMode?: AddPackagePaymentMode | string; + availableBalance?: number | string; +} + +export interface TSimAddPackagePrepareResult { + availableBalance?: number | string; + batchAsyncStatus?: number; + batchInfo?: Record; + batchNo?: string; + batchType?: number; + effectiveMode?: AddPackageEffectiveMode | string; + effectiveModeText?: string; + effectiveTime?: string; + expectedExpireTime?: string; + failCount?: number; + failReason?: string; + flowMb?: number | string; + isTopDept?: boolean; + packageCode?: string; + packageName?: string; + paymentAccounts?: TSimAddPackagePaymentAccount[]; + availablePackages?: TSimAddPackageOption[]; + quantity?: number; + runResult?: number; + snapshot?: Record; + status?: string; + successCount?: number; + targetBatchType?: number; + total?: number; + totalAmount?: number | string; + unitPrice?: number | string; + validCount?: number; + defaultPaymentMode?: AddPackagePaymentMode | string; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/index.ts new file mode 100644 index 0000000..0a92e29 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/index.ts @@ -0,0 +1,31 @@ +import type { + TSimCardCancelExcelSubmitParam, + TSimCardCancelInputSubmitParam, + TSimCardCancelSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardCancel/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardCancelExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardCancel/excel/submit', + { file: params.file }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardCancelInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardCancel/input/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/type.ts new file mode 100644 index 0000000..8579e33 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/type.ts @@ -0,0 +1,39 @@ +/** 提交Excel卡销户请求参数 */ +export interface TSimCardCancelExcelSubmitParam { + /** Excel文件 */ + file: File; +} + +/** 提交批量输入卡销户请求参数 */ +export interface TSimCardCancelInputSubmitParam { + /** 批量输入ICCID文本 */ + input: string; + /** 销户备注 */ + remark?: string; + [property: string]: any; +} + +/** 卡销户提交响应 */ +export interface TSimCardCancelSubmitRes { + /** 批次异步处理状态(Pending 等) */ + batchAsyncStatus?: number; + /** 批次号 */ + batchNo?: string; + /** 批次类型 */ + batchType?: number; + /** 失败行数 */ + failCount?: number; + /** 实际销户数量 */ + quantity?: number; + /** 结果下载任务ID */ + resultDownloadId?: number; + /** 结果文件OSS ID */ + resultFileOssId?: number; + /** 导入状态 */ + status?: string; + /** 解析总行数 */ + total?: number; + /** 校验通过行数 */ + validCount?: number; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.test.ts new file mode 100644 index 0000000..8cf42ec --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.test.ts @@ -0,0 +1,119 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const get = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + get, + post, + upload, + }, +})); + +describe('tSimCardChange api', () => { + beforeEach(() => { + download.mockReset(); + get.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads excel change template from backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith( + '/iot/tSimCardChange/excel/template', + { + responseReturn: 'raw', + }, + ); + }); + + it('submits excel change as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'change.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardChange/excel/submit', + { file }, + { + timeout: 60_000, + }, + ); + }); + + it('prepares input change with backend contract path', async () => { + const { InputPrepare } = await import('./index'); + const params = { + durationMonths: 6, + effectiveMode: 'immediate' as const, + input: '8986000000000000001\n8986000000000000002', + newPackageCode: 'PKG002', + offlineContractCompleted: true, + }; + + InputPrepare(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardChange/input/prepare', { + ...params, + }); + }); + + it('prepares range change with backend contract path', async () => { + const { RangePrepare } = await import('./index'); + const params = { + durationMonths: 6, + effectiveMode: 'next_month' as const, + endIccid: '8986000000000000009', + endImsi: '460000000000009', + endMsisdn: '13000000009', + newPackageCode: 'PKG002', + offlineContractCompleted: true, + startIccid: '8986000000000000001', + startImsi: '460000000000001', + startMsisdn: '13000000001', + }; + + RangePrepare(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardChange/range/prepare', { + ...params, + }); + }); + + it('submits change prepare batch with backend contract path', async () => { + const { BatchSubmit } = await import('./index'); + const params = { + batchNo: 'CH202607060001', + durationMonths: 6, + effectiveMode: 'immediate' as const, + newPackageCode: 'PKG002', + offlineContractCompleted: true, + }; + + BatchSubmit(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardChange/batch/submit', { + ...params, + }); + }); + + it('polls change prepare result with backend contract path', async () => { + const { PrepareResult } = await import('./index'); + const batchNo = 'CH202607060001'; + + PrepareResult(batchNo); + + expect(get).toHaveBeenCalledWith('/iot/tSimCardChange/prepare/result', { + params: { batchNo }, + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.ts new file mode 100644 index 0000000..9d9e1ab --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.ts @@ -0,0 +1,77 @@ +import type { + TSimCardChangeBatchPrepareRes, + TSimCardChangeBatchPrepareResult, + TSimCardChangeBatchSubmitParam, + TSimCardChangeBatchSubmitRes, + TSimCardChangeExcelSubmitParam, + TSimCardChangeExcelSubmitRes, + TSimCardChangeInputPrepareParam, + TSimCardChangeInputOptionsParam, + TSimCardChangeOptionsRes, + TSimCardChangeRangePrepareParam, + TSimCardChangeRangeOptionsParam, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardChange/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardChangeExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardChange/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputOptions(params: TSimCardChangeInputOptionsParam) { + return requestClient.post( + '/iot/tSimCardChange/input/change-options', + params, + ); +} + +export function RangeOptions(params: TSimCardChangeRangeOptionsParam) { + return requestClient.post( + '/iot/tSimCardChange/range/change-options', + params, + ); +} + +export function InputPrepare(params: TSimCardChangeInputPrepareParam) { + return requestClient.post( + '/iot/tSimCardChange/input/prepare', + { ...params }, + ); +} + +export function RangePrepare(params: TSimCardChangeRangePrepareParam) { + return requestClient.post( + '/iot/tSimCardChange/range/prepare', + { ...params }, + ); +} + +export function BatchSubmit(params: TSimCardChangeBatchSubmitParam) { + return requestClient.post( + '/iot/tSimCardChange/batch/submit', + { ...params }, + ); +} + +export function PrepareResult(batchNo: string) { + return requestClient.get( + '/iot/tSimCardChange/prepare/result', + { params: { batchNo } }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/type.ts new file mode 100644 index 0000000..5bd8b42 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/type.ts @@ -0,0 +1,149 @@ +export type TSimCardChangeEffectiveMode = 'immediate' | 'next_month'; + +export interface TSimCardChangeInputPrepareParam { + durationMonths: number; + effectiveMode: TSimCardChangeEffectiveMode; + giftDurationMonths?: number; + input: string; + newPackageCode: string; + offlineContractCompleted: boolean; + [property: string]: any; +} + +export interface TSimCardChangeExcelSubmitParam { + file: File; +} + +export interface TSimCardChangeExcelSubmitRes { + batchNo?: string; + batchType?: number; + resultDownloadId?: number; + resultFileOssId?: number; + status?: string; + [property: string]: any; +} + +export interface TSimCardChangeInputOptionsParam { + input: string; +} + +export interface TSimCardChangeRangeOptionsParam { + endIccid: string; + endImsi: string; + endMsisdn: string; + startIccid: string; + startImsi: string; + startMsisdn: string; +} + +export interface TSimCardChangePackageOption { + changeUnitPrice?: number | string; + flowMb?: number; + packageCode: string; + packageName: string; + packageType?: number; + renewableDurationOptions?: number[]; +} + +export interface TSimCardChangeOptionsRes { + customerAgentId?: number; + customerName?: string; + oldPackageCode?: string; + oldPackageName?: string; + oldPackageType?: number; + packages?: TSimCardChangePackageOption[]; + quantity?: number; +} + +export interface TSimCardChangeBatchPrepareRes { + batchNo: string; + batchType?: number; + agentDefaultPriceId?: number; + changeUnitPrice?: number | string; + customerAgentId?: number; + customerName?: string; + failCount?: number; + newPackageCode?: string; + newPackageFlowMb?: number; + newPackageName?: string; + newPackageType?: number; + oldPackageCode?: string; + oldPackageFlowMb?: number; + oldPackageName?: string; + oldPackageType?: number; + priceSource?: string; + quantity?: number; + renewableDurationOptions?: number[]; + resultDownloadId?: number; + resultFileOssId?: number; + sourceBatchNo?: string; + status?: string; + targetBatchType?: number; + targetPriceId?: number; + total?: number; + validCount?: number; + [property: string]: any; +} + +export interface TSimCardChangeRangePrepareParam { + durationMonths: number; + effectiveMode: TSimCardChangeEffectiveMode; + endIccid: string; + endImsi: string; + endMsisdn: string; + giftDurationMonths?: number; + newPackageCode: string; + offlineContractCompleted: boolean; + startIccid: string; + startImsi: string; + startMsisdn: string; + [property: string]: any; +} + +export interface TSimCardChangeBatchSubmitParam { + adminNote?: string; + batchNo: string; + buyerNote?: string; + durationMonths: number; + effectiveMode: TSimCardChangeEffectiveMode; + giftDurationMonths?: number; + newPackageCode: string; + offlineContractCompleted: boolean; + remark?: string; + [property: string]: any; +} + +export interface TSimCardChangeBatchSubmitRes { + batchNo?: string; + batchType?: number; + changeUnitPrice?: number | string; + customerAgentId?: number; + customerName?: string; + durationMonths?: number; + effectiveMode?: string; + giftDurationMonths?: number; + newPackageCode?: string; + newPackageName?: string; + oldPackageCode?: string; + oldPackageName?: string; + orderSn?: string; + packageBeginTime?: string; + packageEndTime?: string; + quantity?: number; + sourceBatchNo?: string; + status?: string; + totalAmount?: number | string; + [property: string]: any; +} + +export type TSimCardChangeBatchAsyncStatus = number; + +export interface TSimCardChangeBatchPrepareResult { + batchAsyncStatus: TSimCardChangeBatchAsyncStatus; + batchInfo?: TSimCardChangeBatchPrepareRes; + batchNo: string; + failReason?: string; + runResult?: number; + status: string; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.test.ts new file mode 100644 index 0000000..9cbd831 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.test.ts @@ -0,0 +1,56 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardDataCut api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the data cut template from the backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardDataCut/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits an excel data cut batch with the batch threshold', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'dataCut.xlsx'); + + ExcelSubmit({ file, trafficCutoffThreshold: 1024.125 }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardDataCut/excel/submit', + { file, trafficCutoffThreshold: 1024.125 }, + { timeout: 60_000 }, + ); + }); + + it('submits an input data cut batch from the backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000001', + trafficCutoffThreshold: 2048, + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardDataCut/input/submit', params); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.ts new file mode 100644 index 0000000..01058ce --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.ts @@ -0,0 +1,34 @@ +import type { + TSimCardDataCutExcelSubmitParam, + TSimCardDataCutInputSubmitParam, + TSimCardDataCutSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardDataCut/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardDataCutExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardDataCut/excel/submit', + { + file: params.file, + trafficCutoffThreshold: params.trafficCutoffThreshold, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardDataCutInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardDataCut/input/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/type.ts new file mode 100644 index 0000000..aab045f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/type.ts @@ -0,0 +1,16 @@ +export interface TSimCardDataCutExcelSubmitParam { + file: File; + trafficCutoffThreshold: number; +} + +export interface TSimCardDataCutInputSubmitParam { + input: string; + trafficCutoffThreshold: number; +} + +export interface TSimCardDataCutSubmitRes { + batchNo: string; + batchType: number; + batchAsyncStatus: number; + total: number; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.test.ts new file mode 100644 index 0000000..2acc273 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.test.ts @@ -0,0 +1,58 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardDataStart api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the data start template from the backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardDataStart/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits an excel data start batch as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'dataStart.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardDataStart/excel/submit', + { file }, + { timeout: 60_000 }, + ); + }); + + it('submits an input data start batch from the backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000001', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardDataStart/input/submit', + params, + ); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.ts new file mode 100644 index 0000000..4438309 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.ts @@ -0,0 +1,33 @@ +import type { + TSimCardLifecycleExcelSubmitParam, + TSimCardLifecycleInputSubmitParam, + TSimCardLifecycleSubmitRes, +} from '../tSimCardLifecycle/type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardDataStart/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardLifecycleExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardDataStart/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardLifecycleInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardDataStart/input/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.test.ts new file mode 100644 index 0000000..b99aa0b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.test.ts @@ -0,0 +1,58 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardDataStop api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the data stop template from the backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardDataStop/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits an excel data stop batch as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'dataStop.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardDataStop/excel/submit', + { file }, + { timeout: 60_000 }, + ); + }); + + it('submits an input data stop batch from the backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000001 14000000001 460001000000001', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardDataStop/input/submit', + params, + ); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.ts new file mode 100644 index 0000000..062c20f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.ts @@ -0,0 +1,33 @@ +import type { + TSimCardLifecycleExcelSubmitParam, + TSimCardLifecycleInputSubmitParam, + TSimCardLifecycleSubmitRes, +} from '../tSimCardLifecycle/type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardDataStop/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardLifecycleExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardDataStop/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardLifecycleInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardDataStop/input/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.test.ts new file mode 100644 index 0000000..0c6b61d --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.test.ts @@ -0,0 +1,39 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const get = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + get, + }, +})); + +describe('tSimCardInfo session api', () => { + beforeEach(() => { + get.mockReset(); + }); + + it('queries session without showing a global failure message', async () => { + const { QuerySimSession } = await import('./index'); + const params = { iccid: '8986000000000000001' }; + + QuerySimSession(params); + + expect(get).toHaveBeenCalledWith('iot/tSimCardInfo/querySimSession', { + params, + errorMessageMode: 'none', + }); + }); + + it('queries status without showing a global failure message', async () => { + const { QuerySimStatus } = await import('./index'); + const params = { iccid: '8986000000000000001' }; + + QuerySimStatus(params); + + expect(get).toHaveBeenCalledWith('iot/tSimCardInfo/querySimStatus', { + params, + errorMessageMode: 'none', + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts new file mode 100644 index 0000000..71231a1 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts @@ -0,0 +1,76 @@ +import { requestClient } from '#/api/request'; + +// 获取卡信息表列表 +export function List(params: any) { + return requestClient.get('iot/tSimCardInfo/list', { params }); +} + +// 批量号码查询使用 POST,避免较长号码列表超过 URL 长度限制 +export function BatchList(params: any) { + return requestClient.post('iot/tSimCardInfo/list', { ...params }); +} + +// 删除/批量删除卡信息表 +export function Delete(params: any) { + return requestClient.post('iot/tSimCardInfo/delete', { ...params }); +} + +// 添加/编辑卡信息表 +export function Edit(params: any) { + return requestClient.post('iot/tSimCardInfo/edit', { ...params }); +} + +// 获取卡信息表指定详情 +export function View(params: any) { + return requestClient.get('iot/tSimCardInfo/view', { params }); +} + +// 导出卡信息表 +export function Export(params: any) { + return requestClient.post( + '/iot/tSimCardInfo/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} +// 同步单张SIM卡用量 +export function SyncSimCardFlow(params: any) { + return requestClient.post('iot/tSimCardInfo/syncSimCardFlow', { + ...params, + }); +} + +// 同步SIM卡状态 +export function SyncSimCardStatus(params: any) { + return requestClient.post('iot/tSimCardInfo/syncSimCardStatus', { + ...params, + }); +} + +// // 查询SIM卡会话 +// export function QuerySimSession(params: TSimCardInfoQuerySimSessionParam) { +// return requestClient.get( +// 'iot/tSimCardInfo/querySimSession', +// { params }, +// ); +// } +// 查询SIM卡会话 +export function QuerySimSession(params: any) { + return requestClient.get('iot/tSimCardInfo/querySimSession', { + params, + errorMessageMode: 'none', + }); +} + +// 查询SIM卡状态 +export function QuerySimStatus(params: any) { + return requestClient.get('iot/tSimCardInfo/querySimStatus', { + params, + errorMessageMode: 'none', + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/type.ts new file mode 100644 index 0000000..31919b4 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/type.ts @@ -0,0 +1,395 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 卡信息表列表项 */ +export interface TSimCardInfoModel { + /** 主键ID */ + id: number; + /** ICCID */ + iccid: string; + /** MSISDN/卡号 */ + msisdn: string; + /** IMSI */ + imsi: string; + /** IMEI */ + imei: string; + /** 归属地 */ + regionCode: string; + /** 渠道客户ID */ + deptId: number; + /** 渠道客户名称 */ + deptName: string; + /** 当前套餐编号 */ + currentPackageCode: string; + /** 当前套餐名称 */ + packageName: string; + /** 套餐状态:0 无套餐,1待生效,2生效中,3已过期 */ + packageStatus: number; + /** 接入方式:ipv4、ipv6、ipv4_ipv6 */ + accessType: number; + /** 运营商卡状态 枚举 */ + bossCardStatus: number; + /** 卡类型 枚举 */ + cardType: number; + /** 运营商开户日期 */ + bossOpenAt: string; + /** 运营商激活日期 */ + bossActivateAt: string; + /** 是否按运营商激活减去赠送时长方:1是,0否 */ + isBossActivateEnabled: number; + /** 入库批次 */ + inboundBatchNo: string; + /** 出库批次 */ + outboundBatchNo: string; + /** 划拨批次 */ + allocationBatchNo: string; + /** 是否为池卡:1是,0否 */ + isFlowPool: number; + /** 流量池编号 */ + flowPoolCode: string; + /** 当前套餐生效时间 */ + flowPkgBeginAt: string; + /** 套餐赠送结束时间 */ + flowPkgPresentAt: string; + /** 实际赠送结束时间 */ + flowPkgRealPresentAt: string; + /** 当前套餐预计到期时间 */ + flowPkgEndAt: string; + /** 数据服务状态:1启用、0禁用 */ + dataServiceStatus: number; + /** 套餐总流量MB */ + packageTotalFlowMb: number; + /** 已用流量MB */ + usedFlowMb: number; + /** 达量断网配置状态(0未配置 1已开启 2已关闭) */ + trafficCutoffStatus: number; + /** 达量断网阈值 */ + trafficCutoffThreshold: number; + /** 短信服务状态:1启用、0禁用 */ + smsServiceStatus: number; + /** 套餐短信总条数 */ + packageTotalSms: number; + /** 已用短信条数 */ + usedSms: number; + /** 语音服务状态:1启用、0禁用 */ + voiceServiceStatus: number; + /** 套餐语音总分钟数 */ + packageTotalVoice: number; + /** 已用语音分钟数 */ + usedVoice: number; + /** 国漫服务状态:1启用、0禁用 */ + roamServiceStatus: number; + /** 套餐国际流量MB */ + packageTotalRoamFlowMb: number; + /** 已用国际流量MB */ + usedRoamFlowMb: number; + /** 状态最后一次同步时间 */ + statusSyncTime: string; + /** 流量最后一次同步时间 */ + flowSyncTime: string; + /** 短信最后一次同步时间 */ + smsSyncTime: string; + /** 语音最后一次同步时间 */ + voiceSyncTime: string; + /** 国漫最后一次同步时间 */ + roamSyncTime: string; + /** 是否收取附加费:1是,0否 */ + extraFeeEnabled: number; + /** 附加费用倍数 */ + extraFeeMultiple: number; + /** 附加金额 */ + extraFee: number; + /** 通道编号 */ + chanKey: string; + /** 通道名称 */ + chanName: string; + /** 备注 */ + remark: string; + /** 网络类型:4G、5G、NB-IoT */ + netModel: number; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取卡信息表指定信息响应项 */ +export interface TSimCardInfoViewModel { + /** 通道名称 */ + chanName: string; + /** 部门名称 */ + deptName: string; + /** 套餐名称 */ + packageName: string; + /** 剩余流量MB */ + reminFlowMb: number; + /** 主键ID */ + id: number; + /** ICCID */ + iccid: string; + /** MSISDN/卡号 */ + msisdn: string; + /** IMSI */ + imsi: string; + /** IMEI */ + imei: string; + /** 归属地 */ + regionCode: string; + /** 渠道客户ID */ + deptId: number; + /** 当前套餐编号 */ + currentPackageCode: string; + /** 套餐状态:0 无套餐,1待生效,2生效中,3已过期 */ + packageStatus: number; + /** 接入方式:ipv4、ipv6、ipv4_ipv6 */ + accessType: number; + /** 运营商卡状态 枚举 */ + bossCardStatus: number; + /** 卡类型 枚举 */ + cardType: number; + /** 运营商开户日期 */ + bossOpenAt: string; + /** 运营商激活日期 */ + bossActivateAt: string; + /** 是否按运营商激活减去赠送时长方:1是,0否 */ + isBossActivateEnabled: number; + /** 入库批次 */ + inboundBatchNo: string; + /** 出库批次 */ + outboundBatchNo: string; + /** 划拨批次 */ + allocationBatchNo: string; + /** 是否为池卡:1是,0否 */ + isFlowPool: number; + /** 流量池编号 */ + flowPoolCode: string; + /** 当前套餐生效时间 */ + flowPkgBeginAt: string; + /** 套餐赠送结束时间 */ + flowPkgPresentAt: string; + /** 实际赠送结束时间 */ + flowPkgRealPresentAt: string; + /** 当前套餐预计到期时间 */ + flowPkgEndAt: string; + /** 数据服务状态:1启用、0禁用 */ + dataServiceStatus: number; + /** 套餐总流量MB */ + packageTotalFlowMb: number; + /** 已用流量MB */ + usedFlowMb: number; + /** 达量断网配置状态(0未配置 1已开启 2已关闭) */ + trafficCutoffStatus: number; + /** 达量断网阈值 */ + trafficCutoffThreshold: number; + /** 短信服务状态:1启用、0禁用 */ + smsServiceStatus: number; + /** 套餐短信总条数 */ + packageTotalSms: number; + /** 已用短信条数 */ + usedSms: number; + /** 语音服务状态:1启用、0禁用 */ + voiceServiceStatus: number; + /** 套餐语音总分钟数 */ + packageTotalVoice: number; + /** 已用语音分钟数 */ + usedVoice: number; + /** 国漫服务状态:1启用、0禁用 */ + roamServiceStatus: number; + /** 套餐国际流量MB */ + packageTotalRoamFlowMb: number; + /** 已用国际流量MB */ + usedRoamFlowMb: number; + /** 状态最后一次同步时间 */ + statusSyncTime: string; + /** 流量最后一次同步时间 */ + flowSyncTime: string; + /** 短信最后一次同步时间 */ + smsSyncTime: string; + /** 语音最后一次同步时间 */ + voiceSyncTime: string; + /** 国漫最后一次同步时间 */ + roamSyncTime: string; + /** 是否收取附加费:1是,0否 */ + extraFeeEnabled: number; + /** 附加费用倍数 */ + extraFeeMultiple: number; + /** 附加金额 */ + extraFee: number; + /** 通道编号 */ + chanKey: string; + /** 网络类型:4G、5G、NB-IoT */ + netModel: number; + /** 备注 */ + remark: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取卡信息表列表 请求参数 */ +export interface TSimCardInfoListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 运营商卡状态 */ + bossCardStatus?: number; + /** 时间类型 */ + timeType?: number; + /** 时间段 */ + time?: string[]; + /** 查询条件 */ + condition?: string; + /** 起始号段 */ + startNum?: string; + /** 结束号段 */ + endNum?: string; + /** 维度 */ + dimension?: number; + /** 维度状态 */ + dimensionStatus?: string; + /** 维度值 */ + dimensionValue?: string; + /** 排序值 */ + sortValue?: number; + /** 排序类型 */ + sortType?: number; + /** 通道编号 */ + chanKey?: string; + /** 当前套餐编码 */ + currentPackageCode?: string; + /** 卡号 */ + cardValue?: string; + /** 备注 */ + remark?: string; + /** IMEI */ + imei?: string; + /** 渠道客户ID */ + deptId?: number; + /** 主键ID */ + id?: number; + /** ICCID */ + iccid?: string; + /** MSISDN/卡号 */ + msisdn?: string; + /** IMSI */ + imsi?: string; + /** 套餐状态:0 无套餐,1待生效,2生效中,3已过期 */ + packageStatus?: number; + /** 数据服务状态:1启用、0禁用 */ + dataServiceStatus?: number; + /** 短信服务状态:1启用、0禁用 */ + smsServiceStatus?: number; + /** 语音服务状态:1启用、0禁用 */ + voiceServiceStatus?: number; + /** 国漫服务状态:1启用、0禁用 */ + roamServiceStatus?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取卡信息表列表 响应 */ +export type TSimCardInfoListRes = GlobalListRes; + +/** 导出卡信息表列表 请求参数 */ +export type TSimCardInfoExportParam = TSimCardInfoListParam; + +/** 修改/新增卡信息表 请求参数 */ +export interface TSimCardInfoEditParam { + /** 主键ID */ + id?: number; + /** 备注 */ + remark?: string; +} + +/** 获取卡信息表指定信息 请求参数 */ +export interface TSimCardInfoViewParam { + /** 主键ID */ + id?: number; + /** ICCID */ + iccid?: string; + /** MSISDN/卡号 */ + msisdn?: string; +} + +/** 获取卡信息表指定信息 响应 */ +export type TSimCardInfoViewRes = TSimCardInfoViewModel; + +/** 删除卡信息表 请求参数 */ +export interface TSimCardInfoDeleteParam { + /** 主键ID */ + id: number | number[]; +} + +/** 查询SIM卡会话 请求参数 */ +export interface TSimCardInfoQuerySimSessionParam { + /** ICCID */ + iccid: string; +} + +/** 查询SIM卡会话 响应项 */ +export interface TSimCardInfoQuerySimSessionModel { + /** APN */ + apnId: string; + /** 实时IMEI */ + imei?: string; + /** 接入方式 */ + rat: string; + /** IPv4地址 */ + ipv4: string; + /** IPv6地址 */ + ipv6: string; + /** IPv6前缀 */ + ipv6Prefix: string; + /** 在线状态 */ + status: string; + /** 会话创建时间 */ + createTime: string; +} + +/** 查询SIM卡会话 响应 */ +export type TSimCardInfoQuerySimSessionRes = + null | TSimCardInfoQuerySimSessionModel; + +/** 查询SIM卡状态 请求参数 */ +export type TSimCardInfoQuerySimStatusParam = + TSimCardInfoQuerySimSessionParam; + +/** 查询SIM卡状态 响应项 */ +export interface TSimCardInfoQuerySimStatusModel { + /** 卡状态 */ + cardStatus?: number; + /** 最后变更时间 */ + lastChangeDate?: string; +} + +/** 查询SIM卡状态 响应 */ +export type TSimCardInfoQuerySimStatusRes = + null | TSimCardInfoQuerySimStatusModel; diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardLifecycle/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardLifecycle/type.ts new file mode 100644 index 0000000..d0c155b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardLifecycle/type.ts @@ -0,0 +1,20 @@ +export interface TSimCardLifecycleExcelSubmitParam { + /** Excel 文件 */ + file: File; +} + +export interface TSimCardLifecycleInputSubmitParam { + /** 每行填写 ICCID,或 ICCID MSISDN IMSI */ + input: string; +} + +export interface TSimCardLifecycleSubmitRes { + /** 批次编号 */ + batchNo: string; + /** 批次类型 */ + batchType: number; + /** 异步处理状态 */ + batchAsyncStatus: number; + /** 提交总行数 */ + total: number; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/index.ts new file mode 100644 index 0000000..dcb0ebb --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/index.ts @@ -0,0 +1,107 @@ +import type { + ExportColumn, + SimCardQueryExportParam, + SimCardQuerySubmitRes, + SimCardUsageHistoryColumnsRes, + SimCardUsageHistoryDeptOptionsRes, + SimCardUsageHistoryExportParam, +} from './type'; + +import { requestClient } from '#/api/request'; + +/** 卡基础信息查询:下载 Excel 模板 */ +export function DownloadBaseTemplate() { + return requestClient.download('/iot/tSimCardBaseQuery/template', { + responseReturn: 'raw', + }); +} + +/** 卡基础信息查询:可选导出列 */ +export function BaseColumns(): Promise<{ items: ExportColumn[] }> { + return requestClient.get('/iot/tSimCardBaseQuery/columns'); +} + +/** + * 两个导出接口共用的 multipart 组装。 + * 提交字段只在这里维护,避免 BaseExport / UsageExport 各写一份后口径漂移。 + */ +function buildExportForm(params: SimCardQueryExportParam): FormData { + const form = new FormData(); + form.append('mode', params.mode); + form.append('exportColumnsJson', JSON.stringify(params.exportColumns ?? [])); + if (params.batchInput !== undefined) { + form.append('batchInput', params.batchInput); + } + if (params.dimension !== undefined) { + form.append('dimension', params.dimension); + } + if (params.startNum !== undefined) { + form.append('startNum', params.startNum); + } + if (params.endNum !== undefined) { + form.append('endNum', params.endNum); + } + return form; +} + +/** + * 卡基础信息查询:提交导出。 + * 统一走 multipart:Excel 模式带 file,其余模式只带表单字段, + * 保持三个输入方式的请求路径一致。 + */ +export function BaseExport( + params: SimCardQueryExportParam & { file?: File }, +): Promise { + const form = buildExportForm(params); + if (params.file) { + form.append('file', params.file); + } + return requestClient.post('/iot/tSimCardBaseQuery/export', form, { + headers: { 'Content-Type': 'multipart/form-data' }, + timeout: 60_000, + }); +} + +/** 月历史用量查询:下载 Excel 模板 */ +export function DownloadUsageTemplate() { + return requestClient.download('/iot/tSimCardUsageHistory/template', { + responseReturn: 'raw', + }); +} + +/** 月历史用量查询:固定列与近12个月月份清单 */ +export function UsageColumns(): Promise { + return requestClient.get('/iot/tSimCardUsageHistory/columns'); +} + +/** 月历史用量查询:可选公司,展示范围由数据权限决定 */ +export function UsageDeptOptions(): Promise { + return requestClient.get('/iot/tSimCardUsageHistory/deptOptions'); +} + +/** 月历史用量查询:提交导出 */ +export function UsageExport( + params: SimCardUsageHistoryExportParam & { file?: File }, +): Promise { + // deptId 是 dept 模式的必填项,缺省时不能悄悄提交一个没有公司范围的导出请求。 + if (params.mode === 'dept' && !(Number(params.deptId) > 0)) { + return Promise.reject(new Error('按所属公司查询时必须选择具体公司')); + } + const form = buildExportForm(params); + if (params.deptId !== undefined && params.deptId > 0) { + form.append('deptId', String(params.deptId)); + } + if (params.expireStartTime) { + form.append('expireStartTime', params.expireStartTime); + } + if (params.expireEndTime) { + form.append('expireEndTime', params.expireEndTime); + } + if (params.file) { + form.append('file', params.file); + } + return requestClient.post('/iot/tSimCardUsageHistory/export', form, { + headers: { 'Content-Type': 'multipart/form-data' }, + timeout: 60_000, + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/type.ts new file mode 100644 index 0000000..4be8b04 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/type.ts @@ -0,0 +1,55 @@ +export interface ExportColumn { + /** 列表模型字段名,后端按它取值 */ + field: string; + /** 表头文字 */ + label: string; + dictType?: string; +} + +export type QueryMode = 'excel' | 'input' | 'range' | 'dept'; + +export interface SimCardQueryExportParam { + /** 输入方式 */ + mode: QueryMode; + /** 批量输入内容,每行 ICCID 或 ICCID MSISDN IMSI */ + batchInput?: string; + /** 连号维度:iccid / msisdn / imsi */ + dimension?: string; + startNum?: string; + endNum?: string; + /** 导出列,后端只认白名单内的字段 */ + exportColumns?: ExportColumn[]; +} + +export interface SimCardUsageHistoryExportParam extends SimCardQueryExportParam { + /** 所属公司部门ID,mode=dept 时必填 */ + deptId?: number; + /** 到期日期起(含),仅 mode=dept 生效 */ + expireStartTime?: string; + /** 到期日期止(含),仅 mode=dept 生效 */ + expireEndTime?: string; +} + +export interface SimCardQuerySubmitRes { + taskId: number; + taskNo: string; + total: number; +} + +export interface SimCardQueryDeptOption { + deptId: number; + deptName: string; + cardCount: number; + parentId: number; +} + +export interface SimCardUsageHistoryColumnsRes { + items: ExportColumn[]; + months: string[]; +} + +export interface SimCardUsageHistoryDeptOptionsRes { + items: SimCardQueryDeptOption[]; + /** 当前登录用户所属部门,用于公司下拉默认值 */ + currentDeptId: number; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.test.ts new file mode 100644 index 0000000..6114ffc --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.test.ts @@ -0,0 +1,88 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const get = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + get, + post, + upload, + }, +})); + +describe('tSimCardRenew api', () => { + beforeEach(() => { + download.mockReset(); + get.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads excel renew template from backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardRenew/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits excel renew as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'renew.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardRenew/excel/submit', + { file }, + { + timeout: 60_000, + }, + ); + }); + + it('prepares input renew with backend contract path', async () => { + const { InputPrepare } = await import('./index'); + const params = { + input: '8986000000000000001\n8986000000000000002', + }; + + InputPrepare(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardRenew/input/prepare', { + ...params, + }); + }); + + it('confirms renew prepare batch with backend contract path', async () => { + const { BatchConfirm } = await import('./index'); + const params = { + batchNo: 'RN202607060001', + durationMonths: 6, + offlineContractCompleted: true, + }; + + BatchConfirm(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardRenew/batch/confirm', { + ...params, + }); + }); + + it('polls renew prepare result with backend contract path', async () => { + const { PrepareResult } = await import('./index'); + const batchNo = 'RN202607060001'; + + PrepareResult(batchNo); + + expect(get).toHaveBeenCalledWith('/iot/tSimCardRenew/prepare/result', { + params: { batchNo }, + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.ts new file mode 100644 index 0000000..e7a016c --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.ts @@ -0,0 +1,52 @@ +import type { + TSimCardRenewBatchConfirmParam, + TSimCardRenewBatchConfirmRes, + TSimCardRenewBatchPrepareRes, + TSimCardRenewBatchPrepareResult, + TSimCardRenewExcelSubmitParam, + TSimCardRenewExcelSubmitRes, + TSimCardRenewInputPrepareParam, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardRenew/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardRenewExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardRenew/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputPrepare(params: TSimCardRenewInputPrepareParam) { + return requestClient.post( + '/iot/tSimCardRenew/input/prepare', + { ...params }, + ); +} + +export function BatchConfirm(params: TSimCardRenewBatchConfirmParam) { + return requestClient.post( + '/iot/tSimCardRenew/batch/confirm', + { ...params }, + ); +} + +export function PrepareResult(batchNo: string) { + return requestClient.get( + '/iot/tSimCardRenew/prepare/result', + { params: { batchNo } }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/type.ts new file mode 100644 index 0000000..e939fb0 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/type.ts @@ -0,0 +1,127 @@ +export interface TSimCardRenewInputPrepareParam { + input: string; + [property: string]: any; +} + +export interface TSimCardRenewExcelSubmitParam { + file: File; +} + +export interface TSimCardRenewExcelSubmitRes { + batchNo?: string; + batchType?: number; + resultDownloadId?: number; + resultFileOssId?: number; + status?: string; + [property: string]: any; +} + +export interface TSimCardRenewBatchPrepareRes { + agentDefaultPriceId?: number; + batchNo: string; + batchType?: number; + customerAgentId?: number; + customerName?: string; + failCount?: number; + failedItems?: TSimCardRenewPrepareFailedItem[]; + failedItemsTruncated?: boolean; + packageCode?: string; + packageName?: string; + billingMethod?: number; + renewDurationUnit?: 'month' | 'year' | string; + renewDurationUnitText?: string; + durationValue?: number; + durationYears?: number; + giftDurationMonths?: number; + priceSource?: string; + quantity?: number; + renewableDurationOptions?: number[]; + renewBeginDate?: string; + renewBeginDateMax?: string; + renewBeginDateMin?: string; + renewUnitPrice?: number | string; + renewablePackageCodes?: string[]; + renewablePackages?: TSimCardRenewPackageOption[]; + resultDownloadId?: number; + resultFileOssId?: number; + status?: string; + targetPriceId?: number; + total?: number; + validCount?: number; + isTopDept?: boolean; + defaultPaymentMode?: 'balance' | 'offline' | string; + availableBalance?: number | string; + sameRenewBeginDate?: boolean; + [property: string]: any; +} + +export interface TSimCardRenewPrepareFailedItem { + iccid?: string; + reason?: string; +} + +export interface TSimCardRenewPackageOption { + packageCode?: string; + packageName?: string; + renewUnitPrice?: number | string; + renewableDurationOptions?: number[]; +} + +export interface TSimCardRenewBatchConfirmParam { + adminNote?: string; + batchNo: string; + packageCode?: string; + buyerNote?: string; + durationYears?: number; + durationMonths: number; + giftDurationMonths?: number; + offlineContractCompleted: boolean; + paymentMode?: 'balance' | 'offline' | string; + packageBeginTime?: string; + packageEndTime?: string; + renewDate?: string; + remark?: string; + [property: string]: any; +} + +export interface TSimCardRenewBatchConfirmRes { + batchNo: string; + batchType?: number; + billingMethod?: number; + renewDurationUnit?: 'month' | 'year' | string; + renewDurationUnitText?: string; + durationYears?: number; + durationMonths?: number; + giftDurationMonths?: number; + orderSn?: string; + packageCode?: string; + packageName?: string; + paymentMode?: string; + payAmount?: number | string; + payType?: number; + availableBalance?: number | string; + balanceDetailSerialNo?: string; + packageBeginTime?: string; + packageEndTime?: string; + quantity?: number; + renewDate?: string; + renewUnitPrice?: number | string; + status?: string; + totalAmount?: number | string; + prepareChanged?: boolean; + priceChanged?: boolean; + message?: string; + [property: string]: any; +} + +export type TSimCardRenewBatchAsyncStatus = number; + +export interface TSimCardRenewBatchPrepareResult { + batchAsyncStatus: TSimCardRenewBatchAsyncStatus; + batchInfo?: TSimCardRenewBatchPrepareRes; + batchNo: string; + failReason?: string; + runResult?: number; + status: string; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.test.ts new file mode 100644 index 0000000..bd41041 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.test.ts @@ -0,0 +1,61 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardRestart api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the restart template from the backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith( + '/iot/tSimCardRestart/excel/template', + { + responseReturn: 'raw', + }, + ); + }); + + it('submits an excel restart batch as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'restart.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardRestart/excel/submit', + { file }, + { timeout: 60_000 }, + ); + }); + + it('submits an input restart batch from the backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000001 14000000001 460001000000001', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardRestart/input/submit', + params, + ); + }); +}); \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.ts new file mode 100644 index 0000000..aaee594 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.ts @@ -0,0 +1,33 @@ +import type { + TSimCardLifecycleExcelSubmitParam, + TSimCardLifecycleInputSubmitParam, + TSimCardLifecycleSubmitRes, +} from '../tSimCardLifecycle/type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardRestart/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardLifecycleExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardRestart/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardLifecycleInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardRestart/input/submit', params); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.test.ts new file mode 100644 index 0000000..a720347 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.test.ts @@ -0,0 +1,58 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardStart api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the resume template from the backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardStart/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits an excel resume batch as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'resume.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardStart/excel/submit', + { file }, + { timeout: 60_000 }, + ); + }); + + it('submits an input resume batch from the backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000001', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardStart/input/submit', + params, + ); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.ts new file mode 100644 index 0000000..23b0eb5 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.ts @@ -0,0 +1,33 @@ +import type { + TSimCardLifecycleExcelSubmitParam, + TSimCardLifecycleInputSubmitParam, + TSimCardLifecycleSubmitRes, +} from '../tSimCardLifecycle/type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardStart/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardLifecycleExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardStart/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardLifecycleInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardStart/input/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.test.ts new file mode 100644 index 0000000..411a62b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.test.ts @@ -0,0 +1,55 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardStop api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the stop template from the backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardStop/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits an excel stop batch as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'stop.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardStop/excel/submit', + { file }, + { timeout: 60_000 }, + ); + }); + + it('submits an input stop batch from the backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000001 14000000001 460001000000001', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardStop/input/submit', params); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.ts new file mode 100644 index 0000000..a8a5a8d --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.ts @@ -0,0 +1,33 @@ +import type { + TSimCardLifecycleExcelSubmitParam, + TSimCardLifecycleInputSubmitParam, + TSimCardLifecycleSubmitRes, +} from '../tSimCardLifecycle/type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardStop/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardLifecycleExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardStop/excel/submit', + { + file: params.file, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardLifecycleInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardStop/input/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.test.ts new file mode 100644 index 0000000..1f4a578 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.test.ts @@ -0,0 +1,132 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const get = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { download, get, post, upload }, +})); + +describe('tSimCardTrafficCutoff api', () => { + beforeEach(() => { + download.mockReset(); + get.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads the traffic cutoff template', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith( + '/iot/tSimCardTrafficCutoff/excel/template', + { responseReturn: 'raw' }, + ); + }); + + it('submits an excel traffic cutoff batch', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'trafficCutoff.xlsx'); + + ExcelSubmit({ + file, + trafficCutoffCrossMonthHold: 1, + trafficCutoffStatus: 1, + trafficCutoffThreshold: 1024.125, + }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardTrafficCutoff/excel/submit', + { + file, + trafficCutoffCrossMonthHold: 1, + trafficCutoffStatus: 1, + trafficCutoffThreshold: 1024.125, + }, + { timeout: 60_000 }, + ); + }); + + it('submits an input traffic cutoff batch', async () => { + const { InputSubmit } = await import('./index'); + + InputSubmit({ + input: '8986000000000000001', + trafficCutoffCrossMonthHold: 0, + trafficCutoffStatus: 2, + trafficCutoffThreshold: 2048, + }); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardTrafficCutoff/input/submit', + { + input: '8986000000000000001', + trafficCutoffCrossMonthHold: 0, + trafficCutoffStatus: 2, + trafficCutoffThreshold: 2048, + }, + ); + }); + + it('queries configured cards', async () => { + const { List } = await import('./index'); + const params = { page: 1, pageSize: 20, cardValue: '8986' }; + + List(params); + + expect(get).toHaveBeenCalledWith('/iot/tSimCardTrafficCutoff/list', { + params, + }); + }); + + it('exports configured cards', async () => { + const { Export } = await import('./index'); + const params = { + page: 1, + pageSize: 2000, + deptId: 12, + trafficCutoffStatus: 1 as const, + }; + + Export(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardTrafficCutoff/export', + params, + { responseType: 'blob' }, + ); + }); + + it('updates a traffic cutoff configuration', async () => { + const { Edit } = await import('./index'); + const params = { + id: 7, + trafficCutoffCrossMonthHold: 1 as const, + iccid: '8986000000000000001', + trafficCutoffStatus: 1 as const, + trafficCutoffThreshold: 1024.5, + }; + + Edit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardTrafficCutoff/edit', + params, + ); + }); + + it('clears a traffic cutoff configuration', async () => { + const { Delete } = await import('./index'); + + Delete({ id: 7, iccid: '8986000000000000001' }); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardTrafficCutoff/delete', { + id: 7, + iccid: '8986000000000000001', + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.ts new file mode 100644 index 0000000..a2875a1 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.ts @@ -0,0 +1,67 @@ +import type { + TSimCardTrafficCutoffDeleteParam, + TSimCardTrafficCutoffEditParam, + TSimCardTrafficCutoffExcelSubmitParam, + TSimCardTrafficCutoffInputSubmitParam, + TSimCardTrafficCutoffListParam, + TSimCardTrafficCutoffListRes, + TSimCardTrafficCutoffSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardTrafficCutoff/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardTrafficCutoffExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardTrafficCutoff/excel/submit', + { + file: params.file, + trafficCutoffStatus: params.trafficCutoffStatus, + trafficCutoffThreshold: params.trafficCutoffThreshold, + trafficCutoffCrossMonthHold: params.trafficCutoffCrossMonthHold, + }, + { timeout: 60_000 }, + ); +} + +export function InputSubmit( + params: TSimCardTrafficCutoffInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardTrafficCutoff/input/submit', { + input: params.input, + trafficCutoffStatus: params.trafficCutoffStatus, + trafficCutoffThreshold: params.trafficCutoffThreshold, + trafficCutoffCrossMonthHold: params.trafficCutoffCrossMonthHold, + }); +} + +export function List(params: TSimCardTrafficCutoffListParam) { + return requestClient.get( + '/iot/tSimCardTrafficCutoff/list', + { params }, + ); +} + +export function Export(params: TSimCardTrafficCutoffListParam) { + return requestClient.post('/iot/tSimCardTrafficCutoff/export', params, { + responseType: 'blob', + }); +} + +export function Edit(params: TSimCardTrafficCutoffEditParam) { + return requestClient.post('/iot/tSimCardTrafficCutoff/edit', params); +} + +export function Delete(params: TSimCardTrafficCutoffDeleteParam) { + return requestClient.post( + '/iot/tSimCardTrafficCutoff/delete', + params, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts new file mode 100644 index 0000000..b6f4df8 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts @@ -0,0 +1,63 @@ +import type { GlobalListRes } from '#/types/global'; + +export interface TSimCardTrafficCutoffExcelSubmitParam { + trafficCutoffCrossMonthHold: 0 | 1; + file: File; + trafficCutoffStatus: 0 | 1 | 2; + trafficCutoffThreshold: number; +} + +export interface TSimCardTrafficCutoffInputSubmitParam { + trafficCutoffCrossMonthHold: 0 | 1; + input: string; + trafficCutoffStatus: 0 | 1 | 2; + trafficCutoffThreshold: number; +} + +export interface TSimCardTrafficCutoffSubmitRes { + batchNo: string; + batchType: number; + batchAsyncStatus: number; + total: number; +} + +export interface TSimCardTrafficCutoffModel { + trafficCutoffCrossMonthHold: 0 | 1; + id: number; + iccid: string; + msisdn: string; + imsi: string; + imei: string; + chanName?: string; + deptName?: string; + packageName?: string; + bossCardStatus?: number; + trafficCutoffStatus: 1 | 2; + trafficCutoffThreshold: number; +} + +export interface TSimCardTrafficCutoffListParam { + includeUnconfigured?: boolean; + page: number; + pageSize: number; + cardValue?: string; + imei?: string; + deptId?: number | string; + trafficCutoffStatus?: 1 | 2; +} + +export type TSimCardTrafficCutoffListRes = + GlobalListRes; + +export interface TSimCardTrafficCutoffEditParam { + trafficCutoffCrossMonthHold: 0 | 1; + id: number; + iccid: string; + trafficCutoffStatus: 1 | 2; + trafficCutoffThreshold: number; +} + +export interface TSimCardTrafficCutoffDeleteParam { + id: number; + iccid: string; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts new file mode 100644 index 0000000..34fcd20 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts @@ -0,0 +1,126 @@ +import type { TSimCardUnsubSubmitRes } from './type'; + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardUnsub api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads excel unsubscribe template from backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith('/iot/tSimCardUnsub/excel/template', { + responseReturn: 'raw', + }); + }); + + it('submits excel unsubscribe as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'unsubscribe.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardUnsub/excel/submit', + { file }, + { + timeout: 60_000, + }, + ); + }); + + it('submits input unsubscribe from backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + input: '8986000000000000000', + remark: 'unsubscribe remark', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardUnsub/input/submit', + params, + ); + }); + + it('submits range unsubscribe from backend contract path', async () => { + const { RangeSubmit } = await import('./index'); + const params = { + endIccid: '8986000000000000009', + endImsi: '460000000000009', + endMsisdn: '13000000009', + remark: 'unsubscribe remark', + startIccid: '8986000000000000001', + startImsi: '460000000000001', + startMsisdn: '13000000001', + }; + + RangeSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardUnsub/range/submit', + params, + ); + }); + + it('exposes batchAsyncStatus on the submit response type so async Pending is representable', async () => { + const res: TSimCardUnsubSubmitRes = { + batchAsyncStatus: 0, + batchNo: 'B202607210001', + batchType: 1, + }; + + expect(res.batchAsyncStatus).toBe(0); + expect(res.batchNo).toBe('B202607210001'); + }); + + it('keeps excel/input/range submit endpoints pointing at the backend contract paths', async () => { + const { ExcelSubmit, InputSubmit, RangeSubmit } = await import('./index'); + const file = new File(['iccid'], 'unsubscribe.xlsx'); + + ExcelSubmit({ file }); + InputSubmit({ input: '8986000000000000000' }); + RangeSubmit({ + endIccid: '8986000000000000009', + endImsi: '460000000000009', + endMsisdn: '13000000009', + startIccid: '8986000000000000001', + startImsi: '460000000000001', + startMsisdn: '13000000001', + }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardUnsub/excel/submit', + { file }, + { timeout: 60_000 }, + ); + expect(post).toHaveBeenCalledWith('/iot/tSimCardUnsub/input/submit', { + input: '8986000000000000000', + }); + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardUnsub/range/submit', + expect.objectContaining({ + startIccid: '8986000000000000001', + endIccid: '8986000000000000009', + }), + ); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.ts new file mode 100644 index 0000000..85c71e9 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.ts @@ -0,0 +1,38 @@ +import type { + TSimCardUnsubExcelSubmitParam, + TSimCardUnsubInputSubmitParam, + TSimCardUnsubRangeSubmitParam, + TSimCardUnsubSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardUnsub/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit( + params: TSimCardUnsubExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimCardUnsub/excel/submit', + { file: params.file }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimCardUnsubInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardUnsub/input/submit', params); +} + +export function RangeSubmit( + params: TSimCardUnsubRangeSubmitParam, +): Promise { + return requestClient.post('/iot/tSimCardUnsub/range/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/type.ts new file mode 100644 index 0000000..3b8d672 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/type.ts @@ -0,0 +1,58 @@ +/** 提交Excel卡退订请求参数 */ +export interface TSimCardUnsubExcelSubmitParam { + /** Excel文件 */ + file: File; +} + +/** 提交批量输入卡退订请求参数 */ +export interface TSimCardUnsubInputSubmitParam { + /** 批量输入ICCID文本 */ + input: string; + /** 退订备注 */ + remark?: string; + [property: string]: any; +} + +/** 提交连号卡退订请求参数 */ +export interface TSimCardUnsubRangeSubmitParam { + /** 结束ICCID */ + endIccid: string; + /** 结束IMSI */ + endImsi: string; + /** 结束MSISDN */ + endMsisdn: string; + /** 退订备注 */ + remark?: string; + /** 起始ICCID */ + startIccid: string; + /** 起始IMSI */ + startImsi: string; + /** 起始MSISDN */ + startMsisdn: string; + [property: string]: any; +} + +/** 卡退订提交响应 */ +export interface TSimCardUnsubSubmitRes { + /** 批次异步处理状态(Pending 等) */ + batchAsyncStatus?: number; + /** 批次号 */ + batchNo?: string; + /** 批次类型 */ + batchType?: number; + /** 失败行数 */ + failCount?: number; + /** 实际退订数量 */ + quantity?: number; + /** 结果下载任务ID */ + resultDownloadId?: number; + /** 结果文件OSS ID */ + resultFileOssId?: number; + /** 导入状态 */ + status?: string; + /** 解析总行数 */ + total?: number; + /** 校验通过行数 */ + validCount?: number; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/index.ts new file mode 100644 index 0000000..ed0e945 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/index.ts @@ -0,0 +1,96 @@ +import type { + TSimPoolAddPackageBatchConfirmParam, + TSimPoolAddPackageBatchConfirmRes, + TSimPoolAddPackageOptionsRes, + TSimPoolAddPackagePrepareResult, + TSimPoolBindPackageAddPackageExcelSubmitParam, + TSimPoolBindPackageAddPackageInputPrepareParam, + TSimPoolBindPackageAddPackageInputPrepareRes, + TSimPoolBindPackageAddPackageInputSubmitParam, + TSimPoolBindPackageAddPackageSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadAddPackageTemplate() { + return requestClient.download( + '/iot/tSimPoolBindPackage/addPackage/excel/template', + { + responseReturn: 'raw', + }, + ); +} + +export function AddPackageExcelSubmit( + params: TSimPoolBindPackageAddPackageExcelSubmitParam, +): Promise { + return requestClient.upload( + '/iot/tSimPoolBindPackage/addPackage/excel/submit', + { + file: params.file, + manualConfirm: params.manualConfirm, + }, + { + timeout: 60_000, + }, + ); +} + +export function AddPackageOptions(params: { + flowPoolCodes: string[]; +}): Promise { + return requestClient.post( + '/iot/tSimPoolBindPackage/addPackage/options', + params, + ); +} + +export function AddPackagePaymentContext(): Promise { + return requestClient.post( + '/iot/tSimPoolBindPackage/addPackage/payment-context', + ); +} + +export function AddPackageInputSubmit( + params: TSimPoolBindPackageAddPackageInputSubmitParam, +): Promise { + return requestClient.post( + '/iot/tSimPoolBindPackage/addPackage/input/submit', + { + ...params, + }, + ); +} + +export function AddPackageInputPrepare( + params: TSimPoolBindPackageAddPackageInputPrepareParam, +): Promise { + return requestClient.post( + '/iot/tSimPoolBindPackage/addPackage/input/prepare', + { + ...params, + }, + ); +} + +export function AddPackagePrepareResult( + batchNo: string, +): Promise { + return requestClient.get( + '/iot/tSimPoolBindPackage/addPackage/prepare/result', + { + params: { batchNo }, + }, + ); +} + +export function AddPackageBatchConfirm( + params: TSimPoolAddPackageBatchConfirmParam, +): Promise { + return requestClient.post( + '/iot/tSimPoolBindPackage/addPackage/batch/confirm', + { + ...params, + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/type.ts new file mode 100644 index 0000000..de1d563 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/type.ts @@ -0,0 +1,119 @@ +export type AddPackageEffectiveMode = 'current_month'; +export type AddPackagePaymentMode = 'balance' | 'offline'; + +export interface TSimPoolBindPackageAddPackageExcelSubmitParam { + file: File; + paymentMode?: AddPackagePaymentMode; + offlineContractCompleted?: boolean; + manualConfirm?: boolean; +} + +export interface TSimPoolBindPackageAddPackageInputSubmitParam { + input: string; + packageCode?: string; + effectiveMode?: AddPackageEffectiveMode | string; + remark?: string; + paymentMode?: AddPackagePaymentMode; + offlineContractCompleted?: boolean; + [property: string]: any; +} + +export interface TSimPoolBindPackageAddPackageInputPrepareParam { + input: string; + packageCode?: string; + effectiveMode?: AddPackageEffectiveMode | string; + remark?: string; + [property: string]: any; +} + +export interface TSimPoolBindPackageAddPackageSubmitRes { + batchAsyncStatus?: number; + batchNo?: string; + batchType?: number; + targetBatchType?: number; + total?: number; + validCount?: number; + failCount?: number; + [property: string]: any; +} + +export type TSimPoolBindPackageAddPackageInputPrepareRes = + TSimPoolAddPackagePrepareResult; + +export interface TSimPoolAddPackageBatchConfirmParam { + batchNo: string; + packageCode?: string; + effectiveMode?: AddPackageEffectiveMode | string; + remark?: string; + paymentMode?: AddPackagePaymentMode | string; + offlineContractCompleted?: boolean; + [property: string]: any; +} + +export interface TSimPoolAddPackageBatchConfirmRes { + batchAsyncStatus?: number; + batchNo?: string; + batchType?: number; + effectiveMode?: AddPackageEffectiveMode | string; + packageCode?: string; + status?: string; + [property: string]: any; +} + +export interface TSimPoolAddPackagePaymentAccount { + payerDeptId: number; + targetCount: number; + requiredAmount: number | string; + availableBalance: number | string; + balanceEnough: boolean; +} + +export interface TSimPoolAddPackageOption { + flowMb: number; + packageCode: string; + packageName: string; + unitPrice?: number | string; + totalAmount?: number | string; + priceAvailable?: boolean; + priceReason?: string; + paymentAccounts?: TSimPoolAddPackagePaymentAccount[]; +} + +export interface TSimPoolAddPackageOptionsRes { + items: TSimPoolAddPackageOption[]; + isTopDept?: boolean; + defaultPaymentMode?: AddPackagePaymentMode | string; + availableBalance?: number | string; +} + +export interface TSimPoolAddPackagePrepareResult { + availableBalance?: number | string; + batchAsyncStatus?: number; + batchInfo?: Record; + batchNo?: string; + batchType?: number; + effectiveMode?: AddPackageEffectiveMode | string; + effectiveModeText?: string; + effectiveTime?: string; + expectedExpireTime?: string; + failCount?: number; + failReason?: string; + flowMb?: number | string; + isTopDept?: boolean; + packageCode?: string; + packageName?: string; + paymentAccounts?: TSimPoolAddPackagePaymentAccount[]; + availablePackages?: TSimPoolAddPackageOption[]; + quantity?: number; + runResult?: number; + snapshot?: Record; + status?: string; + successCount?: number; + targetBatchType?: number; + total?: number; + totalAmount?: number | string; + unitPrice?: number | string; + validCount?: number; + defaultPaymentMode?: AddPackagePaymentMode | string; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/index.ts new file mode 100644 index 0000000..e3f69a8 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/index.ts @@ -0,0 +1,48 @@ +import type { + TSimWarningConfigEmailCodeParam, + TSimWarningConfigExcelSubmitParam, + TSimWarningConfigInputSubmitParam, + TSimWarningConfigRangeSubmitParam, + TSimWarningConfigSubmitRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function DownloadTemplate(params?: { itemType?: number }) { + return requestClient.download('/iot/tSimWarningConfig/excel/template', { + params, + responseReturn: 'raw', + }); +} + +export function SendEmailCode(params: TSimWarningConfigEmailCodeParam) { + return requestClient.post('/iot/tSimWarningConfig/email/code', params); +} + +export function ExcelSubmit( + params: TSimWarningConfigExcelSubmitParam, +): Promise { + const { file, ...data } = params; + return requestClient.upload( + '/iot/tSimWarningConfig/excel/submit', + { + file, + ...data, + }, + { + timeout: 60_000, + }, + ); +} + +export function InputSubmit( + params: TSimWarningConfigInputSubmitParam, +): Promise { + return requestClient.post('/iot/tSimWarningConfig/input/submit', params); +} + +export function RangeSubmit( + params: TSimWarningConfigRangeSubmitParam, +): Promise { + return requestClient.post('/iot/tSimWarningConfig/range/submit', params); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/type.ts new file mode 100644 index 0000000..0534836 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/type.ts @@ -0,0 +1,47 @@ +export interface TSimWarningConfigCommonParam { + itemType?: number; + warnUnit: number; + firstWarn: number; + secondWarn?: number; + thirdWarn?: number; + warnMethods?: string; + warnPhones?: string; + warnEmails?: string; + warnEmailCode?: string; + autoAction?: number; + isEnabled?: number; + remark?: string; +} + +export interface TSimWarningConfigEmailCodeParam { + captchaId: string; + captchaValue: string; + email: string; +} + +export interface TSimWarningConfigExcelSubmitParam extends TSimWarningConfigCommonParam { + file: File; +} + +export interface TSimWarningConfigInputSubmitParam extends TSimWarningConfigCommonParam { + input: string; +} + +export interface TSimWarningConfigRangeSubmitParam extends TSimWarningConfigCommonParam { + endIccid: string; + endImsi: string; + endMsisdn: string; + startIccid: string; + startImsi: string; + startMsisdn: string; +} + +export interface TSimWarningConfigSubmitRes { + batchAsyncStatus?: number; + batchNo?: string; + batchType?: number; + failCount?: number; + total?: number; + validCount?: number; + [property: string]: any; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tDashboard/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tDashboard/index.ts new file mode 100644 index 0000000..e7189ae --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tDashboard/index.ts @@ -0,0 +1,38 @@ +import type { + CardStatisticsRes, + CardStatusStatisticsRes, + FlowPoolUsageRes, + FlowUsageChartRes, + TopUsageCardsRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取卡片数据统计 +export function CardStatistics() { + return requestClient.get('/home/cardStatistics'); +} + +// 获取卡状态统计 +export function CardStatusStatistics() { + return requestClient.get( + '/home/cardStatusStatistics', + ); +} + +// 获取流量使用图表数据 +export function FlowUsageChart(period: '1m' | '7d') { + return requestClient.get('/home/flowUsageChart', { + params: { period }, + }); +} + +// 获取前一天流量使用前五名的卡片 +export function TopUsageCards() { + return requestClient.get('/home/topUsageCards'); +} + +// 获取流量池流量使用情况 +export function FlowPoolUsage() { + return requestClient.get('/home/flowPoolUsage'); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tDashboard/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tDashboard/type.ts new file mode 100644 index 0000000..69aea58 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tDashboard/type.ts @@ -0,0 +1,64 @@ +/** 首页卡片数据统计 */ +export interface CardStatisticsRes { + /** 总卡数 */ + totalCount: number; + /** 本月新增开卡数 */ + monthlyNewCount: number; + /** 本月流量用量 */ + monthlyFlowUsage: number; + /** 本月活跃卡数 */ + monthlyActiveCount: number; +} + +/** 卡状态统计 */ +export interface CardStatusStatisticsRes { + /** 待激活(1) */ + pendingActivationCount: number; + /** 已激活(2) */ + activatedCount: number; + /** 停机(4) */ + stoppedCount: number; + /** 可测试(6) */ + testableCount: number; + /** 库存(7) */ + inventoryCount: number; + /** 预销户(8) */ + preCancelCount: number; + /** 已销户(9) */ + canceledCount: number; + /** 未知(0) */ + unknownCount: number; +} + +/** 流量使用图表 */ +export interface FlowUsageChartRes { + /** 日期/月度标签 */ + labels: string[]; + /** 流量使用值,单位 MB */ + values: number[]; +} + +/** TOP 流量卡片 */ +export interface TopUsageCard { + iccid: string; + statDate: string; + /** 使用量,单位 MB */ + usageMb: number; +} + +/** TOP 流量卡片响应 */ +export interface TopUsageCardsRes { + data: TopUsageCard[]; +} + +/** 单个流量池使用情况 */ +export interface FlowPoolUsageItem { + flowPoolCode: string; + totalFlowMb: number; + usedFlowMb: number; +} + +/** 流量池使用情况响应 */ +export interface FlowPoolUsageRes { + data: FlowPoolUsageItem[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tFlowPackageConfig/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tFlowPackageConfig/index.ts new file mode 100644 index 0000000..141a152 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tFlowPackageConfig/index.ts @@ -0,0 +1,56 @@ +import { requestClient } from '#/api/request'; + +// 获取SIM流量池套餐配置表列表 +export function List(params:any) { + return requestClient.get('iot/tFlowPackageConfig/list', { params }); +} + +// 删除/批量删除SIM流量池套餐配置表 +export function Delete(params:any) { + return requestClient.post('iot/tFlowPackageConfig/delete', { ...params }); +} + +// 添加/编辑SIM流量池套餐配置表 +export function Edit(params:any) { + return requestClient.post('iot/tFlowPackageConfig/edit', { ...params }); +} + +// 获取SIM流量池套餐配置表指定详情 +export function View(params:any) { + return requestClient.get('iot/tFlowPackageConfig/view', { params }); +} + +// 导出SIM流量池套餐配置表 +export function Export(params:any) { + return requestClient.post('iot/tFlowPackageConfig/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} + +export function GetFlowPackageOptions(params: { poolPackageCode?: string } = {}) { + return requestClient.get( + 'iot/tSimFlowPackageInfo/getFlowPackageOptions', + { params }, + ); +} + +export function FlowPackageList( + params: { flow: string; poolPackageCode?: string } | string, +) { + const flow = typeof params === 'string' ? params : params.flow; + const poolPackageCode = + typeof params === 'string' ? '' : params.poolPackageCode || ''; + const queryFlow = + flow?.startsWith('"') && flow?.endsWith('"') ? flow : `"${flow}"`; + const queryPoolPackageCode = poolPackageCode + ? `&poolPackageCode=${encodeURIComponent(poolPackageCode)}` + : ''; + return requestClient.get( + `iot/tSimFlowPackageInfo/flowPackageList?flow=${queryFlow}${queryPoolPackageCode}`, + ); +} + +export function FlowPackageAddList() { + return requestClient.get('iot/tSimFlowPackageInfo/flowPackageAddList'); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.test.ts new file mode 100644 index 0000000..3a7f1c3 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.test.ts @@ -0,0 +1,50 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { Cards, WarehousingList } from './index'; + +const request = vi.hoisted(() => ({ get: vi.fn() })); +vi.mock('#/api/request', () => ({ requestClient: request })); + +describe('入库列表渠道筛选请求', () => { + it('卡清单按服务端状态筛选,保留状态零并允许清空', async () => { + for (const detailStatus of [0, 3, 4, undefined]) { + const params = { + batchNo: 'INB-TEST', + detailStatus, + page: 1, + pageSize: 20, + }; + await Cards(params); + expect(request.get).toHaveBeenLastCalledWith('common/batchMain/cards', { + params, + }); + } + }); + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('切换渠道后每次传递当前编码并保留入库类型', async () => { + for (const chanKey of ['A', 'B']) { + await WarehousingList({ chanKey, page: 1, pageSize: 20 }); + expect(request.get).toHaveBeenLastCalledWith( + 'common/batchMain/successList', + { + params: { batchType: 1, chanKey, page: 1, pageSize: 20 }, + }, + ); + } + expect(request.get).toHaveBeenCalledTimes(2); + }); + + it('清空渠道不残留上一次筛选条件', async () => { + await WarehousingList({ chanKey: 'A', page: 1 }); + await WarehousingList({ page: 1 }); + expect(request.get).toHaveBeenLastCalledWith( + 'common/batchMain/successList', + { + params: { batchType: 1, page: 1 }, + }, + ); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts new file mode 100644 index 0000000..9fe6797 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts @@ -0,0 +1,81 @@ +import type { + BatchMainCardsParam, + BatchMainCardsRes, + BatchMainDeleteParam, + BatchMainEditParam, + BatchMainExportParam, + BatchMainListParam, + BatchMainListRes, + BatchMainViewParam, + BatchMainViewRes, + BatchMainWarehousingListParam, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取批次主表列表 +export function List(params: BatchMainListParam) { + return requestClient.get('common/batchMain/successList', { + params, + }); +} + +// 获取入库批次列表 +export function WarehousingList(params: BatchMainWarehousingListParam) { + return List({ + ...params, + batchType: 1, + }); +} + +// 获取批次卡清单 +export function Cards(params: BatchMainCardsParam) { + return requestClient.get('common/batchMain/cards', { + params, + }); +} + +// 删除/批量删除批次主表 +export function Delete(params: BatchMainDeleteParam) { + return requestClient.post('common/batchMain/delete', { ...params }); +} + +// 添加/编辑批次主表 +export function Edit(params: BatchMainEditParam) { + return requestClient.post('common/batchMain/edit', { ...params }); +} + +// 获取批次主表指定详情 +export function View(params: BatchMainViewParam) { + return requestClient.get('common/batchMain/view', { + params, + }); +} + +// 导出入库批次列表(数据与入库管理页一致) +export function ExportWarehousing(params: BatchMainWarehousingListParam) { + return requestClient.post( + '/common/batchMain/exportWarehousing', + { ...params, batchType: 1 }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} + +// 导出批次主表 +export function Export(params: BatchMainExportParam) { + return requestClient.post( + '/common/batchMain/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts new file mode 100644 index 0000000..91b72e9 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts @@ -0,0 +1,272 @@ +import type { AllocationUnits } from '#/api/iotlcm/tOperationlog/type'; +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 批次主表列表项 */ +export interface BatchMainBatchInfo { + /** 协议期到期时间 */ + agreementExpiryDate?: null | string; + /** 卡类型 */ + cardType?: string; + /** 运营商达量断网 */ + carrierTrafficCutoffEnabled?: number; + /** 通道编号 */ + chanKey?: string; + /** 是否开启上游三码校验:1开启 0关闭 */ + validateUpstreamBasicInfo?: number; + /** 结束ICCID */ + endIccid?: string; + /** 结束IMSI */ + endImsi?: string; + /** 结束MSISDN */ + endMsisdn?: string; + /** 是否有沉默期 */ + hasSilentPeriod?: number; + /** 是否有测试期 */ + hasTestPeriod?: number; + /** 导入文件OSS ID */ + importFileOssId?: number; + /** 贴片转插拔 */ + insertToPlugEnabled?: number; + /** 沉默期天数 */ + silentPeriodDays?: number; + /** 沉默期最晚过期日期 */ + silentPeriodLatestExpiryDate?: null | string; + /** 起始ICCID */ + startIccid?: string; + /** 起始IMSI */ + startImsi?: string; + /** 起始MSISDN */ + startMsisdn?: string; + /** 供应商 */ + suppliersCode?: string; + /** 测试期天数 */ + testPeriodDays?: number; + /** 测试期最晚过期日期 */ + testPeriodLatestExpiryDate?: null | string; + /** 上游套餐 */ + upPkgCode?: string; + /** 上游给出激活时间 */ + upstreamActivationTime?: null | string; + [property: string]: any; +} + +export interface BatchMainModel extends AllocationUnits { + /** 批次业务参数 */ + batchInfo?: BatchMainBatchInfo; + /** 批次编号 */ + batchNo: string; + /** 批次执行时间 */ + batchTime?: string; + /** 批次类型 枚举 */ + batchType: number; + /** 总数量 */ + totalCount: number; + /** 在库数量 */ + stockCount?: number; + [property: string]: any; +} + +/** 获取批次主表指定信息响应项 */ +export interface BatchMainViewModel extends AllocationUnits { + /** 主键ID */ + id: number; + /** 批次编号 */ + batchNo: string; + /** 订单编号 */ + orderSn: string; + /** 批次类型 枚举 */ + batchType: number; + /** 异步处理状态 0=已创建 1=待处理 2=处理中 3=成功 4=失败 5=部分成功 */ + batchAsyncStatus: number; + /** 来源方式 枚举 */ + sourceType: number; + /** 来源批次编号 */ + sourceBatchNo: string; + /** 是否跨级操作机构 0-否 1-是 */ + isCrossDept: number; + /** 目标机构编号 */ + targetDeptId: number; + /** 机构编号 */ + deptId: number; + /** 总数量 */ + totalCount: number; + /** 有效数量 */ + validCount: number; + /** 成功数量 */ + successCount: number; + /** 失败数量 */ + failCount: number; + /** 运行结果:0-待运行 1-运行中 2-成功 3-失败 */ + runResult: number; + /** 失败原因 */ + failReason: string; + /** 批次信息:入库/出库展示字段 */ + batchInfo: BatchMainViewModel; + /** 备注扩展字段 */ + remark: BatchMainViewModel; + /** 开始时间 */ + startTime: string; + /** 结束时间 */ + endTime: string; + /** 租户ID */ + tenantId: string; + /** 创建部门ID */ + createdDept: number; + /** 创建者ID */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者ID */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 创建者ID摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者ID摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取批次主表列表 请求参数 */ +export interface BatchMainListParam { + /** 关键字 */ + keyword?: string; + /** 批次编号 */ + batchNo?: string; + /** 批次类型 枚举 */ + batchType: number; + /** 批次执行时间 */ + time?: string[]; + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; +} + +/** 获取入库批次列表 请求参数 */ +export type BatchMainWarehousingListParam = Omit< + BatchMainListParam, + 'batchType' +> & { + chanKey?: string; +}; + +/** 获取批次主表列表 响应 */ +export type BatchMainListRes = GlobalListRes; + +/** 批次卡清单列表项 */ +export interface BatchCardListModel extends AllocationUnits { + errorReason?: string; + /** 明细状态 */ + detailStatus?: number; + /** ICCID */ + iccid?: string; + /** IMSI */ + imsi?: string; + /** MSISDN */ + msisdn?: string; + /** 行号 */ + rowNo?: number; + [property: string]: any; +} + +/** 获取批次卡清单请求参数 */ +export interface BatchMainCardsParam { + detailStatus?: number; + /** 批次编号 */ + batchNo: string; + /** 批次类型 */ + batchType?: number; + /** ICCID */ + iccid?: string; + /** 关键字 */ + keyword?: string; + /** MSISDN */ + msisdn?: string; + /** 仅显示当前库存卡 */ + currentStockOnly?: boolean; + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + [property: string]: any; +} + +/** 获取批次卡清单响应 */ +export type BatchMainCardsRes = GlobalListRes; + +/** 导出批次主表列表 请求参数 */ +export type BatchMainExportParam = BatchMainListParam; + +/** 修改/新增批次主表 请求参数 */ +export interface BatchMainEditParam { + /** 新建批次操作规模:1单卡2批量 */ + executionMode?: number; + /** 主键ID */ + id?: number; + /** 批次编号 */ + batchNo?: string; + /** 订单编号 */ + orderSn?: string; + /** 批次类型 枚举 */ + batchType?: number; + /** 批次状态 枚举 */ + batchStatus?: number; + /** 来源方式 枚举 */ + sourceType?: number; + /** 来源批次编号 */ + sourceBatchNo?: string; + /** 是否跨级操作机构 0-否 1-是 */ + isCrossDept?: number; + /** 目标机构编号 */ + targetDeptId?: number; + /** 机构编号 */ + deptId?: number; + /** 总数量 */ + totalCount?: number; + /** 有效数量 */ + validCount?: number; + /** 成功数量 */ + successCount?: number; + /** 失败数量 */ + failCount?: number; + /** 运行结果:0-待运行 1-运行中 2-成功 3-失败 */ + runResult?: number; + /** 失败原因 */ + failReason?: string; + /** 批次信息:入库/出库展示字段 */ + batchInfo?: BatchMainViewModel; + /** 备注扩展字段 */ + remark?: BatchMainViewModel; + /** 开始时间 */ + startTime?: string; + /** 结束时间 */ + endTime?: string; + /** 租户ID */ + tenantId?: string; + /** 创建部门ID */ + createdDept?: number; + /** 创建者ID */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者ID */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取批次主表指定信息 请求参数 */ +export interface BatchMainViewParam { + /** 主键ID */ + id: number; +} + +/** 获取批次主表指定信息 响应 */ +export type BatchMainViewRes = BatchMainViewModel; + +/** 删除批次主表 请求参数 */ +export interface BatchMainDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/index.ts new file mode 100644 index 0000000..48783c7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/index.ts @@ -0,0 +1,21 @@ +import type { + TSimCardCancellationFilter, + TSimCardCancellationListParam, + TSimCardCancellationListRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function List(params: TSimCardCancellationListParam) { + return requestClient.get( + '/iot/tSimCardCancellation/list', + { params }, + ); +} + +export function Export(params: TSimCardCancellationFilter) { + return requestClient.post('/iot/tSimCardCancellation/export', params, { + responseReturn: 'raw', + responseType: 'blob', + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/type.ts new file mode 100644 index 0000000..15265a3 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/type.ts @@ -0,0 +1,45 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +export interface TSimCardCancellationModel { + id: number; + iccid: string; + msisdn: string; + imsi: string; + imei: string; + deptId: number; + deptName: string; + chanKey: string; + chanName: string; + cancelBatchNo: string; + cancelledAt: string; + bossCardStatus: number; + currentPackageCode: string; + packageName: string; + inboundBatchNo: string; + outboundBatchNo: string; + allocationBatchNo: string; + cardType: number; + netModel: number; + remark: string; + createdBy: number; + createdBySumma?: MemberSumma; +} + +export interface TSimCardCancellationFilter { + cardValue?: string; + cancelBatchNo?: string; + deptId?: number; + chanKey?: string; + cancelledStartAt?: string; + cancelledEndAt?: string; + remark?: string; +} + +export interface TSimCardCancellationListParam extends TSimCardCancellationFilter { + page: number; + pageSize: number; +} + +export type TSimCardCancellationListRes = + GlobalListRes; diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.test.ts new file mode 100644 index 0000000..440f548 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.test.ts @@ -0,0 +1,89 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + post, + upload, + }, +})); + +describe('tSimCardInbound api', () => { + beforeEach(() => { + download.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads inbound template from backend contract path', async () => { + const { ExcelTemplate } = await import('./index'); + + ExcelTemplate(); + + expect(download).toHaveBeenCalledWith( + '/iot/tSimCardInbound/excel/template', + { + responseReturn: 'raw', + }, + ); + }); + + it('submits excel inbound import with validation flag form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'inbound.xlsx'); + + ExcelSubmit({ file, validateUpstreamBasicInfo: 1 }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardInbound/excel/submit', + { file, validateUpstreamBasicInfo: 1 }, + { + timeout: 60_000, + }, + ); + }); + + it('submits range inbound import with backend contract path', async () => { + const { RangeSubmit } = await import('./index'); + const params = { + cardType: '1', + chanKey: 'CMCC', + endIccid: '8986000000000000009', + endImsi: '460001000000009', + endMsisdn: '14000000009', + sourceType: 1, + startIccid: '8986000000000000001', + startImsi: '460001000000001', + startMsisdn: '14000000001', + validateUpstreamBasicInfo: 0, + }; + + RangeSubmit(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardInbound/range/submit', { + ...params, + }); + }); + + it('submits input inbound import with backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + cardType: '1', + chanKey: 'CMCC', + input: '8986000000000000001 14000000001 460001000000001', + sourceType: 2, + upPkgCode: 'UP001', + validateUpstreamBasicInfo: 0, + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith('/iot/tSimCardInbound/input/submit', { + ...params, + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.ts new file mode 100644 index 0000000..7966330 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.ts @@ -0,0 +1,137 @@ +import { requestClient } from '#/api/request'; + +// 下载入库示例模板 +export function ExcelTemplate() { + return requestClient.download('/iot/tSimCardInbound/excel/template', { + responseReturn: 'raw', + }); +} + +export interface TSimCardInboundExcelSubmitParams { + file: File; + /** 是否开启上游三码校验:1开启 0关闭 */ + validateUpstreamBasicInfo?: number; +} + +export interface TSimCardInboundSubmitRes { + /** 批次编号 */ + batchNo?: string; + /** 批次类型 */ + batchType?: number; +} + +export interface TSimCardInboundRangeSubmitParams { + /** 连号字段:iccid、msisdn 或 imsi */ + rangeType?: 'iccid' | 'imsi' | 'msisdn'; + /** 协议期到期时间 */ + agreementExpiryDate?: string; + /** 卡类型 */ + cardType?: string; + /** 是否运营商达量断网(global_yes_or_no) */ + carrierTrafficCutoffEnabled?: number; + /** 通道编号 */ + chanKey?: string; + /** 是否开启上游三码校验:1开启 0关闭 */ + validateUpstreamBasicInfo?: number; + /** 结束号段ICCID */ + endIccid?: string; + /** 结束号段IMSI */ + endImsi?: string; + /** 结束号段MSISDN */ + endMsisdn?: string; + /** 是否有沉默期(global_yes_or_no) */ + hasSilentPeriod?: number; + /** 是否有测试期(global_yes_or_no) */ + hasTestPeriod?: number; + /** 是否贴片转插拔(global_yes_or_no) */ + insertToPlugEnabled?: number; + /** 来源方式:0 批次选择,1 连号,2 批量输入,3 文件,4 定时任务 */ + sourceType?: number; + /** 沉默期天数 */ + silentPeriodDays?: number; + /** 沉默期最晚过期日期 */ + silentPeriodLatestExpiryDate?: string; + /** 起始号段ICCID */ + startIccid?: string; + /** 起始号段IMSI */ + startImsi?: string; + /** 起始号段MSISDN */ + startMsisdn?: string; + /** 供应商编码 */ + suppliersCode?: string; + /** 测试期天数 */ + testPeriodDays?: number; + /** 测试期最晚过期日期 */ + testPeriodLatestExpiryDate?: string; + /** 上游套餐编码 */ + upPkgCode?: string; + /** 上游给出激活时间 */ + upstreamActivationTime?: string; + [property: string]: any; +} + +export interface TSimCardInboundInputSubmitParams { + /** 协议期到期时间 */ + agreementExpiryDate?: string; + /** 卡类型 */ + cardType?: string; + /** 是否运营商达量断网(global_yes_or_no) */ + carrierTrafficCutoffEnabled?: number; + /** 通道编号 */ + chanKey?: string; + /** 是否开启上游三码校验:1开启 0关闭 */ + validateUpstreamBasicInfo?: number; + /** 是否有沉默期(global_yes_or_no) */ + hasSilentPeriod?: number; + /** 是否有测试期(global_yes_or_no) */ + hasTestPeriod?: number; + /** 批量输入内容 */ + input: string; + /** 是否贴片转插拔(global_yes_or_no) */ + insertToPlugEnabled?: number; + /** 来源方式:0 批次选择,1 连号,2 批量输入,3 文件,4 定时任务 */ + sourceType?: number; + /** 沉默期天数 */ + silentPeriodDays?: number; + /** 沉默期最晚过期日期 */ + silentPeriodLatestExpiryDate?: string; + /** 供应商编码 */ + suppliersCode?: string; + /** 测试期天数 */ + testPeriodDays?: number; + /** 测试期最晚过期日期 */ + testPeriodLatestExpiryDate?: string; + /** 上游套餐编码 */ + upPkgCode?: string; + /** 上游给出激活时间 */ + upstreamActivationTime?: string; + [property: string]: any; +} + +// Excel批量卡入库 +export function ExcelSubmit(params: TSimCardInboundExcelSubmitParams) { + const { file, ...data } = params; + return requestClient.upload( + '/iot/tSimCardInbound/excel/submit', + { ...data, file }, + { + timeout: 60_000, + }, + ); +} + +// 连号批量卡入库 +export function RangeSubmit(params: TSimCardInboundRangeSubmitParams) { + return requestClient.post( + '/iot/tSimCardInbound/range/submit', + { ...params }, + ); +} + +// 批量输入卡入库 +export function InputSubmit(params: TSimCardInboundInputSubmitParams) { + return requestClient.post( + '/iot/tSimCardInbound/input/submit', + { ...params }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts new file mode 100644 index 0000000..7965934 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts @@ -0,0 +1,221 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const download = vi.fn(); +const get = vi.fn(); +const post = vi.fn(); +const upload = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { + download, + get, + post, + upload, + }, +})); + +describe('tSimCardOutbound api', () => { + beforeEach(() => { + download.mockReset(); + get.mockReset(); + post.mockReset(); + upload.mockReset(); + }); + + it('downloads excel outbound template from backend contract path', async () => { + const { DownloadTemplate } = await import('./index'); + + DownloadTemplate(); + + expect(download).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/excel/template', + { + responseReturn: 'raw', + }, + ); + }); + + it('submits excel outbound as file-only form data', async () => { + const { ExcelSubmit } = await import('./index'); + const file = new File(['iccid'], 'outbound.xlsx'); + + ExcelSubmit({ file }); + + expect(upload).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/excel/submit', + { file }, + { + timeout: 180_000, + }, + ); + }); + + it('submits range outbound with backend contract path', async () => { + const { RangeSubmit } = await import('./index'); + const params = { + customerAgentId: 12, + durationMonths: 6, + endIccid: '8986000000000000009', + endImsi: '460000000000009', + endMsisdn: '13000000009', + offlineContractCompleted: true, + packageBeginTime: '2026-07-02 10:00:00', + packageCode: 'PKG001', + startIccid: '8986000000000000001', + startImsi: '460000000000001', + startMsisdn: '13000000001', + }; + + RangeSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/range/submit', + params, + { timeout: 180_000 }, + ); + }); + + it('queries outbound inbound batch list from backend contract path', async () => { + const { InboundBatchList } = await import('./index'); + const params = { + batchNo: 'IN202607020001', + page: 1, + pageSize: 20, + }; + + InboundBatchList(params); + + expect(get).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/inboundBatch/list', + { + params, + }, + ); + }); + + it('queries outbound inbound batch cards from backend contract path', async () => { + const { InboundBatchCards } = await import('./index'); + const params = { + batchNo: 'IN202607020001', + iccid: '8986', + page: 1, + pageSize: 20, + }; + + InboundBatchCards(params); + + expect(get).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/inboundBatch/cards', + { + params, + }, + ); + }); + + it('queries outbound customer balance from backend contract path', async () => { + const { CustomerBalance } = await import('./index'); + const params = { customerAgentId: 12 }; + + CustomerBalance(params); + + expect(get).toHaveBeenCalledWith('/iot/tSimCardOutbound/customerBalance', { + params, + }); + }); + + it('submits inbound batch outbound with backend-supported payload', async () => { + const { BatchSubmit } = await import('./index'); + const params = { + batchNo: 'IN202607020001', + customerAgentId: 12, + durationMonths: 6, + offlineContractCompleted: false, + packageBeginTime: '2026-07-02', + packageCode: 'PKG001', + }; + + BatchSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/batch/submit', + params, + { timeout: 180_000 }, + ); + }); + + it('submits input outbound with backend contract path', async () => { + const { InputSubmit } = await import('./index'); + const params = { + customerAgentId: 12, + durationMonths: 6, + input: '8986000000000000001\n8986000000000000002', + offlineContractCompleted: true, + packageBeginTime: '2026-07-02 10:00:00', + packageCode: 'PKG001', + }; + + InputSubmit(params); + + expect(post).toHaveBeenCalledWith( + '/iot/tSimCardOutbound/input/submit', + params, + { timeout: 180_000 }, + ); + }); +}); + +describe('tSimCardStock outbound form model', () => { + it('calculates outbound end date from begin date and duration parts', async () => { + const { calculateOutboundEndDate } = + await import('#/views/iotlcm/tLifeCycle/tSimCardStock/outboundFormUtils'); + + expect( + calculateOutboundEndDate({ + durationMonthPart: 6, + durationYears: 1, + giftDurationMonthPart: 2, + giftDurationYears: 0, + packageBeginTime: '2026-08-06', + }), + ).toBe('2028-03-31'); + }); + + it('normalizes outbound submit values without period options', async () => { + const { normalizeOutboundSubmitValues } = + await import('#/views/iotlcm/tLifeCycle/tSimCardStock/outboundFormUtils'); + + expect( + normalizeOutboundSubmitValues({ + adminNote: 'old', + amount: 12, + buyerNote: 'old', + customerBalanceDisplay: '余额:¥100.00', + durationMonthPart: 3, + durationYears: 1, + expectedPackageEndTime: '2027-11-06', + giftDurationMonthPart: 1, + giftDurationYears: 0, + hasSilentPeriod: 0, + hasTestPeriod: 0, + offlineContractCompleted: false, + remark: ' remark ', + silentPeriodDays: 7, + testPeriodDays: 3, + }), + ).toMatchObject({ + amount: '12', + adminNote: undefined, + buyerNote: undefined, + customerBalanceDisplay: undefined, + durationMonths: 15, + expectedPackageEndTime: undefined, + giftDurationMonths: 1, + hasSilentPeriod: undefined, + hasTestPeriod: undefined, + offlineContractCompleted: false, + remark: 'remark', + silentPeriodDays: undefined, + testPeriodDays: undefined, + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.ts new file mode 100644 index 0000000..8e19e11 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.ts @@ -0,0 +1,197 @@ +import { requestClient } from '#/api/request'; + +export interface TSimCardOutboundSubmitRes { + batchAsyncStatus: number; + batchNo: string; + batchType: number; + failCount?: number; + orderSn?: string; + quantity?: number; + resultDownloadId?: number; + resultFileOssId?: number; + status?: string; + total?: number; + validCount?: number; + [property: string]: any; +} + +export interface TSimCardOutboundSubmitBaseParam { + adminNote?: string; + amount?: number | string; + buyerNote?: string; + customerAgentId: number; + durationMonthPart?: number; + durationYears?: number; + durationMonths: number; + giftDurationMonthPart?: number; + giftDurationYears?: number; + giftDurationMonths?: number; + offlineContractCompleted: boolean; + packageBeginTime: string; + packageCode: string; + remark?: string; + [property: string]: any; +} + +export interface TSimCardOutboundExcelSubmitParam { + file: File; +} + +export interface TSimCardOutboundRangeSubmitParam extends TSimCardOutboundSubmitBaseParam { + endIccid: string; + endImsi: string; + endMsisdn: string; + rangeCodeType?: 'iccid' | 'imsi' | 'msisdn'; + startIccid: string; + startImsi: string; + startMsisdn: string; +} + +export interface TSimCardOutboundInputSubmitParam extends TSimCardOutboundSubmitBaseParam { + input: string; +} + +export interface TSimCardOutboundInboundBatchListParam { + agreementExpiryMonths?: number; + batchNo?: string; + cardType?: string; + chanName?: string; + page?: number; + pageSize?: number; + upPkgKeyword?: string; +} + +export interface TSimCardOutboundInboundBatchListItem { + agreementExpiryDate?: string; + batchNo: string; + cardType?: string; + chanKey?: string; + chanName?: string; + firstCreatedAt?: string; + lastCreatedAt?: string; + stockCount: number; + upPkgCode?: string; + upPkgName?: string; +} + +export interface TSimCardOutboundInboundBatchListRes { + items: TSimCardOutboundInboundBatchListItem[]; + total: number; +} + +export interface TSimCardOutboundInboundBatchCardsParam { + batchNo: string; + iccid?: string; + imsi?: string; + msisdn?: string; + page?: number; + pageSize?: number; +} + +export interface TSimCardOutboundInboundBatchCardItem { + agreementExpiryDate?: string; + batchNo: string; + cardType?: string; + chanKey?: string; + chanName?: string; + createdAt?: string; + iccid: string; + imei?: string; + imsi?: string; + msisdn?: string; + upPkgCode?: string; + upPkgName?: string; +} + +export interface TSimCardOutboundInboundBatchCardsRes { + items: TSimCardOutboundInboundBatchCardItem[]; + total: number; +} + +export interface TSimCardOutboundBatchSubmitParam extends TSimCardOutboundSubmitBaseParam { + batchNo: string; +} + +export interface TSimCardOutboundCustomerBalanceParam { + customerAgentId: number; +} + +export interface TSimCardOutboundCustomerBalanceRes { + accountExists: boolean; + balance: number; + customerAgentId: number; + customerName?: string; + status: number; + statusText?: string; +} + +export function DownloadTemplate() { + return requestClient.download('/iot/tSimCardOutbound/excel/template', { + responseReturn: 'raw', + }); +} + +export function ExcelSubmit(params: TSimCardOutboundExcelSubmitParam) { + return requestClient.upload( + '/iot/tSimCardOutbound/excel/submit', + { file: params.file }, + { + timeout: 180_000, + }, + ); +} + +export function RangeSubmit(params: TSimCardOutboundRangeSubmitParam) { + return requestClient.post( + '/iot/tSimCardOutbound/range/submit', + params, + { timeout: 180_000 }, + ); +} + +export function InputSubmit(params: TSimCardOutboundInputSubmitParam) { + return requestClient.post( + '/iot/tSimCardOutbound/input/submit', + params, + { timeout: 180_000 }, + ); +} + +export function InboundBatchList( + params: TSimCardOutboundInboundBatchListParam, +) { + return requestClient.get( + '/iot/tSimCardOutbound/inboundBatch/list', + { + params, + }, + ); +} + +export function InboundBatchCards( + params: TSimCardOutboundInboundBatchCardsParam, +) { + return requestClient.get( + '/iot/tSimCardOutbound/inboundBatch/cards', + { + params, + }, + ); +} + +export function BatchSubmit(params: TSimCardOutboundBatchSubmitParam) { + return requestClient.post( + '/iot/tSimCardOutbound/batch/submit', + params, + { timeout: 180_000 }, + ); +} + +export function CustomerBalance(params: TSimCardOutboundCustomerBalanceParam) { + return requestClient.get( + '/iot/tSimCardOutbound/customerBalance', + { + params, + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/index.ts new file mode 100644 index 0000000..a96e50a --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/index.ts @@ -0,0 +1,49 @@ +import type { + TSimCardStockDeleteParam, + TSimCardStockEditParam, + TSimCardStockExportParam, + TSimCardStockListParam, + TSimCardStockListRes, + TSimCardStockViewParam, + TSimCardStockViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取库存卡信息表列表 +export function List(params: TSimCardStockListParam) { + return requestClient.get('iot/tSimCardStock/list', { + params, + }); +} + +// 删除/批量删除库存卡信息表 +export function Delete(params: TSimCardStockDeleteParam) { + return requestClient.post('iot/tSimCardStock/delete', { ...params }); +} + +// 添加/编辑库存卡信息表 +export function Edit(params: TSimCardStockEditParam) { + return requestClient.post('iot/tSimCardStock/edit', { ...params }); +} + +// 获取库存卡信息表指定详情 +export function View(params: TSimCardStockViewParam) { + return requestClient.get('iot/tSimCardStock/view', { + params, + }); +} + +// 导出库存卡信息表 +export function Export(params: TSimCardStockExportParam) { + return requestClient.post( + '/iot/tSimCardStock/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts new file mode 100644 index 0000000..294c0c6 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts @@ -0,0 +1,127 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 库存卡信息表列表项 */ +export interface TSimCardStockModel { + /** 主键ID */ + id: number; + /** 入库批次号 */ + batchNo?: string; + /** ICCID */ + iccid: string; + /** MSISDN */ + msisdn: string; + /** IMSI */ + imsi: string; + /** IMEI */ + imei: string; + /** 通道编号 */ + chanKey: string; + /** 通道名称 */ + chanName?: string; + /** 卡类型 */ + cardType?: string; + /** 上游套餐编码 */ + upPkgCode?: string; + /** 上游套餐名称 */ + upPkgName?: string; + /** 协议到期时间 */ + agreementExpiryDate?: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建部门名称 */ + createdDeptName?: string; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取库存卡信息表列表 请求参数 */ +export interface TSimCardStockListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 入库批次号 */ + batchNo?: string; + /** ICCID */ + iccid?: string; + /** MSISDN */ + msisdn?: string; + /** IMSI */ + imsi?: string; + /** 通道编号 */ + chanKey?: string; + /** 通道名称 */ + chanName?: string; + /** 卡类型 */ + cardType?: string; + /** 上游套餐关键字 */ + upPkgKeyword?: string; + /** 协议到期快捷筛选(月) */ + agreementExpiryMonths?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取库存卡信息表列表 响应 */ +export type TSimCardStockListRes = GlobalListRes; + +/** 导出库存卡信息表列表 请求参数 */ +export type TSimCardStockExportParam = TSimCardStockListParam; + +/** 修改/新增库存卡信息表 请求参数 */ +export interface TSimCardStockEditParam { + /** 主键ID */ + id?: number; + /** ICCID */ + iccid?: string; + /** MSISDN */ + msisdn?: string; + /** IMSI */ + imsi?: string; + /** IMEI */ + imei?: string; + /** 通道编号 */ + chanKey?: string; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取库存卡信息表指定信息 请求参数 */ +export interface TSimCardStockViewParam { + /** 主键ID */ + id: number; +} + +/** 获取库存卡信息表指定信息 响应 */ +export type TSimCardStockViewRes = TSimCardStockModel; + +/** 删除库存卡信息表 请求参数 */ +export interface TSimCardStockDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts new file mode 100644 index 0000000..322a49f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts @@ -0,0 +1,50 @@ +import type { + BatchExecutionLogDetailListParam, + BatchExecutionLogDetailListRes, + BatchExecutionLogListParam, + BatchExecutionLogListRes, + BatchExecutionLogSummaryParam, + BatchExecutionLogSummaryRes, + BatchExecutionLogSyncReviewParam, + BatchExecutionLogSyncReviewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取批次执行日志列表 +export function List(params: BatchExecutionLogListParam) { + return requestClient.get( + 'common/batchExecutionLog/list', + { + params, + }, + ); +} + +// 获取批次执行日志概要 +export function Summary(params: BatchExecutionLogSummaryParam) { + return requestClient.get( + 'common/batchExecutionLog/summary', + { + params, + }, + ); +} + +// 获取批次执行日志明细列表 +export function DetailList(params: BatchExecutionLogDetailListParam) { + return requestClient.get( + 'common/batchExecutionLog/detailList', + { + params, + }, + ); +} + +// 手动同步待核查批次的上游执行结果(只读补查既有受理号,不重发办理) +export function SyncReview(data: BatchExecutionLogSyncReviewParam) { + return requestClient.post( + 'common/batchExecutionLog/syncReview', + { ...data }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts new file mode 100644 index 0000000..8544cfc --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts @@ -0,0 +1,235 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 划拨单位信息,名称优先使用提交时快照。 */ +export interface AllocationUnits { + sourceDeptId?: number; + sourceDeptName?: string; + targetDeptId?: number; + targetDeptName?: string; + targetDeptMode?: 'per_row' | 'single'; +} + +/** 批次执行日志列表项 */ +export interface BatchExecutionLogModel extends AllocationUnits { + sourceChannel?: string; + executionMode?: number; + /** 主键ID */ + id?: number; + /** 批次编号 */ + batchNo?: string; + /** 异步处理状态 */ + batchAsyncStatus?: number; + /** 重启阶段:waiting_resume 表示停机后等待复机 */ + restartPhase?: string; + /** 计划复机时间 */ + restartResumeAt?: string; + /** 批次类型 */ + batchType?: number; + /** 来源方式 */ + sourceType?: null | number; + /** 总数量 */ + totalCount?: number; + /** 待核查数量 */ + unknownCount?: number; + /** 运行结果 */ + runResult?: number; + /** 开始时间 */ + startTime?: string; + /** 结束时间 */ + endTime?: string; + /** 创建部门ID */ + createdDept?: number; + /** 创建者ID */ + createdBy?: number; + /** 创建者摘要 */ + createdBySumma?: MemberSumma; + /** 创建时间 */ + createdAt?: string; +} + +/** 批次执行日志概要响应 */ +export interface BatchExecutionLogSummaryRes extends AllocationUnits { + sourceChannel?: string; + executionMode?: number; + /** 主键ID */ + id?: number; + /** 批次编号 */ + batchNo?: string; + /** 异步处理状态 */ + batchAsyncStatus?: number; + /** 重启阶段:waiting_resume 表示停机后等待复机 */ + restartPhase?: string; + /** 计划复机时间 */ + restartResumeAt?: string; + /** 批次类型 */ + batchType?: number; + /** 来源方式 */ + sourceType?: null | number; + /** 总数量 */ + totalCount?: number; + /** 待核查数量 */ + unknownCount?: number; + /** 运行结果 */ + runResult?: number; + /** 失败原因 */ + failReason?: string; + /** 源文件 */ + sourceFile?: BatchExecutionLogFileModel; + /** 结果文件 */ + resultFile?: BatchExecutionLogResultFileModel; + /** 开始时间 */ + startTime?: string; + /** 结束时间 */ + endTime?: string; +} + +/** 批次执行日志文件信息 */ +export interface BatchExecutionLogFileModel { + /** 导出任务ID;与历史批次下载任务ID分开,走下载中心鉴权 */ + exportTaskId?: number; + /** OSS文件ID */ + ossId?: number; + /** 文件URL */ + url?: string; +} + +/** 批次执行日志结果文件信息 */ +export interface BatchExecutionLogResultFileModel extends BatchExecutionLogFileModel { + /** 原始下载文件名 */ + originalName?: string; + /** 下载任务ID */ + downloadId?: number; + /** 下载状态 */ + downloadStatus?: number; +} + +/** 获取批次执行日志列表请求参数 */ +export interface BatchExecutionLogListParam { + sourceChannel?: string; + executionMode?: number; + /** 输入方式:0选择、1连号、2输入、3文件、4定时 */ + sourceType?: number; + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 批次编号 */ + batchNo?: string; + /** 异步处理状态 */ + batchAsyncStatus?: number; + /** 批次类型 */ + batchType?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取批次执行日志列表响应 */ +export type BatchExecutionLogListRes = GlobalListRes; + +/** 手动同步待核查批次上游结果的请求参数 */ +export interface BatchExecutionLogSyncReviewParam { + /** 批次编号 */ + batchNo: string; + /** 同步原因 */ + reason?: string; +} + +/** 手动同步待核查批次上游结果的响应 */ +export interface BatchExecutionLogSyncReviewRes { + /** 批次编号 */ + batchNo?: string; + /** 批次类型 */ + batchType?: number; + /** 异步处理状态 */ + batchAsyncStatus?: number; + /** 待核查数量 */ + unknownCount?: number; + /** 是否已提交同步 */ + queued?: boolean; +} + +/** 批次执行日志明细列表项 */ +export interface BatchExecutionLogDetailModel extends AllocationUnits { + /** 协议到期时间 */ + agreementExpiryDate?: string; + /** 卡类型 */ + cardType?: string; + /** 是否运营商达量断网 */ + carrierTrafficCutoffEnabled?: string; + /** 通道编号 */ + chanKey?: string; + /** 明细状态 */ + detailStatus?: number; + /** 错误信息 */ + error?: BatchExecutionLogDetailErrorModel; + /** 是否有沉默期 */ + hasSilentPeriod?: string; + /** 是否有测试期 */ + hasTestPeriod?: string; + /** ICCID */ + iccid?: string; + /** IMEI */ + imei?: string; + /** IMSI */ + imsi?: string; + /** 是否贴片转插拔 */ + insertToPlugEnabled?: string; + /** MSISDN */ + msisdn?: string; + /** 行号 */ + rowNo?: number; + /** 沉默期天数 */ + silentPeriodDays?: string; + /** 沉默期最晚过期日期 */ + silentPeriodLatestExpiryDate?: string; + /** 供应商编码 */ + suppliersCode?: string; + /** 测试期天数 */ + testPeriodDays?: string; + /** 测试期最晚过期日期 */ + testPeriodLatestExpiryDate?: string; + /** 上游套餐编码 */ + upPkgCode?: string; + /** 上游激活时间 */ + upstreamActivationTime?: string; + [property: string]: any; +} + +/** 批次执行日志明细错误信息 */ +export interface BatchExecutionLogDetailErrorModel { + /** 异常原因 */ + reason?: string; + [property: string]: any; +} + +/** 获取批次执行日志明细列表请求参数 */ +export interface BatchExecutionLogDetailListParam { + /** 批次编号 */ + batchNo: string; + /** 批次类型 */ + batchType?: number; + /** 明细状态 */ + detailStatus?: number; + /** ICCID */ + iccid?: string; + /** 关键字 */ + keyword?: string; + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + [property: string]: any; +} + +/** 获取批次执行日志明细列表响应 */ +export type BatchExecutionLogDetailListRes = + GlobalListRes; + +/** 获取批次执行日志概要请求参数 */ +export interface BatchExecutionLogSummaryParam { + /** 批次编号 */ + batchNo: string; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOrder/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOrder/index.ts new file mode 100644 index 0000000..c0efd14 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tOrder/index.ts @@ -0,0 +1,97 @@ +import { requestClient } from '#/api/request'; + +export interface OrderItem { + businessBatchNo: string; + durationUnit: string; + durationValue: number; + effectiveMode: string; + itemId: number; + price: number; + productName: string; + productSn: string; + quantity: number; + serviceBeginTime?: string; + serviceEndTime?: string; + sourceBatchNo: string; +} + +export interface OrderRow { + agentName: string; + balance: number; + businessBatchNo: string; + buyerNote: string; + createdAt: string; + customerName: string; + discountAmount: number; + distributionStatus: number; + id: number; + items?: OrderItem[]; + offlinePaidAmount: number; + onlinePaidAmount: number; + orderSn: string; + orderStatus: number; + orderType: number; + paidAmount: number; + parentOrderSn: string; + payOrderSn: string; + payStatus: number; + payTime?: string; + payType: number; + productAmount: number; + productName: string; + productSn: string; + quantity: number; + returnStatus: number; + serviceBeginTime?: string; + serviceEndTime?: string; + serviceFee: number; + totalAmount: number; + unitPrice: number; + unrefundAmount: number; + updatedAt: string; +} + +export interface OrderListParams { + createdAt?: [string, string]; + distributionStatus?: number; + orderSn?: string; + orderStatus?: number; + orderType?: number; + page: number; + pageSize: number; + payStatus?: number; + payType?: number; + perspective?: 'purchase' | 'sell'; +} + +export interface OrderListResult { + items: OrderRow[]; + page: number; + pageSize: number; + total: number; +} + +export function List(params: OrderListParams) { + return requestClient.get('iot/tOrder/list', { params }); +} + +export function SellList(params: OrderListParams) { + return requestClient.get('iot/tOrder/sellList', { params }); +} + +export function View(params: { id: number }) { + return requestClient.get('iot/tOrder/view', { params }); +} + +export function Export(params: OrderListParams) { + return requestClient.post( + '/iot/tOrder/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.ts new file mode 100644 index 0000000..dee6fd7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.ts @@ -0,0 +1,58 @@ +import type { + TSimFlowPackageInfoDeleteParam, + TSimFlowPackageInfoEditParam, + TSimFlowPackageInfoExportParam, + TSimFlowPackageInfoListParam, + TSimFlowPackageInfoListRes, + TSimFlowPackageInfoViewParam, + TSimFlowPackageInfoViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取SIM流量套餐管理列表 +export function List(params: TSimFlowPackageInfoListParam) { + return requestClient.get( + 'iot/tSimFlowPackageInfo/list', + { params }, + ); +} + +// 删除/批量删除SIM流量套餐管理 +export function Delete(params: TSimFlowPackageInfoDeleteParam) { + return requestClient.post('iot/tSimFlowPackageInfo/delete', { ...params }); +} + +// 添加/编辑SIM流量套餐管理 +export function Edit(params: TSimFlowPackageInfoEditParam) { + return requestClient.post('iot/tSimFlowPackageInfo/edit', { ...params }); +} + +// 同步当前部门套餐关联 +export function SyncDeptPackages() { + return requestClient.post('iot/tSimFlowPackageInfo/syncDeptPackages'); +} + +// 获取SIM流量套餐管理指定详情 +export function View(params: TSimFlowPackageInfoViewParam) { + return requestClient.get( + 'iot/tSimFlowPackageInfo/view', + { + params, + }, + ); +} + +// 导出SIM流量套餐管理 +export function Export(params: TSimFlowPackageInfoExportParam) { + return requestClient.post( + '/iot/tSimFlowPackageInfo/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/type.ts new file mode 100644 index 0000000..42a315a --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/type.ts @@ -0,0 +1,228 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** SIM流量套餐管理列表项 */ +export interface TSimFlowPackageInfoModel { + /** 主键ID */ + id: number; + /** 套餐编码 */ + packageCode: string; + /** 套餐分类编码 */ + categoryCode: string; + /** 套餐分类名称 */ + categoryName: string; + /** 池套餐编码 */ + poolPackageCode: number; + /** 套餐名称 */ + packageName: string; + /** 套餐类型:101-卡套餐 102-池套餐 103-单卡加油包 104-池卡加油包 */ + packageType: number; + /** 计费方式 */ + billingMethod: string; + /** 排序号 */ + sortNo: number; + /** 套餐流量(MB) */ + flowMb: number; + /** 套餐流量(GB) */ + flowGb: number; + /** 是否启用:0-停用 1-启用(flow_package_enabled) */ + enabled: number; + /** 目录售价 */ + listPrice: number; + /** 渠道出货价 */ + agentShipmentPrice: number; + /** 终端售价 */ + terminalSalePrice: number; + /** 成本价 */ + costPrice: number; + /** 默认利润 */ + defaultProfit: number; + /** 默认系数 */ + defaultRatio: number; + /** 终端成本 */ + terminalCost: number; + /** 默认终端利润 */ + defaultTerminalProfit: number; + /** 默认终端系数 */ + defaultTerminalRatio: number; + /** 是否自动续费 */ + isAutoRenew: number; + /** 自动续费套餐ID */ + autoRenewPackageId: number; + /** 自动续费年限 */ + autoRenewYears: number; + /** 租户ID */ + tenantId: string; + /** 创建部门ID */ + createdDept: number; + /** 创建者ID */ + createdBy: number; + /** 创建者ID摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者ID */ + updatedBy: number; + /** 更新者ID摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; + isTopDept?: boolean; +} + +/** 获取SIM流量套餐管理指定信息响应项 */ +export interface TSimFlowPackageInfoViewModel { + /** 主键ID */ + id: number; + /** 套餐编码 */ + packageCode: string; + /** 套餐分类编码 */ + categoryCode: string; + /** 池套餐编码 */ + poolPackageCode: number; + /** 套餐名称 */ + packageName: string; + /** 套餐类型:101-卡套餐 102-池套餐 103-单卡加油包 104-池卡加油包 */ + packageType: number; + /** 计费方式 */ + billingMethod: string; + /** 排序号 */ + sortNo: number; + /** 套餐流量(MB) */ + flowMb: number; + /** 套餐流量(GB) */ + flowGb: number; + /** 是否启用:0-停用 1-启用(flow_package_enabled) */ + enabled: number; + /** 目录售价 */ + listPrice: number; + /** 渠道出货价 */ + agentShipmentPrice: number; + /** 终端售价 */ + terminalSalePrice: number; + /** 成本价 */ + costPrice: number; + /** 默认利润 */ + defaultProfit: number; + /** 默认系数 */ + defaultRatio: number; + /** 终端成本 */ + terminalCost: number; + /** 默认终端利润 */ + defaultTerminalProfit: number; + /** 默认终端系数 */ + defaultTerminalRatio: number; + /** 可续费时长配置:[1,2,3] */ + renewableDurationConfig: TSimFlowPackageInfoViewModel; + /** 可续费套餐编码列表 */ + renewablePackageCodes?: string[]; + /** 可变更套餐编码列表 */ + changeablePackageCodes?: string[]; + /** 可订购加油包套餐编码列表 */ + topupPackageCodes?: string[]; + /** 可续费套餐名称列表 */ + renewablePackageNames?: string[]; + /** 可变更套餐名称列表 */ + changeablePackageNames?: string[]; + /** 可订购加油包套餐名称列表 */ + topupPackageNames?: string[]; + /** 是否自动续费:0-是 1-否 */ + isAutoRenew: number; + /** 自动续费套餐ID */ + autoRenewPackageId: number; + /** 自动续费年限 */ + autoRenewYears: number; + isTopDept?: boolean; +} + +/** 获取SIM流量套餐管理列表 请求参数 */ +export interface TSimFlowPackageInfoListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 套餐编码 */ + packageCode?: string; + /** 套餐分类编码 */ + categoryCode?: string; + /** 套餐名称 */ + packageName?: string; + /** 套餐类型:101-卡套餐 102-池套餐 103-单卡加油包 104-池卡加油包 */ + packageType?: string; + /** 是否启用:0-否 1-是 */ + enabled?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取SIM流量套餐管理列表 响应 */ +export type TSimFlowPackageInfoListRes = + GlobalListRes; + +/** 导出SIM流量套餐管理列表 请求参数 */ +export type TSimFlowPackageInfoExportParam = TSimFlowPackageInfoListParam; + +/** 修改/新增SIM流量套餐管理 请求参数 */ +export interface TSimFlowPackageInfoEditParam { + /** 主键ID */ + id?: number; + /** 套餐编码 */ + packageCode?: string; + /** 套餐分类编码 */ + categoryCode?: string; + /** 池套餐编码 */ + poolPackageCode?: number; + /** 套餐名称 */ + packageName?: string; + /** 套餐类型:101-卡套餐 102-池套餐 103-单卡加油包 104-池卡加油包 */ + packageType?: number; + /** 计费方式 */ + billingMethod?: string; + /** 排序号 */ + sortNo?: number; + /** 套餐流量(MB) */ + flowMb?: number; + /** 套餐流量(GB) */ + flowGb?: number; + /** 是否启用:0-否 1-是(yesno_enum) */ + enabled?: number; + /** 目录售价 */ + listPrice?: number; + /** 成本价 */ + costPrice?: number; + /** 默认利润 */ + defaultProfit?: number; + /** 默认系数 */ + defaultRatio?: number; + /** 终端成本 */ + terminalCost?: number; + /** 默认终端利润 */ + defaultTerminalProfit?: number; + /** 默认终端系数 */ + defaultTerminalRatio?: number; + /** 可续费时长配置:[1,2,3] */ + renewableDurationConfig?: TSimFlowPackageInfoViewModel; + /** 是否自动续费:0-是 1-否 */ + isAutoRenew?: number; + /** 自动续费套餐ID */ + autoRenewPackageId?: number; + /** 自动续费年限 */ + autoRenewYears?: number; +} + +/** 获取SIM流量套餐管理指定信息 请求参数 */ +export interface TSimFlowPackageInfoViewParam { + /** 主键ID */ + id: number; +} + +/** 获取SIM流量套餐管理指定信息 响应 */ +export type TSimFlowPackageInfoViewRes = TSimFlowPackageInfoViewModel; + +/** 删除SIM流量套餐管理 请求参数 */ +export interface TSimFlowPackageInfoDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.ts new file mode 100644 index 0000000..440bd7f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.ts @@ -0,0 +1,130 @@ +import type { + TSimFlowPackagePriceAgentDefaultPackagePriceInheritParam, + TSimFlowPackagePriceAgentDefaultPackagePriceListParam, + TSimFlowPackagePriceAgentDefaultPackagePriceListRes, + TSimFlowPackagePriceAgentDefaultPackagePriceSaveParam, + TSimFlowPackagePriceAgentPackagePriceInheritParam, + TSimFlowPackagePriceAgentPackagePriceListParam, + TSimFlowPackagePriceAgentPackagePriceListRes, + TSimFlowPackagePriceAgentPackagePriceSaveParam, + TSimFlowPackagePriceAgenttreeRes, + TSimFlowPackagePriceDeleteParam, + TSimFlowPackagePriceEditParam, + TSimFlowPackagePriceExportParam, + TSimFlowPackagePriceListParam, + TSimFlowPackagePriceListRes, + TSimFlowPackagePriceViewParam, + TSimFlowPackagePriceViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取SIM流量套餐定价列表 +export function List(params: TSimFlowPackagePriceListParam) { + return requestClient.get( + 'iot/tSimFlowPackagePrice/list', + { params }, + ); +} + +// 查询本级默认套餐定价 +export function AgentDefaultPackagePriceList( + params: TSimFlowPackagePriceAgentDefaultPackagePriceListParam, +) { + return requestClient.get( + 'iot/tSimFlowPackagePrice/agentDefaultPackagePrice/list', + { params }, + ); +} + +// 保存本级默认套餐定价 +export function AgentDefaultPackagePriceSave( + params: TSimFlowPackagePriceAgentDefaultPackagePriceSaveParam, +) { + return requestClient.post( + 'iot/tSimFlowPackagePrice/agentDefaultPackagePrice/save', + { ...params }, + ); +} + +// 恢复上级套餐定价 +export function AgentDefaultPackagePriceInherit( + params: TSimFlowPackagePriceAgentDefaultPackagePriceInheritParam, +) { + return requestClient.post( + 'iot/tSimFlowPackagePrice/agentDefaultPackagePrice/inherit', + { ...params }, + ); +} + +// 查询指定下级代理套餐生效定价 +export function AgentPackagePriceList( + params: TSimFlowPackagePriceAgentPackagePriceListParam, +) { + return requestClient.get( + 'iot/tSimFlowPackagePrice/agentPackagePrice/list', + { params }, + ); +} + +// 保存下级代理专属套餐定价 +export function AgentPackagePriceSave( + params: TSimFlowPackagePriceAgentPackagePriceSaveParam, +) { + return requestClient.post('iot/tSimFlowPackagePrice/agentPackagePrice/save', { + ...params, + }); +} + +// 恢复下级代理上级套餐定价 +export function AgentPackagePriceInherit( + params: TSimFlowPackagePriceAgentPackagePriceInheritParam, +) { + return requestClient.post( + 'iot/tSimFlowPackagePrice/agentPackagePrice/inherit', + { + ...params, + }, + ); +} + +// 删除/批量删除SIM流量套餐定价 +export function Delete(params: TSimFlowPackagePriceDeleteParam) { + return requestClient.post('iot/tSimFlowPackagePrice/delete', { ...params }); +} + +// 添加/编辑SIM流量套餐定价 +export function Edit(params: TSimFlowPackagePriceEditParam) { + return requestClient.post('iot/tSimFlowPackagePrice/edit', { ...params }); +} + +// 获取SIM流量套餐定价指定详情 +export function View(params: TSimFlowPackagePriceViewParam) { + return requestClient.get( + 'iot/tSimFlowPackagePrice/view', + { + params, + }, + ); +} + +// 导出SIM流量套餐定价 +export function Export(params: TSimFlowPackagePriceExportParam) { + return requestClient.post( + '/iot/tSimFlowPackagePrice/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} + +// 获取渠道代理树形结构 +export function GetTSimFlowPackagePriceAgentTreeApi() { + return requestClient.get( + '/agent/dept/subCompany', + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/type.ts new file mode 100644 index 0000000..2affc71 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/type.ts @@ -0,0 +1,332 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** SIM流量套餐定价列表项 */ +export interface TSimFlowPackagePriceModel { + /** 主键ID */ + id: number; + /** 套餐编码 */ + packageCode: string; + /** 套餐名称 */ + packageName: string; + /** 渠道适用类型:0-所有客户 1-指定客户 */ + agentScopeType: number; + /** 指定渠道客户ID */ + targetAgentId: number; + /** 机构名称 */ + deptName: string; + /** 渠道成本系数 */ + agentCostRatio: number; + /** 渠道成本利润 */ + agentCostProfit: number; + /** 终端用户成本系数 */ + userCostRatio: number; + /** 终端用户成本利润 */ + userCostProfit: number; + /** 是否启用:0-否 1-是(yesno_enum) */ + enabled: number; + /** 租户ID */ + tenantId: string; + /** 创建部门ID */ + createdDept: number; + /** 创建者ID */ + createdBy: number; + /** 创建者ID摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者ID */ + updatedBy: number; + /** 更新者ID摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取SIM流量套餐定价指定信息响应项 */ +export interface TSimFlowPackagePriceViewModel { + /** 主键ID */ + id: number; + /** 套餐编码 */ + packageCode: string; + /** 渠道适用类型:0-所有客户 1-指定客户 */ + agentScopeType: number; + /** 指定渠道客户ID */ + targetAgentId: number; + /** 机构编号 */ + deptId: string; + /** 渠道成本系数 */ + agentCostRatio: number; + /** 渠道成本利润 */ + agentCostProfit: number; + /** 终端用户成本系数 */ + userCostRatio: number; + /** 终端用户成本利润 */ + userCostProfit: number; + /** 是否启用:0-否 1-是(yesno_enum) */ + enabled: number; + /** 备注 */ + remark: string; + /** 租户ID */ + tenantId: string; + /** 创建部门ID */ + createdDept: number; + /** 创建者ID */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者ID */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 创建者ID摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者ID摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取SIM流量套餐定价列表 请求参数 */ +export interface TSimFlowPackagePriceListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 套餐编码 */ + packageCode?: string; + /** 渠道适用类型:0-所有客户 1-指定客户 */ + agentScopeType?: number; + /** 指定渠道客户ID */ + targetAgentId?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取SIM流量套餐定价列表 响应 */ +export type TSimFlowPackagePriceListRes = + GlobalListRes; + +/** 查询本级默认套餐定价 请求参数 */ +export interface TSimFlowPackagePriceAgentDefaultPackagePriceListParam { + /** 关键字 */ + keyword?: string; + /** 套餐编码 */ + packageCode?: string; + /** 套餐名称 */ + packageName?: string; + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; +} + +/** 本级/下级代理套餐价格列表项 */ +export interface TSimFlowPackagePriceAgentPackagePriceListItem { + /** 代理成本 */ + agentCost?: number; + /** 代理成本利润 */ + agentCostProfit?: number; + /** 代理成本系数 */ + agentCostRatio?: number; + /** 本级代理默认定价ID,没有则为0 */ + agentDefaultPriceId?: number; + /** 代理出货价 */ + agentShipmentPrice?: number; + /** 是否启用:0-否 1-是 */ + enabled?: number; + /** 套餐编码 */ + packageCode?: string; + /** 套餐名称 */ + packageName?: string; + /** 价格来源:system-系统兜底/agentDefault-本级默认/target-下级专属 */ + priceSource?: string; + /** 备注 */ + remark?: string; + /** 目标代理ID */ + targetAgentId?: number; + /** 本级对当前下级代理的专属定价ID,没有则为0 */ + targetPriceId?: number; + /** 终端成本 */ + terminalCost?: number; + /** 终端成本利润 */ + terminalCostProfit?: number; + /** 终端成本系数 */ + terminalCostRatio?: number; + /** 终端售价 */ + terminalSalePrice?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 查询本级默认套餐定价 响应 */ +export type TSimFlowPackagePriceAgentDefaultPackagePriceListRes = + GlobalListRes; + +/** 保存本级默认套餐定价项 */ +export interface TSimFlowPackagePriceAgentDefaultPackagePriceSaveItem { + /** 渠道利润 */ + agentCostProfit?: number; + /** 渠道成本系数 */ + agentCostRatio?: number; + /** 本级默认定价ID */ + agentDefaultPriceId?: number; + /** 套餐编码 */ + packageCode?: string; + /** 价格来源:system/agentDefault */ + priceSource?: string; + /** 备注 */ + remark?: string; + /** 终端利润 */ + terminalCostProfit?: number; + /** 终端成本系数 */ + terminalCostRatio?: number; +} + +/** 保存本级默认套餐定价 请求参数 */ +export interface TSimFlowPackagePriceAgentDefaultPackagePriceSaveParam { + /** 保存项 */ + items?: TSimFlowPackagePriceAgentDefaultPackagePriceSaveItem[]; +} + +/** 恢复本级默认套餐定价项 */ +export interface TSimFlowPackagePriceAgentDefaultPackagePriceInheritItem { + /** 本级默认定价ID */ + agentDefaultPriceId?: number; + /** 套餐编码 */ + packageCode?: string; +} + +/** 恢复本级默认套餐定价 请求参数 */ +export interface TSimFlowPackagePriceAgentDefaultPackagePriceInheritParam { + /** 恢复项 */ + items?: TSimFlowPackagePriceAgentDefaultPackagePriceInheritItem[]; +} + +/** 查询指定下级代理套餐生效定价 请求参数 */ +export interface TSimFlowPackagePriceAgentPackagePriceListParam extends TSimFlowPackagePriceAgentDefaultPackagePriceListParam { + /** 指定下级代理ID */ + targetAgentId?: number; +} + +/** 查询指定下级代理套餐生效定价 响应 */ +export type TSimFlowPackagePriceAgentPackagePriceListRes = + GlobalListRes; + +/** 保存下级代理专属套餐定价项 */ +export interface TSimFlowPackagePriceAgentPackagePriceSaveItem extends TSimFlowPackagePriceAgentDefaultPackagePriceSaveItem { + /** 下级专属定价ID */ + targetPriceId?: number; +} + +/** 保存下级代理专属套餐定价 请求参数 */ +export interface TSimFlowPackagePriceAgentPackagePriceSaveParam { + /** 保存项 */ + items?: TSimFlowPackagePriceAgentPackagePriceSaveItem[]; + /** 指定下级代理ID */ + targetAgentId?: number; +} + +/** 恢复下级代理专属套餐定价项 */ +export interface TSimFlowPackagePriceAgentPackagePriceInheritItem { + /** 下级专属定价ID */ + targetPriceId?: number; + /** 套餐编码 */ + packageCode?: string; +} + +/** 恢复下级代理专属套餐定价 请求参数 */ +export interface TSimFlowPackagePriceAgentPackagePriceInheritParam { + /** 恢复项 */ + items?: TSimFlowPackagePriceAgentPackagePriceInheritItem[]; + /** 指定下级代理ID */ + targetAgentId?: number; +} + +/** 导出SIM流量套餐定价列表 请求参数 */ +export type TSimFlowPackagePriceExportParam = TSimFlowPackagePriceListParam; + +/** 修改/新增SIM流量套餐定价 请求参数 */ +export interface TSimFlowPackagePriceEditParam { + /** 主键ID */ + id?: number; + /** 套餐编码 */ + packageCode?: string; + /** 渠道适用类型:0-所有客户 1-指定客户 */ + agentScopeType?: number; + /** 指定渠道客户ID */ + targetAgentId?: number; + /** 机构编号 */ + deptId?: string; + /** 渠道成本系数 */ + agentCostRatio?: number; + /** 渠道成本利润 */ + agentCostProfit?: number; + /** 终端用户成本系数 */ + userCostRatio?: number; + /** 终端用户成本利润 */ + userCostProfit?: number; + /** 是否启用:0-否 1-是(yesno_enum) */ + enabled?: number; + /** 备注 */ + remark?: string; + /** 租户ID */ + tenantId?: string; + /** 创建部门ID */ + createdDept?: number; + /** 创建者ID */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者ID */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取SIM流量套餐定价指定信息 请求参数 */ +export interface TSimFlowPackagePriceViewParam { + /** 主键ID */ + id: number; +} + +/** 获取SIM流量套餐定价指定信息 响应 */ +export type TSimFlowPackagePriceViewRes = TSimFlowPackagePriceViewModel; + +/** 删除SIM流量套餐定价 请求参数 */ +export interface TSimFlowPackagePriceDeleteParam { + /** 主键ID */ + id: number | number[]; +} + +/** 获取渠道代理树形结构响应项 */ +export interface TSimFlowPackagePriceAgenttreeModel { + /** 节点ID */ + id?: number | string; + /** 代理ID */ + agentId?: number | string; + /** 组织ID */ + deptId?: number | string; + /** 树节点Key */ + key?: number | string; + /** 树节点标题 */ + title?: string; + /** 代理名称 */ + agentName?: string; + /** 组织名称 */ + deptName?: string; + /** 节点名称 */ + name?: string; + /** 上级ID */ + parentId?: number | string; + /** 子节点 */ + children?: TSimFlowPackagePriceAgenttreeModel[]; + /** 代理/公司树 */ + items?: TSimFlowPackagePriceAgenttreeModel[]; +} + +/** 获取渠道代理树形结构 响应 */ +export interface TSimFlowPackagePriceAgenttreeRes { + /** 代理/公司树 */ + items: TSimFlowPackagePriceAgenttreeModel[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/index.ts new file mode 100644 index 0000000..5892413 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/index.ts @@ -0,0 +1,57 @@ +import type { + TSimFlowPoolDeleteParam, + TSimFlowPoolEditParam, + TSimFlowPoolExportParam, + TSimFlowPoolListParam, + TSimFlowPoolListRes, + TSimFlowPoolViewParam, + TSimFlowPoolViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取流量池表列表 +export function List(params: TSimFlowPoolListParam) { + return requestClient.get('iot/tSimFlowPool/list', { + params, + }); +} + +// 删除/批量删除流量池表 +export function Delete(params: TSimFlowPoolDeleteParam) { + return requestClient.post('iot/tSimFlowPool/delete', { ...params }); +} + +// 添加/编辑流量池表 +export function Edit(params: TSimFlowPoolEditParam) { + return requestClient.post('iot/tSimFlowPool/edit', { ...params }); +} + +// 获取流量池表指定详情 +export function View(params: TSimFlowPoolViewParam) { + return requestClient.get('iot/tSimFlowPool/view', { + params, + }); +} + +// 导出流量池表 +export function Export(params: TSimFlowPoolExportParam) { + return requestClient.post( + '/iot/tSimFlowPool/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} + +// 根据套餐编码获取流量池下关联的卡列表 +export function GetCardsByPackageCodes(params: { packageCodes: string[] }) { + return requestClient.post( + '/iot/tSimFlowPool/getCardsByPackageCodes', + params, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/type.ts new file mode 100644 index 0000000..177b08c --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/type.ts @@ -0,0 +1,187 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 流量池表列表项 */ +export interface TSimFlowPoolModel { + /** 主键ID */ + id: number; + /** 流量池编号 */ + flowPoolCode: string; + /** 客户编号 */ + deptId: number; + /** 客户名称 */ + deptName: string; + /** 池套餐编码 */ + poolPackageCode: number; + /** 池套餐名称 */ + poolPackageName: string; + /** 关联卡数量 */ + cardCount: number; + /** 套餐卡流量MB */ + cardFlowMb: number; + /** 套内总流量MB */ + poolPackageFlowMb: number; + /** 加油包总流量MB */ + addOnFlowMb: number; + /** 总流量MB(套内+加油包) */ + totalFlowMb: number; + /** 已使用流量MB */ + usedFlowMb: number; + /** 剩余流量MB */ + remainFlowMb: number; + /** 状态:0 正常、1 停用、2 锁定 */ + poolStatus: number; + /** 备注 */ + remark: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取流量池表指定信息响应项 */ +export interface TSimFlowPoolViewModel { + /** 主键ID */ + id: number; + /** 流量池编号 */ + flowPoolCode: string; + /** 客户编号 */ + deptId: number; + /** 套餐编号列表(冗余) */ + packageCodes: string[]; + /** 池套餐编码 */ + poolPackageCode: number; + /** 关联卡数量 */ + cardCount: number; + /** 套餐卡流量MB */ + cardFlowMb: number; + /** 套内总流量MB */ + poolPackageFlowMb: number; + /** 加油包总流量MB */ + addOnFlowMb: number; + /** 总流量MB(套内+加油包) */ + totalFlowMb: number; + /** 已使用流量MB */ + usedFlowMb: number; + /** 剩余流量MB */ + remainFlowMb: number; + /** 状态:0 正常、1 停用、2 锁定 */ + poolStatus: number; + /** 备注 */ + remark: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 客户名称 */ + deptName: string; + /** 池套餐名称 */ + poolPackageName: string; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取流量池表列表 请求参数 */ +export interface TSimFlowPoolListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 主键ID */ + id?: number; + /** 状态:0 正常、1 停用、2 锁定 */ + poolStatus?: number; + /** 创建时间 */ + createdAt?: string[]; + /** 流量池编号 */ + flowPoolCode?: string; +} + +/** 获取流量池表列表 响应 */ +export type TSimFlowPoolListRes = GlobalListRes; + +/** 导出流量池表列表 请求参数 */ +export type TSimFlowPoolExportParam = TSimFlowPoolListParam; + +/** 修改/新增流量池表 请求参数 */ +export interface TSimFlowPoolEditParam { + /** 主键ID */ + id?: number; + /** 流量池编号 */ + flowPoolCode?: string; + /** 客户编号 */ + deptId?: number; + /** 套餐编号列表(冗余) */ + packageCodes?: string[]; + /** 池套餐编码 */ + poolPackageCode?: number; + /** 关联卡数量 */ + cardCount?: number; + /** 套餐卡流量MB */ + cardFlowMb?: number; + /** 套内总流量MB */ + poolPackageFlowMb?: number; + /** 加油包总流量MB */ + addOnFlowMb?: number; + /** 总流量MB(套内+加油包) */ + totalFlowMb?: number; + /** 已使用流量MB */ + usedFlowMb?: number; + /** 剩余流量MB */ + remainFlowMb?: number; + /** 状态:0 正常、1 停用、2 锁定 */ + poolStatus?: number; + /** 备注 */ + remark?: string; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取流量池表指定信息 请求参数 */ +export interface TSimFlowPoolViewParam { + /** 主键ID */ + id: number; +} + +/** 获取流量池表指定信息 响应 */ +export type TSimFlowPoolViewRes = TSimFlowPoolViewModel; + +/** 删除流量池表 请求参数 */ +export interface TSimFlowPoolDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/index.ts new file mode 100644 index 0000000..6d03714 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/index.ts @@ -0,0 +1,53 @@ +import type { + TSimPackageCategoryDeleteParam, + TSimPackageCategoryEditParam, + TSimPackageCategoryExportParam, + TSimPackageCategoryListParam, + TSimPackageCategoryListRes, + TSimPackageCategoryViewParam, + TSimPackageCategoryViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取套餐分类表列表 +export function List(params: TSimPackageCategoryListParam) { + return requestClient.get( + 'iot/tSimPackageCategory/list', + { params }, + ); +} + +// 删除/批量删除套餐分类表 +export function Delete(params: TSimPackageCategoryDeleteParam) { + return requestClient.post('iot/tSimPackageCategory/delete', { ...params }); +} + +// 添加/编辑套餐分类表 +export function Edit(params: TSimPackageCategoryEditParam) { + return requestClient.post('iot/tSimPackageCategory/edit', { ...params }); +} + +// 获取套餐分类表指定详情 +export function View(params: TSimPackageCategoryViewParam) { + return requestClient.get( + 'iot/tSimPackageCategory/view', + { + params, + }, + ); +} + +// 导出套餐分类表 +export function Export(params: TSimPackageCategoryExportParam) { + return requestClient.post( + '/iot/tSimPackageCategory/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/type.ts new file mode 100644 index 0000000..5a014ae --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/type.ts @@ -0,0 +1,95 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 套餐分类表列表项 */ +export interface TSimPackageCategoryModel { + /** 主键ID */ + id: number; + /** 套餐分类编号 */ + categoryCode: string; + /** 套餐分类名称 */ + categoryName: string; + /** 排序 */ + sortNo: number; + /** 是否启用 */ + enabled: number; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取套餐分类表列表 请求参数 */ +export interface TSimPackageCategoryListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 套餐分类编号 */ + categoryCode?: string; + /** 套餐分类名称 */ + categoryName?: string; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取套餐分类表列表 响应 */ +export type TSimPackageCategoryListRes = GlobalListRes; + +/** 导出套餐分类表列表 请求参数 */ +export type TSimPackageCategoryExportParam = TSimPackageCategoryListParam; + +/** 修改/新增套餐分类表 请求参数 */ +export interface TSimPackageCategoryEditParam { + /** 主键ID */ + id?: number; + /** 套餐分类编号 */ + categoryCode?: string; + /** 套餐分类名称 */ + categoryName?: string; + /** 排序 */ + sortNo?: number; + /** 是否启用 */ + enabled?: number; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取套餐分类表指定信息 请求参数 */ +export interface TSimPackageCategoryViewParam { + /** 主键ID */ + id: number; +} + +/** 获取套餐分类表指定信息 响应 */ +export type TSimPackageCategoryViewRes = TSimPackageCategoryModel; + +/** 删除套餐分类表 请求参数 */ +export interface TSimPackageCategoryDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/index.ts new file mode 100644 index 0000000..6414fff --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/index.ts @@ -0,0 +1,53 @@ +import type { + TSimUpstreamPackageDeleteParam, + TSimUpstreamPackageEditParam, + TSimUpstreamPackageExportParam, + TSimUpstreamPackageListParam, + TSimUpstreamPackageListRes, + TSimUpstreamPackageViewParam, + TSimUpstreamPackageViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取上游套餐表列表 +export function List(params: TSimUpstreamPackageListParam) { + return requestClient.get( + 'iot/tSimUpstreamPackage/list', + { params }, + ); +} + +// 删除/批量删除上游套餐表 +export function Delete(params: TSimUpstreamPackageDeleteParam) { + return requestClient.post('iot/tSimUpstreamPackage/delete', { ...params }); +} + +// 添加/编辑上游套餐表 +export function Edit(params: TSimUpstreamPackageEditParam) { + return requestClient.post('iot/tSimUpstreamPackage/edit', { ...params }); +} + +// 获取上游套餐表指定详情 +export function View(params: TSimUpstreamPackageViewParam) { + return requestClient.get( + 'iot/tSimUpstreamPackage/view', + { + params, + }, + ); +} + +// 导出上游套餐表 +export function Export(params: TSimUpstreamPackageExportParam) { + return requestClient.post( + '/iot/tSimUpstreamPackage/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/type.ts new file mode 100644 index 0000000..d75fc57 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/type.ts @@ -0,0 +1,97 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 上游套餐表列表项 */ +export interface TSimUpstreamPackageModel { + /** 主键 */ + id: number; + /** 上游套餐编码 */ + upPkgCode: string; + /** 上游套餐名称 */ + upPkgName: string; + /** 运营商:1移动,2联通,3电信 */ + operator: number; + /** APN名称 */ + apnName: string; + /** 备注 */ + remark: string; + /** 创建部门 */ + createdDept: number; + /** 创建时间 */ + createdAt: string; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取上游套餐表列表 请求参数 */ +export interface TSimUpstreamPackageListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 上游套餐编码 */ + upPkgCode?: string; + /** 上游套餐名称 */ + upPkgName?: string; + /** 运营商:1移动,2联通,3电信 */ + operator?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取上游套餐表列表 响应 */ +export type TSimUpstreamPackageListRes = GlobalListRes; + +/** 导出上游套餐表列表 请求参数 */ +export type TSimUpstreamPackageExportParam = TSimUpstreamPackageListParam; + +/** 修改/新增上游套餐表 请求参数 */ +export interface TSimUpstreamPackageEditParam { + /** 主键 */ + id?: number; + /** 上游套餐编码 */ + upPkgCode?: string; + /** 上游套餐名称 */ + upPkgName?: string; + /** 运营商:1移动,2联通,3电信 */ + operator?: number; + /** APN名称 */ + apnName?: string; + /** 备注 */ + remark?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建时间 */ + createdAt?: string; + /** 创建者 */ + createdBy?: number; + /** 更新时间 */ + updatedAt?: string; + /** 更新者 */ + updatedBy?: number; +} + +/** 获取上游套餐表指定信息 请求参数 */ +export interface TSimUpstreamPackageViewParam { + /** 主键 */ + id: number; +} + +/** 获取上游套餐表指定信息 响应 */ +export type TSimUpstreamPackageViewRes = TSimUpstreamPackageModel; + +/** 删除上游套餐表 请求参数 */ +export interface TSimUpstreamPackageDeleteParam { + /** 主键ID */ + id: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/index.ts new file mode 100644 index 0000000..3876b57 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/index.ts @@ -0,0 +1,30 @@ +import type { + SimDiagnoseFlowParam, + SimDiagnoseFlowRes, + SimDiagnoseInfoParam, + SimDiagnoseInfoRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +const silentErrorConfig = { + errorMessageMode: 'none', +} as const; + +// 获取卡诊断信息(基本信息、会话信息、套餐信息) +export function GetSimDiagnoseInfo(params: SimDiagnoseInfoParam) { + return requestClient.post( + '/iot/tSimdiagnose/info', + params, + silentErrorConfig, + ); +} + +// 获取卡流量数据 +export function GetSimDiagnoseFlow(params: SimDiagnoseFlowParam) { + return requestClient.post( + '/iot/tSimdiagnose/flow', + params, + silentErrorConfig, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/type.ts new file mode 100644 index 0000000..112b5c8 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/type.ts @@ -0,0 +1,160 @@ +// 卡诊断信息接口 +export interface SimDiagnoseInfoParam { + /** 查询码:ICCID / MSISDN / IMSI */ + queryCode: string; + onlyFlow?: boolean; +} + +export interface SimDiagnoseModuleItem { + reason?: string; + /** 状态:success / error / cached / skipped */ + status: 'cached' | 'error' | 'skipped' | 'success' | string; + /** 状态说明 */ + message?: string; + /** 是否使用缓存 */ + cached?: boolean; + /** 缓存更新时间 */ + updatedAt?: string; +} + +export interface SimDiagnoseRateLimitPccItem { + pccServiceCode?: string; + pccName?: string; + pccPolicyStatus?: string; + pccServiceUsageState?: string; + modifyTime?: string; +} + +export interface SimDiagnoseRateLimitApnItem { + apnName?: string; + apnStatus?: string; + modifyTime?: string; + overUseDetails?: string; + apnServiceUsageState?: string; + pccDetails?: SimDiagnoseRateLimitPccItem[]; +} + +// 卡信息 +export interface SimDiagnoseInfo { + /** ICCID */ + iccid?: string; + /** IMSI */ + imsi?: string; + /** MSISDN */ + msisdn?: string; + /** 卡状态:0未知 1待激活 2已激活 4已停机 6可测试 7库存 8预销户 9已销户 */ + status?: string; + /** 数据状态:0关闭/停用 1开启/启用 */ + dataStatus?: string; + dataServiceSource?: 'apn' | 'network_block'; + netBlockStatus?: string; + netBlockReason?: string; + /** 在线状态:0离线 1在线 2未知 */ + onlineStatus?: string; + /** 终端开关机状态:0关机 1开机 */ + operatingStatus?: string; + /** 设备状态:0异常/不可用 1正常 */ + deviceStatus?: string; + /** 机卡状态:0异常/机卡分离 1正常 2未知 */ + imeiStatus?: string; + /** 区域限制状态:0受限/已触发 1正常/未触发 2未知 */ + regionLimitStatus?: string; + /** 区域限制订购状态:0已订购 1未订购 */ + regionLimitOrderStatus?: string; + /** 区域限制触发状态:0已断网 1未断网 2未知 */ + regionLimitTriggerStatus?: string; + /** 区域限制类型 */ + regionLimitType?: string; + /** 限制区域 */ + regionLimitArea?: string; + /** 人联网限制状态:0限制 1正常 2未知 3运营商暂不支持 */ + humanLimitStatus?: string; + /** 达量限速状态:0已触发 1未触发 2未知 3运营商暂不支持 */ + rateLimitStatus?: string; + /** 达量限速原因 */ + rateLimitReason?: string; + /** 达量限速明细 */ + rateLimitDetail?: string; + /** APN达量限速明细 */ + rateLimitApnDetails?: SimDiagnoseRateLimitApnItem[]; + /** 套餐总流量 MB */ + packageTotalFlowMb?: number; + /** 已用流量 MB */ + usedFlowMb?: number; + /** 剩余流量 MB */ + remainFlowMb?: number; + /** 流量同步时间 */ + flowSyncTime?: string; + /** 停机原因 */ + stopReason?: string; + /** 冻结状态 */ + frozenStatus?: string; + /** 冻结原因 */ + frozenReason?: string; + /** 冻结时间 */ + frozenOperTime?: string; +} + +// 会话信息 +export interface SimDiagnoseSession { + /** APN */ + apnId?: string; + /** 近30天最新终端使用 IMEI */ + imei?: string; + /** 接入方式 */ + rat?: string; + /** IPV4 */ + ipv4?: string; + /** IPV6 */ + ipv6?: string; + /** IPV6 前缀 */ + ipv6Prefix?: string; + /** 会话状态:0在线 -1离线 -2未查询到会话 */ + status?: string; + /** 会话创建时间 */ + createTime?: string; +} + +// 套餐信息 +export interface SimDiagnosePackage { + /** 套餐名称 */ + packageName?: string; + /** 套餐类型 */ + packageType?: string; + /** 生效状态:0待生效 1生效中 2已过期 3已终止 4已作废 */ + effectiveStatus?: string; + /** 套餐总流量 MB */ + packageTotalFlowMb?: number; + /** 套餐时长(月) */ + durationMonths?: number; + /** 预计到期时间 */ + expectedExpireTime?: string; +} + +// 卡诊断信息响应 +export interface SimDiagnoseInfoRes { + info: null | SimDiagnoseInfo; + modules?: Record; + package: null | SimDiagnosePackage; + session: null | SimDiagnoseSession; +} + +// 流量查询参数 +export interface SimDiagnoseFlowParam { + /** 查询码:ICCID / MSISDN / IMSI */ + queryCode: string; + /** 查询类型:7d近7天、30d近30天、6M近6个月 */ + queryType: '6M' | '7d' | '30d'; +} + +// 流量查询响应 +export interface SimDiagnoseFlowRes { + /** 时间节点 */ + times: string[]; + /** 流量数据 */ + flow: number[]; + /** 各时间节点是否存在采集记录 */ + flowAvailable?: boolean[]; + /** 流量单位:MB / GB */ + unit: string; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/index.ts new file mode 100644 index 0000000..cd32871 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/index.ts @@ -0,0 +1,41 @@ +import type { + SimWarningConfigDeleteParam, + SimWarningConfigListParam, + SimWarningConfigListRes, + SimWarningConfigSaveParam, + SimWarningConfigSaveRes, + SimWarningConfigStatusParam, + SimWarningConfigViewParam, + SimWarningConfigViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +export function List(params: SimWarningConfigListParam) { + return requestClient.get( + '/iot/simWarningConfig/list', + { params }, + ); +} + +export function View(params: SimWarningConfigViewParam) { + return requestClient.get( + '/iot/simWarningConfig/view', + { params }, + ); +} + +export function Save(params: SimWarningConfigSaveParam) { + return requestClient.post( + '/iot/simWarningConfig/save', + { ...params }, + ); +} + +export function Status(params: SimWarningConfigStatusParam) { + return requestClient.post('/iot/simWarningConfig/status', { ...params }); +} + +export function Delete(params: SimWarningConfigDeleteParam) { + return requestClient.post('/iot/simWarningConfig/delete', { ...params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts new file mode 100644 index 0000000..2d6f71a --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts @@ -0,0 +1,80 @@ +import type { GlobalListRes } from '#/types/global'; + +export interface SimWarningConfigModel { + id: number; + tenantId?: string; + itemType: number; + itemId: number; + itemCode: string; + batchNo?: string; + warnType?: number; + warnUnit: number; + firstWarn?: number; + secondWarn?: number; + thirdWarn?: number; + warnMethods?: string; + warnPhones?: string; + warnEmails?: string; + autoAction?: number; + + isEnabled: number; + wxTemplateId?: string; + remark?: string; + createdDept?: number; + createdBy?: number; + createdAt?: string; + updatedBy?: number; + updatedAt?: string; +} + +export interface SimWarningConfigListParam { + page?: number; + pageSize?: number; + keyword?: string; + id?: number; + itemType?: number; + itemId?: number; + itemCode?: string; + warnUnit?: number; + isEnabled?: number; +} + +export type SimWarningConfigListRes = GlobalListRes; + +export interface SimWarningConfigViewParam { + id: number; +} + +export type SimWarningConfigViewRes = SimWarningConfigModel; + +export interface SimWarningConfigSaveParam { + id?: number; + itemType: number; + itemId?: number; + itemCode: string; + batchNo?: string; + warnUnit: number; + firstWarn: number; + secondWarn?: number; + thirdWarn?: number; + warnMethods?: string; + warnPhones?: string; + warnEmails?: string; + autoAction?: number; + + isEnabled?: number; + remark?: string; +} + +export interface SimWarningConfigSaveRes { + id: number; +} + +export interface SimWarningConfigStatusParam { + id: number; + isEnabled: number; +} + +export interface SimWarningConfigDeleteParam { + id: number; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/index.ts new file mode 100644 index 0000000..f7ebdfd --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/index.ts @@ -0,0 +1,53 @@ +import type { + TAgentEnterpriseDeleteParam, + TAgentEnterpriseEditParam, + TAgentEnterpriseExportParam, + TAgentEnterpriseListParam, + TAgentEnterpriseListRes, + TAgentEnterpriseViewParam, + TAgentEnterpriseViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取企业客户单位信息列表 +export function List(params: TAgentEnterpriseListParam) { + return requestClient.get( + 'agent/tAgentEnterprise/list', + { params }, + ); +} + +// 删除/批量删除企业客户单位信息 +export function Delete(params: TAgentEnterpriseDeleteParam) { + return requestClient.post('agent/tAgentEnterprise/delete', { ...params }); +} + +// 添加/编辑企业客户单位信息 +export function Edit(params: TAgentEnterpriseEditParam) { + return requestClient.post('agent/tAgentEnterprise/edit', { ...params }); +} + +// 获取企业客户单位信息指定详情 +export function View(params: TAgentEnterpriseViewParam) { + return requestClient.get( + 'agent/tAgentEnterprise/view', + { + params, + }, + ); +} + +// 导出企业客户单位信息 +export function Export(params: TAgentEnterpriseExportParam) { + return requestClient.post( + '/agent/tAgentEnterprise/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/type.ts new file mode 100644 index 0000000..9f39131 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/type.ts @@ -0,0 +1,113 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 企业客户单位信息列表项 */ +export interface TAgentEnterpriseModel { + /** 主键ID */ + id: number; + /** 部门机构id */ + deptId: number; + /** 单位全称 */ + fullName: string; + /** 行业 */ + industry: string; + /** 法人名称 */ + legalPersonName: string; + /** 法人身份证号 */ + legalPersonIdCard: string; + /** 单位类型 */ + companyType: string; + /** 单位成立时间 */ + establishTime: string; + /** 开户行名称 */ + bankName: string; + /** 开户行账号 */ + bankAccount: string; + /** 租户ID */ + tenantId: string; + /** 创建部门 */ + createdDept: number; + /** 创建者 */ + createdBy: number; + /** 创建者摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者 */ + updatedBy: number; + /** 更新者摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取企业客户单位信息列表 请求参数 */ +export interface TAgentEnterpriseListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 主键ID */ + id?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取企业客户单位信息列表 响应 */ +export type TAgentEnterpriseListRes = GlobalListRes; + +/** 导出企业客户单位信息列表 请求参数 */ +export type TAgentEnterpriseExportParam = TAgentEnterpriseListParam; + +/** 修改/新增企业客户单位信息 请求参数 */ +export interface TAgentEnterpriseEditParam { + /** 主键ID */ + id?: number; + /** 部门机构id */ + deptId?: number; + /** 单位全称 */ + fullName?: string; + /** 行业 */ + industry?: string; + /** 法人名称 */ + legalPersonName?: string; + /** 法人身份证号 */ + legalPersonIdCard?: string; + /** 单位类型 */ + companyType?: string; + /** 单位成立时间 */ + establishTime?: string; + /** 开户行名称 */ + bankName?: string; + /** 开户行账号 */ + bankAccount?: string; + /** 租户ID */ + tenantId?: string; + /** 创建部门 */ + createdDept?: number; + /** 创建者 */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者 */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取企业客户单位信息指定信息 请求参数 */ +export interface TAgentEnterpriseViewParam { + /** 部门机构id */ + deptId: number; +} + +/** 获取企业客户单位信息指定信息 响应 */ +export type TAgentEnterpriseViewRes = TAgentEnterpriseModel; + +/** 删除企业客户单位信息 请求参数 */ +export interface TAgentEnterpriseDeleteParam { + /** 部门机构id */ + deptId: number; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/index.ts new file mode 100644 index 0000000..15c9fd5 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/index.ts @@ -0,0 +1,53 @@ +import type { + TCustWithdrawAccountDeleteParam, + TCustWithdrawAccountEditParam, + TCustWithdrawAccountExportParam, + TCustWithdrawAccountListParam, + TCustWithdrawAccountListRes, + TCustWithdrawAccountViewParam, + TCustWithdrawAccountViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取客户提现账户表列表 +export function List(params: TCustWithdrawAccountListParam) { + return requestClient.get( + 'agent/tCustWithdrawAccount/list', + { params }, + ); +} + +// 删除/批量删除客户提现账户表 +export function Delete(params: TCustWithdrawAccountDeleteParam) { + return requestClient.post('agent/tCustWithdrawAccount/delete', { ...params }); +} + +// 添加/编辑客户提现账户表 +export function Edit(params: TCustWithdrawAccountEditParam) { + return requestClient.post('agent/tCustWithdrawAccount/edit', { ...params }); +} + +// 获取客户提现账户表指定详情 +export function View(params: TCustWithdrawAccountViewParam) { + return requestClient.get( + 'agent/tCustWithdrawAccount/view', + { + params, + }, + ); +} + +// 导出客户提现账户表 +export function Export(params: TCustWithdrawAccountExportParam) { + return requestClient.post( + '/agent/tCustWithdrawAccount/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/type.ts new file mode 100644 index 0000000..f8e89c6 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/type.ts @@ -0,0 +1,155 @@ +import type { GlobalListRes } from '#/types/global'; +import type { MemberSumma } from '#/utils'; + +/** 客户提现账户表列表项 */ +export interface TCustWithdrawAccountModel { + /** 主键ID */ + id: number; + /** 企业客户ID */ + deptId: number; + /** 提现账号类型,1:支付宝,2:微信 */ + accountType: number; + /** 账户名称/真实姓名 */ + accountName: string; + /** 手机号 */ + mobile: string; + /** 是否默认账号:0-否 1-是 */ + isDefault: number; + /** 是否启用:0-未启用 1-启用 */ + enabled: number; + /** 状态:0-禁用 1-正常 */ + status: number; + /** 租户ID */ + tenantId: string; + /** 创建部门ID */ + createdDept: number; + /** 创建者ID */ + createdBy: number; + /** 创建者ID摘要信息 */ + createdBySumma: MemberSumma; + /** 创建时间 */ + createdAt: string; + /** 更新者ID */ + updatedBy: number; + /** 更新者ID摘要信息 */ + updatedBySumma: MemberSumma; + /** 更新时间 */ + updatedAt: string; +} + +/** 获取客户提现账户表指定信息响应项 */ +export interface TCustWithdrawAccountViewModel { + /** 主键ID */ + id: number; + /** 企业客户ID */ + deptId: number; + /** 提现账号类型,1:支付宝,2:微信 */ + accountType: number; + /** 账号 */ + accountNo: string; + /** 账户名称/真实姓名 */ + accountName: string; + /** 手机号 */ + mobile: string; + /** 是否默认账号:0-否 1-是 */ + isDefault: number; + /** 是否启用:0-未启用 1-启用 */ + enabled: number; + /** 状态:0-禁用 1-正常 */ + status: number; + /** 租户ID */ + tenantId: string; + /** 创建部门ID */ + createdDept: number; + /** 创建者ID */ + createdBy: number; + /** 创建时间 */ + createdAt: string; + /** 更新者ID */ + updatedBy: number; + /** 更新时间 */ + updatedAt: string; + /** 创建者ID摘要信息 */ + createdBySumma: MemberSumma; + /** 更新者ID摘要信息 */ + updatedBySumma: MemberSumma; +} + +/** 获取客户提现账户表列表 请求参数 */ +export interface TCustWithdrawAccountListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 主键ID */ + id?: number; + /** 状态:0-禁用 1-正常 */ + status?: number; + /** 创建时间 */ + createdAt?: string[]; +} + +/** 获取客户提现账户表列表 响应 */ +export type TCustWithdrawAccountListRes = GlobalListRes; + +/** 导出客户提现账户表列表 请求参数 */ +export type TCustWithdrawAccountExportParam = TCustWithdrawAccountListParam; + +/** 修改/新增客户提现账户表 请求参数 */ +export interface TCustWithdrawAccountEditParam { + /** 主键ID */ + id?: number; + /** 企业客户ID */ + deptId?: number; + /** 提现账号类型,1:支付宝,2:微信 */ + accountType?: number; + /** 账号 */ + accountNo?: string; + /** 账户名称/真实姓名 */ + accountName?: string; + /** 手机号 */ + mobile?: string; + /** 是否默认账号:0-否 1-是 */ + isDefault?: number; + /** 是否启用:0-未启用 1-启用 */ + enabled?: number; + /** 状态:0-禁用 1-正常 */ + status?: number; + /** 租户ID */ + tenantId?: string; + /** 创建部门ID */ + createdDept?: number; + /** 创建者ID */ + createdBy?: number; + /** 创建时间 */ + createdAt?: string; + /** 更新者ID */ + updatedBy?: number; + /** 更新时间 */ + updatedAt?: string; +} + +/** 获取客户提现账户表指定信息 请求参数 */ +export interface TCustWithdrawAccountViewParam { + /** 主键ID */ + id: number; +} + +/** 获取客户提现账户表指定信息 响应 */ +export type TCustWithdrawAccountViewRes = TCustWithdrawAccountViewModel; + +/** 删除客户提现账户表 请求参数 */ +export interface TCustWithdrawAccountDeleteParam { + /** 主键ID */ + id: number | number[]; +} + +/** 更新客户提现账户表状态 请求参数 */ +export interface TCustWithdrawAccountStatusParam { + /** 主键ID */ + id: number; + /** 状态 */ + status?: number; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/index.ts new file mode 100644 index 0000000..d741c3c --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/index.ts @@ -0,0 +1,49 @@ +import type { + TDivisionCodeDeleteParam, + TDivisionCodeEditParam, + TDivisionCodeExportParam, + TDivisionCodeListParam, + TDivisionCodeListRes, + TDivisionCodeViewParam, + TDivisionCodeViewRes, +} from './type'; + +import { requestClient } from '#/api/request'; + +// 获取村级行政区划表列表 +export function List(params: TDivisionCodeListParam) { + return requestClient.get('common/tDivisionCode/list', { + params, + }); +} + +// 删除/批量删除村级行政区划表 +export function Delete(params: TDivisionCodeDeleteParam) { + return requestClient.post('common/tDivisionCode/delete', { ...params }); +} + +// 添加/编辑村级行政区划表 +export function Edit(params: TDivisionCodeEditParam) { + return requestClient.post('common/tDivisionCode/edit', { ...params }); +} + +// 获取村级行政区划表指定详情 +export function View(params: TDivisionCodeViewParam) { + return requestClient.get('common/tDivisionCode/view', { + params, + }); +} + +// 导出村级行政区划表 +export function Export(params: TDivisionCodeExportParam) { + return requestClient.post( + '/common/tDivisionCode/export', + { ...params }, + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', + }, + responseType: 'blob', + }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/type.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/type.ts new file mode 100644 index 0000000..1d28dff --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/type.ts @@ -0,0 +1,72 @@ +import type { GlobalListRes } from '#/types/global'; + +/** 村级行政区划表列表项 */ +export interface TDivisionCodeModel { + /** ID */ + regionId: number; + /** 行政区域代码 */ + regionCode: string; + /** 行政区域名称 */ + regionName: string; + /** 等级 */ + regionLevel: number; + /** 上级代码 */ + regionParent: string; + /** 城乡分类代码 */ + regionType: string; +} + +/** 获取村级行政区划表列表 请求参数 */ +export interface TDivisionCodeListParam { + /** 页码 */ + page?: number; + /** 每页大小 */ + pageSize?: number; + /** 关键字 */ + keyword?: string; + /** 行政区域名称 */ + regionName?: string; + /** 行政区域代码 */ + regionCode?: string; + /** 等级 */ + regionLevel?: number; + /** 上级代码 */ + regionParent?: string; +} + +/** 获取村级行政区划表列表 响应 */ +export type TDivisionCodeListRes = GlobalListRes; + +/** 导出村级行政区划表列表 请求参数 */ +export type TDivisionCodeExportParam = TDivisionCodeListParam; + +/** 修改/新增村级行政区划表 请求参数 */ +export interface TDivisionCodeEditParam { + /** ID */ + regionId?: number; + /** 行政区域代码 */ + regionCode?: string; + /** 行政区域名称 */ + regionName?: string; + /** 等级 */ + regionLevel?: number; + /** 上级代码 */ + regionParent?: string; + /** 城乡分类代码 */ + regionType?: string; +} + +/** 获取村级行政区划表指定信息 请求参数 */ +export interface TDivisionCodeViewParam { + /** ID */ + regionId: number; +} + +/** 获取村级行政区划表指定信息 响应 */ +export type TDivisionCodeViewRes = TDivisionCodeModel; + +/** 删除村级行政区划表 请求参数 */ +export interface TDivisionCodeDeleteParam { + /** regionId */ + regionId: number | number[]; +} diff --git a/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tTplatformSetting/index.ts b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tTplatformSetting/index.ts new file mode 100644 index 0000000..4aba3f2 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/iotlcm/zAnother/tTplatformSetting/index.ts @@ -0,0 +1,39 @@ +import { requestClient } from '#/api/request'; + +// 获取二级域名站点个性化配置表列表 +export function List(params:any) { + return requestClient.get('system/tTplatformSetting/list', { params }); +} + +// 删除/批量删除二级域名站点个性化配置表 +export function Delete(params:any) { + return requestClient.post('system/tTplatformSetting/delete', { ...params }); +} + +// 添加/编辑二级域名站点个性化配置表 +export function Edit(params:any) { + return requestClient.post('system/tTplatformSetting/edit', { ...params }); +} + +// 修改二级域名站点个性化配置表状态 +export function Status(params:any) { + return requestClient.post('system/tTplatformSetting/status', { ...params }); +} + +// 获取二级域名站点个性化配置表指定详情 +export function View(params:any) { + return requestClient.get('system/tTplatformSetting/view', { params }); +} + +// 获取二级域名站点个性化配置表最大排序 +export function MaxSort(params:any) { + return requestClient.get('system/tTplatformSetting/maxSort', { params }); +} + +// 导出二级域名站点个性化配置表 +export function Export(params:any) { + return requestClient.post('/system/tTplatformSetting/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/monitor/cache.ts b/admin-ui/vue/apps/web-antd/src/api/monitor/cache.ts new file mode 100644 index 0000000..cbfc13b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/monitor/cache.ts @@ -0,0 +1,35 @@ +/** + * @description 缓存监控相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface CommandStats { + name: string; + value: string; +} + +export interface RedisInfo { + [key: string]: string; +} + +export interface CacheInfo { + commandStats: CommandStats[]; + dbSize: number; + info: RedisInfo; +} + +export async function redisCacheInfo() { + return requestClient.get('/monitor/cache'); +} + +export async function rebuildMemoryCache() { + return requestClient.post<{ tables: number }>( + '/monitor/cache/memory/rebuild', + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/monitor/full-sync.test.ts b/admin-ui/vue/apps/web-antd/src/api/monitor/full-sync.test.ts new file mode 100644 index 0000000..80fcf86 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/monitor/full-sync.test.ts @@ -0,0 +1,140 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +const get = vi.fn(); +const post = vi.fn(); + +vi.mock('#/api/request', () => ({ + requestClient: { get, post }, +})); + +describe('full-sync monitor api', () => { + beforeEach(() => { + get.mockReset(); + post.mockReset(); + }); + + it.each([ + 'traffic_usage', + 'sim_status', + 'imei', + 'traffic_usage_daily', + 'traffic_usage_monthly', + ] as const)( + 'queries runs for %s with the selected limit', + async (syncKind) => { + const { listFullSyncRuns } = await import('./full-sync'); + listFullSyncRuns({ syncKind, limit: 50 }); + + expect(get).toHaveBeenCalledWith('/iot/fullSyncRuns', { + params: { syncKind, limit: 50 }, + }); + }, + ); + + it('starts the requested sync kind', async () => { + const { startFullSync } = await import('./full-sync'); + startFullSync('sim_status'); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/start', { + syncKind: 'sim_status', + channels: undefined, + }); + }); + + it('starts the daily usage sync kind', async () => { + const { startFullSync } = await import('./full-sync'); + startFullSync('traffic_usage_daily'); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/start', { + syncKind: 'traffic_usage_daily', + channels: undefined, + }); + }); + + it('starts the monthly usage history sync kind', async () => { + const { startFullSync } = await import('./full-sync'); + startFullSync('traffic_usage_monthly'); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/start', { + syncKind: 'traffic_usage_monthly', + channels: undefined, + }); + }); + + it('starts the IMEI sync kind with a channel scope', async () => { + const { startFullSync } = await import('./full-sync'); + startFullSync('imei', ['217']); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/start', { + syncKind: 'imei', + channels: ['217'], + }); + }); + + it.each([3, 12, 100])( + 'passes a nonzero replay budget of %i unchanged', + async (maxRounds) => { + const { replayFullSync } = await import('./full-sync'); + replayFullSync('source-run-1', maxRounds); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/replay', { + sourceRunId: 'source-run-1', + maxRounds, + }); + }, + ); + + it('omits a zero replay budget to use the server default', async () => { + const { replayFullSync } = await import('./full-sync'); + replayFullSync('source-run-1', 0); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/replay', { + sourceRunId: 'source-run-1', + }); + }); + + it('fetches replay status through the admin API', async () => { + const { getFullSyncReplay } = await import('./full-sync'); + getFullSyncReplay('replay:run/1'); + + expect(get).toHaveBeenCalledWith( + '/iot/fullSyncRuns/replay/replay%3Arun%2F1', + ); + }); + + it('sends the channel scope for a partial sync', async () => { + const { startFullSync } = await import('./full-sync'); + startFullSync('traffic_usage', ['217', '173']); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/start', { + syncKind: 'traffic_usage', + channels: ['217', '173'], + }); + }); + + it('omits an empty channel scope so it stays a full sync', async () => { + const { startFullSync } = await import('./full-sync'); + startFullSync('traffic_usage', []); + + expect(post).toHaveBeenCalledWith('/iot/fullSyncRuns/start', { + syncKind: 'traffic_usage', + channels: undefined, + }); + }); + + it('loads the channel candidates for the start dialog', async () => { + const { listFullSyncChannels } = await import('./full-sync'); + listFullSyncChannels(); + + expect(get).toHaveBeenCalledWith('/iot/fullSyncRuns/channels'); + }); + + it('keeps failure pagination opaque to the caller', async () => { + const { listFullSyncFailures } = await import('./full-sync'); + listFullSyncFailures('run-1', { limit: 100, cursor: 'opaque-token' }); + + expect(get).toHaveBeenCalledWith('/iot/fullSyncRuns/run-1/failures', { + params: { limit: 100, cursor: 'opaque-token' }, + }); + }); +}); diff --git a/admin-ui/vue/apps/web-antd/src/api/monitor/full-sync.ts b/admin-ui/vue/apps/web-antd/src/api/monitor/full-sync.ts new file mode 100644 index 0000000..a57c398 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/monitor/full-sync.ts @@ -0,0 +1,170 @@ +import { requestClient } from '#/api/request'; + +export type FullSyncKind = + | 'traffic_usage' + | 'traffic_usage_daily' + | 'traffic_usage_monthly' + | 'sim_status' + | 'imei'; + +export interface FullSyncRunMeta { + runId: string; + operation: string; + queryMonth?: string; + status: string; + currentRound: number; + activeCount: number; + inflightCount: number; + nextRoundCount: number; + successCount: number; + failedCount: number; + createdAt?: string; + producerCompletedAt?: string; + completedAt?: string; + syncType?: string; + sourceRunId?: string; + replayCycle?: number; + triggerSource?: string; + scannedCount?: number; + enqueuedCount?: number; + upstreamAttemptCount?: number; + batchCount?: number; + maxRound?: number; + pendingFailureCount?: number; + startedAt?: string; + archiveStatus?: string; + archivedAt?: string; + // scopeChannels is 0 for a full sync. + scopeChannels?: number; + scopeDigest?: string; + scopeChannelsSample?: string; +} + +export interface FullSyncRoundStats { + runId: string; + round: number; + enqueuedCount: number; + activeCount: number; + nextRoundCount: number; + successCount: number; + failedCount: number; + upstreamAttemptCount: number; + batchCount: number; + startedAt?: string; + completedAt?: string; +} + +export interface FullSyncRunView { + source: 'live' | 'archive'; + run: FullSyncRunMeta; + rounds?: FullSyncRoundStats[]; + syncKind?: FullSyncKind; + syncName?: string; +} + +export interface FullSyncRunListResult { + items: FullSyncRunView[]; + total: number; +} + +export interface FullSyncFailure { + taskId: string; + cardId: number; + errorCategory: string; + errorMessage: string; + failedAt: string; + round: number; +} + +export interface FullSyncFailurePage { + items: FullSyncFailure[]; + nextCursor?: string; +} + +export interface FullSyncStartResult { + runId: string; + syncKind: FullSyncKind; + status: string; + scopeChannels: number; +} + +export interface FullSyncChannelOption { + chanKey: string; + chanName: string; + tempKey: string; + operator: number; + cardCount: number; + syncEnabled: boolean; +} + +export interface FullSyncChannelOptionsResult { + items: FullSyncChannelOption[]; +} + +export interface FullSyncReplayResult { + replayRunId: string; + status: string; +} + +export interface FullSyncReplayStatus extends FullSyncReplayResult { + sourceRunId: string; + remaining: number; + enqueued: number; + runStatus?: string; + error?: string; +} + +export function listFullSyncRuns(params?: { + syncKind?: FullSyncKind; + limit?: number; +}) { + return requestClient.get('/iot/fullSyncRuns', { + params, + }); +} + +export function getFullSyncRun(runId: string) { + return requestClient.get( + `/iot/fullSyncRuns/${encodeURIComponent(runId)}`, + ); +} + +export function listFullSyncFailures( + runId: string, + params?: { limit?: number; cursor?: string }, +) { + return requestClient.get( + `/iot/fullSyncRuns/${encodeURIComponent(runId)}/failures`, + { params }, + ); +} + +export function startFullSync(syncKind: FullSyncKind, channels?: string[]) { + return requestClient.post('/iot/fullSyncRuns/start', { + syncKind, + // Omit or send an empty list for a full sync. + channels: channels && channels.length > 0 ? channels : undefined, + }); +} + +export function replayFullSync(sourceRunId: string, maxRounds = 0) { + return requestClient.post('/iot/fullSyncRuns/replay', { + sourceRunId, + // Zero uses the Worker's configured default; positive budgets pass through. + ...(maxRounds === 0 ? {} : { maxRounds }), + }); +} + +export function getFullSyncReplay(replayRunId: string) { + return requestClient.get( + `/iot/fullSyncRuns/replay/${encodeURIComponent(replayRunId)}`, + ); +} + +// listFullSyncChannels returns the channels a partial sync can target, with +// their card counts, so the operator can judge the impact before selecting. +export function listFullSyncChannels() { + return requestClient.get( + '/iot/fullSyncRuns/channels', + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/monitor/index.ts b/admin-ui/vue/apps/web-antd/src/api/monitor/index.ts new file mode 100644 index 0000000..acc6496 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/monitor/index.ts @@ -0,0 +1,11 @@ +/** + * @description 监控模块接口导出 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +export * from './cache'; +export * from './full-sync'; diff --git a/admin-ui/vue/apps/web-antd/src/api/monitor/online.ts b/admin-ui/vue/apps/web-antd/src/api/monitor/online.ts new file mode 100644 index 0000000..7e47af3 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/monitor/online.ts @@ -0,0 +1,57 @@ +/** + * @description 在线用户监控相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysUserOnlineListReq { + page: number; + pageSize: number; + ipaddr: string; + userName: string; + status: string; +} + +export interface SysUserOnline { + onlineId: number; + tenantId: string; + uuid: string; + userName: string; + clientKey: string; + deviceType: string; + ipaddr: string; + loginLocation: string; + browser: string; + os: string; + token: string; + loginTime: string; + expireTime: string; +} + +export interface SysUserOnlineListRes { + items: SysUserOnline[]; + total: number; +} + +export interface SysUserOnlineDeleteReq { + ids: number[]; +} + +export interface SysUserOnlineDeleteRes { +} + +export const getSysUserOnlineListApi = (params: SysUserOnlineListReq) => { + return requestClient.get('/system/user-online/list', { params }); +}; + +export const deleteSysUserOnlineApi = (params: SysUserOnlineDeleteReq) => { + return requestClient.post('/system/user-online/delete', { ...params }); +}; + + + diff --git a/admin-ui/vue/apps/web-antd/src/api/regions/index.ts b/admin-ui/vue/apps/web-antd/src/api/regions/index.ts new file mode 100644 index 0000000..8b7388c --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/regions/index.ts @@ -0,0 +1,11 @@ +import { requestClient } from '#/api/request'; + +// 获取行政区划列表 +export function List(params:any) { + return requestClient.get('regions/iotRegions/list', { params }); +} + +// 获取指定省份下行政区划树形结构 +export function Tree(params:any) { + return requestClient.get('regions/iotRegions/tree', { params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/request.ts b/admin-ui/vue/apps/web-antd/src/api/request.ts new file mode 100644 index 0000000..122c3d7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/request.ts @@ -0,0 +1,230 @@ +/** + * @description 请求客户端配置 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import type { RequestClientOptions, HttpResponse } from '@vben/request'; + +import { useAppConfig } from '@vben/hooks'; +import { preferences } from '@vben/preferences'; +import { + authenticateResponseInterceptor, + errorMessageResponseInterceptor, + RequestClient, +} from '@vben/request'; +import { useAccessStore } from '@vben/stores'; + +import { message, Modal } from 'ant-design-vue'; + +import { useAuthStore } from '#/store'; + +import { refreshTokenApi } from './core'; + +import { $t } from '@vben/locales'; +import { isEmpty, isNull } from 'lodash-es'; + +const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); + +/** + * 是否已经处在登出过程中了 一个标志位 + * 主要是防止一个页面会请求多个api 都401 会导致登出执行多次 + */ +let isLogoutProcessing = false; + +function createRequestClient(baseURL: string, options?: RequestClientOptions) { + const client = new RequestClient({ + ...options, + baseURL, + // 消息提示类型 + errorMessageMode: 'message', + // 是否返回原生响应 比如:需要获取响应头时使用该属性 + isReturnNativeResponse: false, + // 需要对返回数据进行处理 + isTransformResponse: true, + }); + + /** + * 重新认证逻辑 + */ + async function doReAuthenticate() { + console.warn('Access token or refresh token is invalid or expired. '); + const accessStore = useAccessStore(); + const authStore = useAuthStore(); + accessStore.setAccessToken(null); + if ( + preferences.app.loginExpiredMode === 'modal' && + accessStore.isAccessChecked + ) { + accessStore.setLoginExpired(true); + } else { + await authStore.logout(); + } + } + + /** + * 刷新token逻辑 + */ + async function doRefreshToken() { + const accessStore = useAccessStore(); + const resp = await refreshTokenApi(); + const newToken = resp.data; + accessStore.setAccessToken(newToken); + return newToken; + } + + function formatToken(token: null | string) { + return token ? `Bearer ${token}` : null; + } + + // 请求头处理 + client.addRequestInterceptor({ + fulfilled: async (config) => { + const accessStore = useAccessStore(); + + config.headers.Authorization = formatToken(accessStore.accessToken); + config.headers['Accept-Language'] = preferences.app.locale; + return config; + }, + }); + + // 处理返回的响应数据格式 + // client.addResponseInterceptor( + // defaultResponseInterceptor({ + // codeField: 'code', + // dataField: 'data', + // successCode: 0, + // }), + // ); + + client.addResponseInterceptor({ + fulfilled: async (response) => { + const { config, data: responseData, status, headers } = response; + if (config.responseReturn === 'raw') { + return response; + } + if (!responseData) { + throw new Error($t('http.apiRequestFailed')); + } + + // console.log('response', response); + + if (status >= 200 && status < 400) { + if (config.responseReturn === 'body') { + return responseData; + } else if (headers['content-type']?.includes?.('application/json')) { + // 导出/下载类接口用 blob 方式接收 JSON 回执(异步导出只回任务信息,没有文件流)。 + // 此时 axios 的 responseData 就是 Blob 本身,Blob 上没有 code 字段, + // 若继续走下面的业务码判断会被误判为失败并抛错,所以直接交给调用方解析。 + if (config.responseType === 'blob') { + return responseData; + } + } else if (headers['content-type']?.includes?.('application/octet-stream')) { + // 下载文件 + return responseData; + } + const { code, data, message: msg, ...other } = responseData; + // 业务状态码为200则请求成功 + const hasSuccess = Reflect.has(responseData, 'code') && code === 0; + const hasLoginTimeout = Reflect.has(responseData, 'code') && code === 61; + if (hasSuccess) { + let successMsg = msg; + + if (isNull(successMsg) || isEmpty(successMsg)) { + successMsg = $t(`http.operationSuccess`); + } + + if (response.config.successMessageMode === 'modal') { + Modal.success({ + content: successMsg, + title: $t('http.successTip'), + }); + } else if (response.config.successMessageMode === 'message') { + message.success(successMsg); + } + // 分页情况下为code msg rows total 并没有data字段 + // 如果有data 直接返回data 没有data将剩余参数(...other)封装为data返回 + // 需要考虑data为null的情况(比如查询为空) 所以这里直接判断undefined + if (data !== undefined) { + return data; + } + // 没有data 将其他参数包装为data + return other; + } + if (hasLoginTimeout) { + // 已经在登出过程中 不再执行 + if (isLogoutProcessing) { + return; + } + isLogoutProcessing = true; + const _msg = $t('http.loginTimeout'); + const userStore = useAuthStore(); + userStore.logout().finally(() => { + message.error(_msg); + isLogoutProcessing = false; + }); + // 不再执行下面逻辑 + return; + } + } else if (status == 401) { + // 已经在登出过程中 不再执行 + if (isLogoutProcessing) { + return; + } + isLogoutProcessing = true; + const _msg = $t('http.loginTimeout'); + const userStore = useAuthStore(); + userStore.logout().finally(() => { + message.error(_msg); + isLogoutProcessing = false; + }); + // 不再执行下面逻辑 + return; + } + console.log('addResponseInterceptor response', response); + throw Object.assign({}, response, { response }); + }, + }); + // token过期的处理 + client.addResponseInterceptor( + authenticateResponseInterceptor({ + client, + doReAuthenticate, + doRefreshToken, + enableRefreshToken: preferences.app.enableRefreshToken, + formatToken, + }), + ); + + // 通用的错误处理,如果没有进入上面的错误处理逻辑,就会进入这里 + client.addResponseInterceptor( + errorMessageResponseInterceptor((msg: string, error) => { + const errorMessageMode = + error?.config?.errorMessageMode ?? + error?.response?.config?.errorMessageMode; + if (errorMessageMode === 'none') { + return; + } + + console.log('errorMessageResponseInterceptor error', error); + // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg + // 当前mock接口返回的错误字段是 error 或者 message + const responseData = error?.response?.data ?? {}; + const errorMessage = responseData?.error ?? responseData?.message ?? ''; + // 如果没有错误信息,则会根据状态码进行提示 + const finalErrorMessage = errorMessage || msg; + message.error(finalErrorMessage); + }), + ); + return client; +} + +export const requestClient = createRequestClient(apiURL, { + responseReturn: 'data', + timeout: 30000, +}); + +export const baseRequestClient = new RequestClient({ baseURL: apiURL, timeout: 30000, }); diff --git a/admin-ui/vue/apps/web-antd/src/api/system/client.ts b/admin-ui/vue/apps/web-antd/src/api/system/client.ts new file mode 100644 index 0000000..72b51b4 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/client.ts @@ -0,0 +1,140 @@ +/** + * @description 客户端管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysClientListReq { + clientId: string; + clientKey: string; + clientSecret: string; + status: string; +} + +export interface SysClient { + id: number; + clientId: string; + clientKey: string; + clientSecret: string; + grantType: string; + deviceType: string; + activeTimeout: number; + timeout: number; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; +} + +export interface SysClientListRes { + items: SysClient[]; + total: number; +} + +export interface SysClientViewReq { + id: number; +} + +export interface SysClientViewRes { + id: number; + clientId: string; + clientKey: string; + clientSecret: string; + grantType: string; + grantTypeList?: string[]; + deviceType: string; + activeTimeout: number; + timeout: number; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedDept: number; + updatedBy: number; + updatedAt: string; +} + +export interface SysClientAddReq { + clientId: string; + clientKey: string; + clientSecret: string; + grantType: string; + deviceType: string; + activeTimeout: number; + timeout: number; + status: string; +} + +export interface SysClientAddRes { + id: number; +} + +export interface SysClientEditReq { + id: number; + clientId?: string; + clientKey?: string; + clientSecret?: string; + grantType?: string; + deviceType?: string; + activeTimeout?: number; + timeout?: number; + status?: string; +} + +export interface SysClientEditRes { + id: number; +} + +export interface SysClientDeleteReq { + ids: number[]; +} + +export interface SysClientDeleteRes { + ids: number[]; +} + +export interface SysClientStatusReq { + id: number; + status: string; +} + +export interface SysClientStatusRes { + id: number; +} + +export const getSysClientListApi = (params: SysClientListReq) => { + return requestClient.get('/system/client/list', { params }); +}; + +export const getSysClientViewApi = (params: SysClientViewReq) => { + return requestClient.get('/system/client/view', { params }); +}; + +export const postSysClientAddApi = (params: SysClientAddReq|{ + [x: string]: any; +}) => { + return requestClient.post('/system/client/add', { ...params }); +}; + +export const postSysClientEditApi = (params: SysClientEditReq|{ + [x: string]: any; +}) => { + return requestClient.post('/system/client/edit', { ...params }); +}; + +export const postSysClientDeleteApi = (params: SysClientDeleteReq|{ + [x: string]: any; +}) => { + return requestClient.post('/system/client/delete', { ...params }); +}; + +export const postSysClientStatusApi = (params: SysClientStatusReq|{ + [x: string]: any; +}) => { + return requestClient.post('/system/client/status', { ...params }); +}; \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/system/config.ts b/admin-ui/vue/apps/web-antd/src/api/system/config.ts new file mode 100644 index 0000000..cf5d7f4 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/config.ts @@ -0,0 +1,109 @@ +/** + * @description 系统配置相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface GetSysConfigListReq { + configName: string; + configKey: string; + configType: string; + createdAt: string; +} + +export interface SysConfig { + configId: number; + tenantId:string; + configName:string; + configKey:string; + configValue:string; + configType:string; + createdDept:number; + createdBy:number; + createdAt:string; + remark:string; +} + +export interface GetSysConfigListRes { + items: SysConfig[]; + total: number; +} + +export interface AddSysConfigReq { + configName: string; + configKey: string; + configValue: string; + configType: string; + remark: string; +} + +export interface AddSysConfigRes { + configId: number; +} + +export interface EditSysConfigReq { + configId: number; + configName: string; + configKey: string; + configValue: string; + configType: string; + remark: string; +} + +export interface EditSysConfigRes { + configId: number; +} + +export interface DeleteSysConfigReq { + configIds: number[]; +} + +export interface DeleteSysConfigRes { + configIds: number[]; +} + +export interface GetSysConfigByIdReq { + configId: number; +} + +export interface GetSysConfigByIdRes { + configId: number; + tenantId: string; + configName: string; + configKey: string; + configValue: string; + configType: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; +} + +export async function getSysConfigListApi(params: GetSysConfigListReq) { + return requestClient.get('/system/config/list', { params }); +} + +export async function addSysConfigApi(params: AddSysConfigReq | { + [x: string]: any; +}) { + return requestClient.post('/system/config/add', { ...params }); +} + +export async function editSysConfigApi(params: EditSysConfigReq | { + [x: string]: any; +}) { + return requestClient.post('/system/config/edit', { ...params }); +} + +export async function deleteSysConfigApi(params: DeleteSysConfigReq) { + return requestClient.post('/system/config/delete', { ...params }); +} + +export async function getSysConfigByIdApi(params: GetSysConfigByIdReq) { + return requestClient.get('/system/config/view', { params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/dept.ts b/admin-ui/vue/apps/web-antd/src/api/system/dept.ts new file mode 100644 index 0000000..ef98807 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/dept.ts @@ -0,0 +1,237 @@ +/** + * @description 组织管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysDeptMini { + deptId: number; + deptName: string; +} + +export interface SysDeptListParam { + deptName?: string; + status?: string; + deptType?: number; + page?: number; + pageSize?: number; +} + +export interface SysDeptTreeParam { + deptType?: number; +} +export interface SysDeptListData { + deptId: number; + deptType: number; + tenantId: string; + parentId: number; + ancestors: string; + deptName: string; + deptCategory: string; + orderNum: number; + leader: number; + phone: string; + email: string; + status: string; + createdAt: string; +} + +export interface SysDeptListRes { + items: SysDeptListData[]; + total: number; +} + + +export async function getSysDeptListApi(params: SysDeptListParam) { + return requestClient.get('/system/dept/list', { params }); +} + +export interface SysDeptTreeData { + deptId: number; + parentId: number; + key: string; + deptName: string; + children?: SysDeptTreeData[]; +} +export interface SysDeptTreeRes { + items: SysDeptTreeData[]; +} + +export async function getSysDeptTreeApi(params: SysDeptTreeParam) { + return requestClient.get('/system/dept/tree', { params }); +} + +/** + * 组织管理页专用的完整部门树节点。 + * + * 与 SysDeptTreeData 的区别:后者只带 7 个精简字段,供部门选择器、 + * 用户管理左栏等场景使用;本页表格还要展示组织编码、状态、创建时间。 + */ +export interface SysDeptFullTreeData extends SysDeptListData { + children?: SysDeptFullTreeData[]; +} + +export interface SysDeptFullTreeRes { + items: SysDeptFullTreeData[]; +} + +/** + * 获取完整部门树(后端已组装好嵌套 children)。 + * + * 支持 deptName 模糊搜索、status / deptType 筛选;树结构由后端建, + * 前端 vxe-table 用 transform: false 直接渲染,无需二次建树。 + */ +export async function getSysDeptFullTreeApi(params: SysDeptListParam) { + return requestClient.get('/system/dept/tree/full', { + params, + }); +} + +export interface SysDeptAddParam { + parentId: number; + ancestors: string; + deptName: string; + deptCategory: string; + orderNum: number; + leader: number; + phone: string; + email: string; + status: string; +} + +export interface SysDeptAddRes { + deptId: number; +} + +export async function addSysDeptApi(params: SysDeptAddParam | { + [x: string]: any; +}) { + return requestClient.post('/system/dept/add', params); +} + +export interface SysDeptEditParam { + deptId: number; + parentId?: number; + ancestors?: string; + deptName?: string; + deptCategory?: string; + orderNum?: number; + leader?: number; + phone?: string; + email?: string; + status?: string; +} + +export interface SysDeptEditRes { + deptId: number; +} + +export async function editSysDeptApi(params: SysDeptEditParam | { + [x: string]: any; +}) { + return requestClient.post('/system/dept/edit', params); +} + +export interface SysDeptDeleteParam { + deptId: number; +} + +export interface SysDeptDeleteRes { + deptId: number; +} + +export async function deleteSysDeptApi(params: SysDeptDeleteParam) { + return requestClient.post('/system/dept/delete', params); +} + +export interface SysDeptViewParam { + deptId: number; +} + +export interface SysDeptViewRes { + deptId: number; + tenantId: string; + parentId: number; + ancestors: string; + deptName: string; + deptCategory: string; + orderNum: number; + leader: number | null; + phone: string; + email: string; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; + deptType: number|string; + areaCode?: string; + address?: string; + creditCode?: string; +} + +export async function viewSysDeptApi(params: SysDeptViewParam) { + return requestClient.get('/system/dept/view', { params }); +} + +/** + * 批量获取组织名称 + * @param deptIds 组织ID数组 + * @returns 组织ID到名称的映射对象 + */ +export async function batchGetDeptNames(deptIds: number[]): Promise> { + if (!deptIds || deptIds.length === 0) { + return {}; + } + + try { + // 获取所有组织列表,使用合理的页面大小(不超过2000) + const response = await getSysDeptListApi({ + deptName: '', + status: '', + page: 1, + pageSize: 2000 + }); + + if (!response || !response.items) { + console.error('组织列表API返回格式错误:', response); + return {}; + } + + const deptList = response.items; + + // 创建ID到名称的映射,只包含请求的ID + const nameMap: Record = {}; + deptIds.forEach(id => { + const dept = deptList.find(d => d.deptId === id); + nameMap[id] = dept ? dept.deptName : `组织${id}`; + }); + + return nameMap; + } catch (error) { + console.error('批量获取组织名称失败:', error); + // 失败时返回ID作为名称的映射 + const fallbackMap: Record = {}; + deptIds.forEach(id => { + fallbackMap[id] = String(id); + }); + return fallbackMap; + } +} + +export interface SysDeptApiInfoRes { + deptKey: string; + deptName: string; + appKey: string; + appSecret: string; +} + +export async function getSysDeptApiInfoApi() { + return requestClient.get('/agent/dept/apiInfo'); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/dict.ts b/admin-ui/vue/apps/web-antd/src/api/system/dict.ts new file mode 100644 index 0000000..080f1b8 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/dict.ts @@ -0,0 +1,217 @@ +/** + * @description 字典管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; +import { useCacheStore } from '#/store/cache'; +const KEY = 'dictList'; + +export interface SysDictTypeListReq { + page: number; + pageSize: number; + dictName: string; + dictType: string; +} +export interface SysDictTypeListModel { + dictId: number; + tenantId: string; + dictName: string; + dictType: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; + isSys?: string; // 添加是否系统内置字段 +} +export interface SysDictTypeListRes { + items: SysDictTypeListModel[]; + total: number; +} + +export async function getSysDictTypeListApi(params: SysDictTypeListReq) { + return requestClient.get('/system/dict/list', { params }); +} + +export interface SysDictDataListReq { + page: number; + pageSize: number; + dictId: number; + dictType: string; +} +export interface SysDictDataListModel { + dictCode: number; + tenantId: string; + dictSort: number; + dictLabel: string; + dictValue: string; + dictType: string; + cssClass: string; + listClass: string; + isDefault: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; +} +export interface SysDictDataListRes { + items: SysDictDataListModel[]; + type: SysDictTypeListModel; + total: number; +} + +export async function getSysDictDataListApi(params: SysDictDataListReq) { + return useCacheStore().getCache(params, KEY, () => requestClient.get('/system/dict-data/list/' + params.dictId, { params })) +} + + +export interface SysDictTypeAddReq { + dictName: string; + dictType: string; + remark: string; + isSys?: string; // 添加是否系统内置字段 +} +export interface SysDictTypeAddRes { + dictId: number; +} + +export async function addSysDictTypeApi(params: SysDictTypeAddReq | { + [x: string]: any; +}) { + useCacheStore().clearCache(KEY) + return requestClient.post('/system/dict-type/add', { ...params }); +} + +export interface SysDictTypeEditReq { + dictId: number; + dictName: string; + dictType: string; + remark: string; + isSys?: string; // 添加是否系统内置字段 +} +export interface SysDictTypeEditRes { + dictId: number; +} + +export async function editSysDictTypeApi(params: SysDictTypeEditReq | { + [x: string]: any; +}) {useCacheStore().clearCache(KEY) + return requestClient.post('/system/dict-type/edit', { ...params }); +} + +export interface SysDictTypeDeleteReq { + dictIds: number[]; +} +export interface SysDictTypeDeleteRes { + dictIds: number[]; +} + +export async function deleteSysDictTypeApi(params: SysDictTypeDeleteReq) { + useCacheStore().clearCache(KEY) + return requestClient.post('/system/dict-type/delete', { ...params }); +} + +export interface SysDictTypeViewReq { + dictId: number; +} +export interface SysDictTypeViewRes { + dictId: number; + tenantId: string; + dictName: string; + dictType: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; + remark: string; + isSys?: string; +} + +export async function getSysDictTypeViewApi(params: SysDictTypeViewReq) { + return requestClient.get('/system/dict-type/view', { params }); +} + +export interface SysDictDataAddReq { + dictSort: number; + dictLabel: string; + dictValue: string; + dictType: string; + cssClass: string; + listClass: string; + isDefault: string; + remark: string; +} +export interface SysDictDataAddRes { + dictCode: number; +} + +export async function addSysDictDataApi(params: SysDictDataAddReq | { + [x: string]: any; +}) { + useCacheStore().clearCache(KEY) + return requestClient.post('/system/dict-data/add', { ...params }); +} + +export interface SysDictDataEditReq { + dictCode: number; + dictSort: number; + dictLabel: string; + dictValue: string; + dictType: string; + cssClass: string; + listClass: string; + isDefault: string; + remark: string; +} +export interface SysDictDataEditRes { + dictCode: number; +} + +export async function editSysDictDataApi(params: SysDictDataEditReq | { + [x: string]: any; +}) { + useCacheStore().clearCache(KEY) + return requestClient.post('/system/dict-data/edit', { ...params }); +} + +export interface SysDictDataDeleteReq { + dictCodes: number[]; +} +export interface SysDictDataDeleteRes { + dictCodes: number[]; +} + +export async function deleteSysDictDataApi(params: SysDictDataDeleteReq) { + useCacheStore().clearCache(KEY) + return requestClient.post('/system/dict-data/delete', { ...params }); +} + +export interface SysDictDataViewReq { + dictCode: number; +} +export interface SysDictDataViewRes { + dictCode: number; + tenantId: string; + dictSort: number; + dictLabel: string; + dictValue: string; + dictType: string; + cssClass: string; + listClass: string; + isDefault: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; + remark: string; +} + +export async function getSysDictDataViewApi(params: SysDictDataViewReq) { + return requestClient.get('/system/dict-data/view', { params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/index.ts b/admin-ui/vue/apps/web-antd/src/api/system/index.ts new file mode 100644 index 0000000..6e32ecb --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/index.ts @@ -0,0 +1,18 @@ +/** + * @description 系统管理模块接口导出 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +export * from './dept'; +export * from './post'; +export * from './role'; +export * from './dict'; +export * from './config'; +export * from './user'; +export * from './notice'; +export * from './menu'; +export * from './social'; \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/system/job.ts b/admin-ui/vue/apps/web-antd/src/api/system/job.ts new file mode 100644 index 0000000..033d9ee --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/job.ts @@ -0,0 +1,86 @@ +/** + * @description 定时任务相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysJobListReq { + jobName: string; + jobGroup: string; + status: string; + page: number; + pageSize: number; +} + +export interface SysJobSaveReq { + jobId: number; + jobName: string; + jobGroup: string; + jobParams: string; + invokeTarget: string; + cronExpression: string; + misfirePolicy: string; + concurrent: string; + status: string; + remark: string; +} + + +export interface SysJob { + jobId: number; + jobName: string; + jobGroup: string; + jobParams: string; + invokeTarget: string; + cronExpression: string; + misfirePolicy: string | number | null; + concurrent: string | number | null; + status: string; + remark: string; +} + +export interface SysJobListRes { + items: SysJob[]; + total: number; +} + +export interface SysJobDeleteReq { + jobIds: number[]; +} + +export interface SysJobDeleteRes { + jobIds: number[]; +} + +export async function getSysJobListApi(params: SysJobListReq) { + return requestClient.get('/system/job/list', { params }); +} + +export async function viewSysJobApi(params: {jobId: number}) { + return requestClient.get('/system/job/view', { params }); +} + +export async function addSysJobApi(params: SysJobSaveReq|any) { + return requestClient.post('/system/job/add', params); +} + +export async function updateSysJobApi(params: SysJobSaveReq|any) { + return requestClient.post('/system/job/update', params ); +} +export async function updateStatusApi(params: SysJobSaveReq|any) { + return requestClient.post('/system/job/status', params ); +} + +export async function deleteSysJobApi(params: SysJobDeleteReq) { + return requestClient.post('/system/job/delete', { ...params }); +} + +export async function execOnceApi(params: {jobId: number}) { + return requestClient.post('/system/job/exec', params); +} + diff --git a/admin-ui/vue/apps/web-antd/src/api/system/logininfor.ts b/admin-ui/vue/apps/web-antd/src/api/system/logininfor.ts new file mode 100644 index 0000000..45f0ba9 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/logininfor.ts @@ -0,0 +1,53 @@ +/** + * @description 登录日志相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysLogininforListReq { + ipaddr: string; + userName: string; + status: string; + loginTime: string[]; +} + +export interface SysLogininfor { + infoId: number; + tenantId: string; + userName: string; + clientKey: string; + deviceType: string; + ipaddr: string; + loginLocation: string; + browser: string; + os: string; + status: string; + msg: string; + loginTime: string; +} + +export interface SysLogininforListRes { + items: SysLogininfor[]; + total: number; +} + +export interface SysLogininforDeleteReq { + infoIds: number[]; +} + +export interface SysLogininforDeleteRes { + infoIds: number[]; +} + +export async function getSysLogininforListApi(params: SysLogininforListReq) { + return requestClient.get('/system/logininfor/list', { params }); +} + +export async function deleteSysLogininforApi(params: SysLogininforDeleteReq) { + return requestClient.post('/system/logininfor/delete', { ...params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/menu.ts b/admin-ui/vue/apps/web-antd/src/api/system/menu.ts new file mode 100644 index 0000000..c9f042b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/menu.ts @@ -0,0 +1,122 @@ +/** + * @description 菜单管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; +import { useCacheStore } from "#/store/cache"; +const KEY = "menmenuuList"; +export interface SysMenuListReq { + menuName: string; + status: string; +} + +export interface SysMenuListData { + menuId: number; + menuName: string; + parentId: number; + orderNum: number; + path: string; + component: string; + queryParam: string; + isFrame: number; + isCache: number; + menuType: string; + visible: string; + status: string; + perms: string; + icon: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; + children?: SysMenuListData[]; +} + +export interface SysMenuListRes { + items: SysMenuListData[]; + total: number; +} + +export interface SysMenuTreeRes { + items: SysMenuListData[]; +} + +export interface SysMenuViewReq { + menuId: number; +} + +export interface SysMenuViewRes extends SysMenuListData {} + +export interface SysMenuAddReq { + menuName: string; + parentId: number; + orderNum: number; + path: string; + component: string; + queryParam: string; + isFrame: number; + isCache: number; + menuType: string; + visible: string; + status: string; + perms: string; + icon: string; + remark: string; +} + +export interface SysMenuUpdateReq { + menuId: number; + menuName?: string; + parentId?: number; + orderNum?: number; + path?: string; + component?: string; + queryParam?: string; + isFrame?: number; + isCache?: number; + menuType?: string; + visible?: string; + status?: string; + perms?: string; + icon?: string; + remark?: string; +} + +export interface SysMenuDeleteReq { + menuId: number; +} + +export async function getSysMenuListApi(params?: SysMenuListReq) { + return useCacheStore().getCache(params?params:{}, KEY, () => requestClient.get('/system/menu/list', { params })); +} + +/** + * 获取菜单树(后端已建好嵌套 children,前端无需再开启 treeConfig.transform 二次建树) + */ +export async function getSysMenuTreeApi(params?: SysMenuListReq) { + return requestClient.get('/system/menu/tree', { params }); +} + +export async function getSysMenuViewApi(params: SysMenuViewReq) { + return requestClient.get('/system/menu/view', { params }); +} + +export async function updateSysMenuApi(params: SysMenuUpdateReq|any) { + useCacheStore().clearCache(KEY); + return requestClient.post('/system/menu/update', { ...params }); +} + +export async function deleteSysMenuApi(params: SysMenuDeleteReq|any) { + useCacheStore().clearCache(KEY); + return requestClient.post('/system/menu/delete', { ...params }); +} + +export async function addSysMenuApi(params: SysMenuAddReq|any) { + useCacheStore().clearCache(KEY); + return requestClient.post('/system/menu/add', { ...params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/notice.ts b/admin-ui/vue/apps/web-antd/src/api/system/notice.ts new file mode 100644 index 0000000..96203d4 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/notice.ts @@ -0,0 +1,104 @@ +/** + * @description 通知公告相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; +import type { SysUserMini } from '#/api/system/user'; +export interface SysNoticeListReq { + noticeTitle: string; + noticeType: string; + createdBy: string; +} + +export interface SysNotice { + noticeId: number; + tenantId:string; + noticeTitle:string; + noticeType:string; + noticeContent:string; + status:string; + createdDept:number; + createdBy:number; + createdAt:string; + remark:string; + createdByUser:SysUserMini; +} + +export interface SysNoticeListRes { + items: SysNotice[]; + total: number; +} + +export interface SysNoticeAddReq { + noticeTitle: string; + noticeType: string; + noticeContent: string; + status: string; + remark: string; +} + +export interface SysNoticeEditReq { + noticeId: number; + noticeTitle?: string; + noticeType?: string; + noticeContent?: string; + status?: string; + remark?: string; +} + +export interface SysNoticeDeleteReq { + noticeIds: number[]; +} + +export interface SysNoticeViewReq { + noticeId : number; +} + +export interface SysNoticeViewRes extends SysNotice { + userIdList: any; + deptIdList: any; +} + +export interface SysNoticeAddRes { + noticeId: number; +} + +export interface SysNoticeEditRes { + noticeId: number; +} + +export interface SysNoticeDeleteRes { + noticeIds: number[]; +} + + + +export async function getSysNoticeListApi(params: SysNoticeListReq) { + return requestClient.get('/system/notice/list', { params }); +} + +export async function addSysNoticeApi(params: SysNoticeAddReq | { + [x: string]: any; +}) { + return requestClient.post('/system/notice/add', { ...params }); +} + + +export async function editSysNoticeApi(params: SysNoticeEditReq| { + [x: string]: any; +}) { + return requestClient.post('/system/notice/edit', { ...params }); +} + +export async function deleteSysNoticeApi(params: SysNoticeDeleteReq) { + return requestClient.post('/system/notice/delete', { ...params }); +} + +export async function getSysNoticeApi(params: SysNoticeViewReq) { + return requestClient.get('/system/notice/view', { params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/oper-log.ts b/admin-ui/vue/apps/web-antd/src/api/system/oper-log.ts new file mode 100644 index 0000000..2e1683e --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/oper-log.ts @@ -0,0 +1,46 @@ +/** + * @description 操作日志相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysOperLogListReq { + operIp: string; + businessType: string; + method: string; +} + +export interface SysOperLog { + operId: number; + tenantId: string; + title: string; + businessType: number; + method: string; + requestMethod: string; + operatorType: number; + operName: string; + deptName: string; + operUrl: string; + operIp: string; + operLocation: string; + operParam: string; + jsonResult: string; + status: number; + errorMsg: string; + operTime: string; + costTime: number; +} + +export interface SysOperLogListRes { + items: SysOperLog[]; + total: number; +} + +export async function getSysOperLogList(params: SysOperLogListReq) { + return requestClient.get('/system/oper-log/list', { params }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/system/oss-config.ts b/admin-ui/vue/apps/web-antd/src/api/system/oss-config.ts new file mode 100644 index 0000000..ce27bef --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/oss-config.ts @@ -0,0 +1,127 @@ +import { requestClient } from '#/api/request'; + +export const sysOssConfigApi = { + list: (params: any) => requestClient.get('/system/oss-config/list', { params }), + view: (params: any) => requestClient.get('/system/oss-config/view', { params }), + add: (params: any) => requestClient.post('/system/oss-config/add', { ...params }), + edit: (params: any) => requestClient.post('/system/oss-config/edit', { ...params }), + delete: (params: any) => requestClient.post('/system/oss-config/delete', { ...params }), +}; + +export interface SysOssConfigListParam { + page: number; + pageSize: number; + configKey: string; + bucketName: string; + status: string; +} +export interface SysOssConfigListRes { + items: SysOssConfigListData[]; + total: number; +} +export interface SysOssConfigListData { + ossConfigId: number; + configKey: string; + accessKey: string; + secretKey: string; + bucketName: string; + prefix: string; + endpoint: string; + domain: string; + isHttps: string; + region: string; + accessPolicy: string; + status: string; + ext1: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; +} +export interface SysOssConfigViewParam { + ossConfigId: number; +} +export interface SysOssConfigViewRes { + ossConfigId: number; + configKey: string; + accessKey: string; + secretKey: string; + bucketName: string; + prefix: string; + endpoint: string; + domain: string; + isHttps: string; + region: string; + accessPolicy: string; + status: string; + ext1: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; +} +export interface SysOssConfigAddParam { + configKey: string; + accessKey: string; + secretKey: string; + bucketName: string; + prefix: string; + endpoint: string; + domain: string; + isHttps: string; + region: string; + accessPolicy: string; + status: string; + ext1: string; + remark: string; +} +export interface SysOssConfigAddRes { + ossConfigId: number; +} +export interface SysOssConfigEditParam { + ossConfigId: number; + configKey?: string; + accessKey?: string; + secretKey?: string; + bucketName?: string; + prefix?: string; + endpoint?: string; + domain?: string; + isHttps?: string; + region?: string; + accessPolicy?: string; + status?: string; + ext1?: string; + remark?: string; +} +export interface SysOssConfigEditRes { + ossConfigId: number; +} +export interface SysOssConfigDeleteParam { + ossConfigIds: number[]; +} +export interface SysOssConfigDeleteRes { + ossConfigIds: number[]; +} + +export async function getSysOssConfigListApi(params: SysOssConfigListParam) { + return requestClient.get('/system/oss-config/list', { params }); +} +export async function getSysOssConfigViewApi(params: SysOssConfigViewParam) { + return requestClient.get('/system/oss-config/view', { params }); +} +export async function addSysOssConfigApi(params: SysOssConfigAddParam |{ + [x: string]: any; +}) { + return requestClient.post('/system/oss-config/add', { ...params }); +} +export async function editSysOssConfigApi(params: SysOssConfigEditParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/oss-config/edit', { ...params }); +} +export async function deleteSysOssConfigApi(params: SysOssConfigDeleteParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/oss-config/delete', { ...params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/oss.ts b/admin-ui/vue/apps/web-antd/src/api/system/oss.ts new file mode 100644 index 0000000..c06a882 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/oss.ts @@ -0,0 +1,118 @@ +/** + * @description 对象存储管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; +import type { AxiosRequestConfig } from '@vben/request'; +export interface SysOssListParam { + page: number; + pageSize: number; + fileName: string; + originalName: string; + fileSuffix: string; +} + +export interface SysOssListData { + ossId: number; + tenantId: string; + fileName: string; + originalName: string; + fileSuffix: string; + url: string; + createdDept: number; + createdAt: string; + createdBy: number; + service: string; +} + +export interface SysOssListModel { + items: SysOssListData[]; + total: number; +} + +export interface SysOssDownloadParam { + ossId: number; +} + +export interface SysOssDownloadModel { + ossId: number; +} + +export interface SysOssDeleteParam { + ossIds: number[]; +} + +export interface SysOssDeleteModel { + ossIds: number[]; +} + +export interface SysOssViewParam { + ossId: number; +} + +export interface SysOssViewModel { + ossId: number; + tenantId: string; + fileName: string; + originalName: string; + fileSuffix: string; + url: string; + createdDept: number; + createdAt: string; + createdBy: number; + service: string; +} + +export async function getSysOssListApi(params: SysOssListParam) { + return requestClient.get('/system/oss/list', { params }); +} + +export async function getSysOssDownloadApi(params: SysOssDownloadParam) { + return requestClient.get('/system/oss/download', { params }); +} + +export async function getSysOssViewApi(params: SysOssViewParam) { + return requestClient.get('/system/oss/view', { params }); +} + +export async function deleteSysOssApi(params: SysOssDeleteParam) { + return requestClient.post('/system/oss/delete', { ...params }); +} + +export type ID = number | string; +export function ossDownload( + ossId: ID, + onDownloadProgress?: AxiosRequestConfig['onDownloadProgress'], +) { + return requestClient.download(`/common/oss/download?ossId=${ossId}`, { + timeout: 30 * 1000, + onDownloadProgress + }); +} + +export function ossUpload(file: Blob | File) { + const formData = new FormData(); + formData.append('file', file); + return requestClient.post('/common/oss/upload', formData, { + headers: { 'Content-Type': 'multipart/form-data;charset=UTF-8' }, + timeout: 30 * 1000, + }); +} + +export function ossUploadImg(file: Blob | File) { + console.log(file); + const files = new FormData(); + files.append('file', file); + files.append('isDevice', "false"); + files.append('fileType', "img"); + console.log(files.getAll('file')); + return requestClient.post('/common/oss/upload', files, { + headers: { 'Content-Type': 'multipart/form-data;charset=UTF-8' }, + timeout: 30 * 1000, + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/post.ts b/admin-ui/vue/apps/web-antd/src/api/system/post.ts new file mode 100644 index 0000000..c64d9c2 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/post.ts @@ -0,0 +1,143 @@ +/** + * @description 岗位管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +import type { SysDeptMini } from '#/api/system/dept'; + +export interface SysPostListParam { + page?: number; + pageSize?: number; + postCode?: string; + postName?: string; + deptId?: number; + belongDeptId?: number; +} + +export interface SysPostListData { + postId: number; + tenantId: string; + deptId: number; + postCode: string; + postCategory: string; + postName: string; + postSort: number; + status: string; + remark: string; + createdAt: string; + deptInfo: SysDeptMini; +} + +export interface SysPostListRes { + items: SysPostListData[]; + total: number; + page: number; + pageSize: number; +} + +export async function getSysPostListApi(params: SysPostListParam) { + return requestClient.get('/system/post/list', { params }); +} + +export interface SysPostMini { + postId: number; + deptId: number; + postName: string; +} + +export interface SysPostAddParam { + deptId: number; + postCode: string; + postCategory: string; + postName: string; + postSort: number; + status: string; + remark: string; +} + +export interface SysPostAddRes { + postId: number; +} + +export async function addSysPostApi(params: SysPostAddParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/post/add', { ...params }); +} + +export interface SysPostEditParam { + postId: number; + deptId?: number; + postCode?: string; + postCategory?: string; + postName?: string; + postSort?: number; + status?: string; + remark?: string; +} + +export interface SysPostEditRes { + postId: number; +} + +export async function editSysPostApi(params: SysPostEditParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/post/edit', { ...params }); +} + +export interface SysPostDeleteParam { + postId?: number; + postIds?: number[]; +} + +export interface SysPostDeleteRes { + postId: number; +} + +export async function deleteSysPostApi(params: SysPostDeleteParam) { + return requestClient.post('/system/post/delete', { ...params }); +} + +export interface SysPostViewParam { + postId: number; +} + +export interface SysPostViewRes { + postId: number; + tenantId: string; + deptId: number; + postCode: string; + postCategory: string; + postName: string; + postSort: number; + status: string; + remark: string; + createdDept: number; + createdBy: number; + createdAt: string; + deptInfo: SysDeptMini; +} + +export async function getSysPostViewApi(params: SysPostViewParam) { + return requestClient.get('/system/post/view', { params }); +} + +export interface SysPostExportParam extends SysPostListParam { +} + +export interface SysPostExportRes { +} + +export async function getSysPostExportApi(params: SysPostExportParam) { + return requestClient.post('/system/post/export', params , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/qrcode.ts b/admin-ui/vue/apps/web-antd/src/api/system/qrcode.ts new file mode 100644 index 0000000..0f39baf --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/qrcode.ts @@ -0,0 +1,129 @@ +/** + * @description 系统二维码管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +/** + * @description 获取绑定二维码 + */ +export interface QrBindRes { + ticket: string; + expireTime: string; + qrUrl: string; + scanned: boolean; + openId?: string; +} +export async function getQrBindApi() { + return requestClient.get('/system/qrcode/bind'); +} + +/** + * @description 获取绑定二维码扫码状态 + */ +export interface QrBindStatusRes extends QrBindRes { + bound?: boolean; + expired?: boolean; +} +export async function getQrBindStatusApi() { + return requestClient.get('/system/qrcode/bind/status'); +} + +/** + * @description 获取登录二维码 + */ +export interface QrLoginRes { + tempUserId: string; + ticket: string; + expireTime: string; + qrUrl: string; + scanned: boolean; + openId?: string; + bound?: boolean; + expired?: boolean; + loginUserOut?: { + id: number; + username: string; + nickName: string; + avatar: string; + tenantId: string; + deptId: number; + }; + token?: string; +} +export async function getQrLoginApi() { + return requestClient.get('/system/qrcode/login'); +} + +/** + * @description 获取登录二维码扫码状态 + */ +export async function getQrLoginStatusApi(tempUserId: string) { + return requestClient.get('/system/qrcode/login/status', { params: { tempUserId } }); +} + +/** + * @description 登录并关联OpenId + */ +export interface QrLoginBindOpenIdParam { + openId: string; + tenantId: string; + username: string; + password: string; + captchaID?: string; + captchaValue: string; +} +export async function qrLoginBindOpenIdApi(params: QrLoginBindOpenIdParam) { + return requestClient.post('/system/qrcode/loginAndBindOpenId', params); +} + +/** + * @description 注册并关联OpenId + */ +export interface QrRegisterBindOpenIdParam { + openId: string; + userName: string; + password: string; + tenantId: string; + captchaId?: string; + captchaValue: string; +} +export async function qrRegisterBindOpenIdApi(params: QrRegisterBindOpenIdParam) { + return requestClient.post('/system/qrcode/registerAndBindOpenId', params); +} + +/** + * @description 扫码成功回调 + */ +export interface QrScanCallbackParam { + sceneId?: number; + thirdId?: number; + ticket?: string; + openId?: string; + event?: string; +} +export async function qrScanCallbackApi(params: QrScanCallbackParam) { + return requestClient.post('/system/qrcode/scan/callback', params); +} + +/** + * @description 扫码后选择用户登录 + */ +export interface QrLoginSelectUserParam { + userName: string; + tenantId: string; + openId: string; +} +export async function qrLoginSelectUserApi(params: QrLoginSelectUserParam) { + return requestClient.post('/system/qrcode/loginSelectUser', params); +} + +//删除绑定关系 +export async function deleteSocialBindingApi(id: string) { + return requestClient.post(`/system/social/delete`, { id }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/role.ts b/admin-ui/vue/apps/web-antd/src/api/system/role.ts new file mode 100644 index 0000000..001aa90 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/role.ts @@ -0,0 +1,146 @@ +/** + * @description 角色管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysRoleListParam { + page?: number; + pageSize?: number; + deptId?: number; + roleName?: string; + roleKey?: string; + status?: string; + createdAt?: string[]; +} + +export interface SysRoleListData { + roleId: number; + tenantId: string; + roleName: string; + roleKey: string; + roleSort: number; + dataScope: string; + menuCheckStrictly: number; + deptCheckStrictly: number; + status: string; + createdDept: number; + createdAt: string; + remark: string; +} + +export interface SysRoleViewData { + isTemplateRole: boolean; + isDeptDefaultRole: boolean; + roleMenuDataScopes: Record; + deptId: number; + roleId: number; + tenantId: string; + roleName: string; + roleKey: string; + roleSort: number; + dataScope: string; + menuCheckStrictly: number; + deptCheckStrictly: number; + status: string; + createdDept: number; + createdAt: string; + remark: string; + menuIds: number[]; + deptIds: number[]; +} + +export interface SysRoleListRes { + items: SysRoleListData[]; + total: number; +} + +export async function getSysRoleListApi(params: SysRoleListParam) { + return requestClient.get('/system/role/list', { params }); +} + +export interface SysRoleMini { + roleId: number; + roleName: string; + dataScope: string; +} +export interface SysRoleViewParam { + roleId: number; +} + +export interface SysRoleAddParam { + roleName: string; + roleKey: string; + roleSort: number; + menuCheckStrictly: number; + deptCheckStrictly: number; + status: string; + remark: string; + menuIds: number[]; +} + +export interface SysRoleEditParam { + roleId: number; + roleName: string; + roleKey: string; + roleSort: number; + menuCheckStrictly: number; + deptCheckStrictly: number; + status: string; + remark: string; + menuIds: number[]; +} + +export interface SysRoleDeleteParam { + roleId: number; + roleIds: number[]; +} + +export interface SysRoleAddRes {} + +export interface SysRoleEditRes {} + +export interface SysRoleDeleteRes {} + +export interface SysRoleDataScopeEditParam { + roleId: number; + dataScope: string; + deptCheckStrictly?: number; + deptIds?: number[]; +} +export interface SysRoleDataScopeEditRes {} + +export async function addSysRoleApi(params: SysRoleAddParam | any) { + return requestClient.post('/system/role/add', { ...params }); +} + +export async function editSysRoleApi(params: SysRoleEditParam | any) { + return requestClient.post('/system/role/edit', { ...params }); +} + +export async function deleteSysRoleApi(params: SysRoleDeleteParam | any) { + return requestClient.post('/system/role/delete', { + ...params, + }); +} + +export async function getSysRoleViewApi(params: SysRoleViewParam | any) { + console.log( + '/Users/lixiujie/dev_test/dev_go/xiujie_iot/vue/apps/web-antd/src/api/system/role.ts', + params, + ); + return requestClient.get('/system/role/view', { params }); +} + +export async function editSysRoleDataScopeApi( + params: SysRoleDataScopeEditParam | any, +) { + return requestClient.post('/system/role/dataScope', { + ...params, + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/social.ts b/admin-ui/vue/apps/web-antd/src/api/system/social.ts new file mode 100644 index 0000000..0183d38 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/social.ts @@ -0,0 +1,54 @@ +/** + * @description 社交账号管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; + +export interface SysSocialListReq { + page?: number; + pageSize?: number; + userId?: number; +} + +export interface SysSocialListRes { + items: SysSocialListModel[]; + total: number; +} + +export interface SysSocialListModel { + id: number; +userId: number; +tenantId: string; + authId: string; + source: string; + openId: string; + userName: string; + nickName: string; + email: string; + avatar: string; + accessToken: string; + expireIn: number; + refreshToken: string; + accessCode: string; + unionId: string; + scope: string; + tokenType: string; + idToken: string; + macAlgorithm: string; + macKey: string; + code: string; + oauthToken: string; + oauthTokenSecret: string; + createdDept: number; + createdBy: number; + createdAt: string; +} + +export async function getSysSocialListApi(params: SysSocialListReq) { + return requestClient.get('/system/social/list', { params }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/sysNoticeUser/index.ts b/admin-ui/vue/apps/web-antd/src/api/system/sysNoticeUser/index.ts new file mode 100644 index 0000000..daff7a7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/sysNoticeUser/index.ts @@ -0,0 +1,38 @@ +import { requestClient } from '#/api/request'; + +// 获取用户通知公告表列表 +export function List(params:any) { + return requestClient.get('system/sysNoticeUser/list', { params }); +} + +// 删除/批量删除用户通知公告表 +export function Delete(params:any) { + return requestClient.post('system/sysNoticeUser/delete', { ...params }); +} + +// 添加/编辑用户通知公告表 +export function Edit(params:any) { + return requestClient.post('system/sysNoticeUser/edit', { ...params }); +} + +// 修改用户通知公告表状态 +export function Status(params:any) { + return requestClient.post('system/sysNoticeUser/status', { ...params }); +} + +// 获取用户通知公告表指定详情 +export function View(params:any) { + return requestClient.get('system/sysNoticeUser/view', { params }); +} + +// 导出用户通知公告表 +export function Export(params:any) { + return requestClient.post('/system/sysNoticeUser/export', { ...params } , { + headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, + responseType: 'blob', + }); +} +/** 已读 */ +export function Read(params:any) { + return requestClient.post('system/sysNoticeUser/read', { ...params }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/system/tTplatformSetting.ts b/admin-ui/vue/apps/web-antd/src/api/system/tTplatformSetting.ts new file mode 100644 index 0000000..ddc0dc7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/tTplatformSetting.ts @@ -0,0 +1,54 @@ +import { requestClient } from '#/api/request'; + +export interface TTplatformSettingViewReq { + /** + * 完整域名 + */ + fullDomain?: string; + [property: string]: any; +} + +export interface TTplatformSettingViewRes { + /** + * 图标地址 + */ + appIcon?: string; + /** + * 平台标题 + */ + appTitle?: string; + /** + * 完整域名 + */ + fullDomain?: string; + /** + * 登录页描述文案 + */ + loginPageDescription?: string; + /** + * 登录页大标题 + */ + loginPageTitle?: string; + /** + * 登录标语图地址 + */ + loginSloganImage?: string; + /** + * 状态 0启用 1禁用 + */ + status?: number; + /** + * 二级域名前缀 + */ + subDomain?: string; + [property: string]: any; +} + +export async function getTTplatformSettingViewApi( + params: TTplatformSettingViewReq, +) { + return requestClient.get( + '/system/tTplatformSetting/view', + { params }, + ); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/tenant.ts b/admin-ui/vue/apps/web-antd/src/api/system/tenant.ts new file mode 100644 index 0000000..b1fcdf7 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/tenant.ts @@ -0,0 +1,136 @@ +import { requestClient } from '#/api/request'; +import {md5} from 'js-md5'; +export interface SysTenantListParam { + page: number; + pageSize: number; + tenantId: string; + contactUserName: string; + contactPhone: string; +} + +export interface SysTenantListData { + id: number; + tenantId: string; + contactUserName: string; + contactPhone: string; + companyName: string; + licenseNumber: string; + address: string; + intro: string; + domain: string; + remark: string; + packageId: number; + expireTime: string; + accountCount: number; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; +} + +export interface SysTenantListRes { + items: SysTenantListData[]; + total: number; +} + +export interface SysTenantAddParam { + contactUserName: string; + contactPhone: string; + companyName: string; + licenseNumber: string; + address: string; + intro: string; + domain: string; + remark: string; + packageId: number; + expireTime: string; + accountCount: number; + status: string; + username: string; + password: string; +} + +export interface SysTenantAddModel { + id: number; +} + +export interface SysTenantEditParam { + id: number; + tenantId?: string; + contactUserName?: string; + contactPhone?: string; + companyName?: string; + licenseNumber?: string; + address?: string; + intro?: string; + domain?: string; + remark?: string; + packageId?: number; + expireTime?: string; + accountCount?: number; + status?: string; +} +export interface SysTenantEditModel { + id: number; +} + +export interface SysTenantDeleteParam { + ids : number[]; +} +export interface SysTenantDeleteModel { + ids: number[]; +} + +export interface SysTenantStatusParam { + id: number; + status: string; +} +export interface SysTenantStatusModel { + id: number; +} + +export interface SysTenantViewParam { + id: number; +} +export interface SysTenantViewModel { + id: number; +} + +export async function getSysTenantListApi(params: SysTenantListParam) { + return requestClient.get('/system/tenant/list', { params }); +} + +export async function getSysTenantViewApi(params: SysTenantViewParam) { + return requestClient.get('/system/tenant/view', { params }); +} + +export async function addSysTenantApi(params: SysTenantAddParam|{ + [x: string]: any; +}) { + params.password = md5(params.password); + return requestClient.post('/system/tenant/add', { ...params }); +} + +export async function editSysTenantApi(params: SysTenantEditParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/tenant/edit', { ...params }); +} + +export async function deleteSysTenantApi(params: SysTenantDeleteParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/tenant/delete', { ...params }); +} + +export async function statusSysTenantApi(params: SysTenantStatusParam) { + return requestClient.post('/system/tenant/status', { ...params }); +} + +export async function syncmenuTenantApi(params: any) { + return requestClient.post('/system/tenant/syncmenu', { + ...params, + }); +} diff --git a/admin-ui/vue/apps/web-antd/src/api/system/tenant_package.ts b/admin-ui/vue/apps/web-antd/src/api/system/tenant_package.ts new file mode 100644 index 0000000..844bcec --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/tenant_package.ts @@ -0,0 +1,116 @@ +import { requestClient } from '#/api/request'; + +export interface SysTenantPackageListParam { + page: number; + pageSize: number; + tenantId?: string; + contactUserName?: string; + contactPhone?: string; +} + +export interface SysTenantPackageListData { + packageId: number; + packageName: string; + menuIds: string; + remark: string; + menuCheckStrictly: number; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; +} +export interface SysTenantPackageListRes { + items: SysTenantPackageListData[]; + total: number; +} + +export interface SysTenantPackageViewParam { + packageId: number; +} + +export interface SysTenantPackageViewRes { + packageId: number; + packageName: string; + menuIds: string; + remark: string; + menuCheckStrictly: number; + status: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; +} + +export interface SysTenantPackageAddParam { + packageName: string; + menuIds: string; + remark: string; + menuCheckStrictly: number; + status: string; +} + + export interface SysTenantPackageAddRes { + packageId: number; +} + +export interface SysTenantPackageEditParam { + packageId: number; + packageName: string; + menuIds: string; + remark: string; + menuCheckStrictly: number; + status: string; +} + +export interface SysTenantPackageEditRes { + packageId: number; +} + +export interface SysTenantPackageDeleteParam { + packageIds: number[]; +} + +export interface SysTenantPackageDeleteRes { + packageIds: number[]; +} + +export interface SysTenantPackageStatusParam { + packageId: number; + status: string; +} + +export interface SysTenantPackageStatusRes { + packageId: number; +} + +export async function getSysTenantPackageListApi(params: SysTenantPackageListParam) { + return requestClient.get('/system/tenant/package/list', { params }); +} + +export async function getSysTenantPackageViewApi(params: SysTenantPackageViewParam) { + return requestClient.get('/system/tenant/package/view', { params }); +} + + +export async function addSysTenantPackageApi(params: SysTenantPackageAddParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/tenant/package/add', { ...params }); +} + +export async function editSysTenantPackageApi(params: SysTenantPackageEditParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/tenant/package/edit', { ...params }); +} + +export async function deleteSysTenantPackageApi(params: SysTenantPackageDeleteParam) { + return requestClient.post('/system/tenant/package/delete', { ...params }); +} + +export async function statusSysTenantPackageApi(params: SysTenantPackageStatusParam) { + return requestClient.post('/system/tenant/package/status', { ...params }); +} \ No newline at end of file diff --git a/admin-ui/vue/apps/web-antd/src/api/system/user.ts b/admin-ui/vue/apps/web-antd/src/api/system/user.ts new file mode 100644 index 0000000..cbb301f --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/system/user.ts @@ -0,0 +1,320 @@ +/** + * @description 用户管理相关接口 + * @Link https://github.com/xiujiecn/xiu-admin + * @Copyright Copyright (c) 2025 LiXiujie + * @Author Lxj + * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE + * @date 2024-03-21 + */ + +import { requestClient } from '#/api/request'; +import type { SysDeptMini } from './dept'; +import type { SysRoleMini } from './role'; +import type { SysPostMini } from './post'; +import type { UserInfo } from '@vben/types'; +import type { Recordable } from '@vben/types'; +import {md5} from 'js-md5'; + +export interface SysUserListParam { + tenantId: string; + userId: number; + deptId: number; + userName: string; + nickName: string; + email: string; + phonenumber: string; + status: string; + createdAt: string; + page: number; + pageSize: number; + } + export interface SysUserListData { + userId: number; + tenantId: string; + deptId: number; + userName: string; + nickName: string; + userType: string; + email: string; + phonenumber: string; + sex: string; + avatar: string; + status: string; + loginIp: string; + loginDate: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; + deletedBy: number; + deletedAt: string; + remark: string; + deptInfo: SysDeptMini; + } + export interface SysUserListRes { + items: SysUserListData[]; + total: number; + } + + export async function getSysUserListApi(params: SysUserListParam) { + return requestClient.get('/system/user/list', { params }); + } + + + export interface UserProfileRes { + user: UserProfileData; + } + + export interface UserProfileData { + userId: number; + tenantId: string; + deptId: number | undefined; + userName: string; + nickName: string; + userType: string; + email: string; + phonenumber: string; + sex: string; + avatar: string; + status: string; + loginIp: string; + loginDate: string; + createdDept: number; + createdBy: number; + createdAt: string; + remark: string; + deptInfo: SysDeptMini; + roles: SysRoleMini[]; + posts: SysPostMini[]; + companyInfo: SysDeptMini; + } + + + + export interface SysUserViewModel extends UserProfileData { + + } + + export const EmptySysUserViewModel: SysUserViewModel = { + userId: 0, + tenantId: '', + deptId: undefined, + userName: '', + nickName: '', + userType: '', + email: '', + phonenumber: '', + sex: '0', + avatar: '', + status: '0', + loginIp: '', + loginDate: '', + createdDept: 0, + createdBy: 0, + createdAt: '', + remark: '', + deptInfo: { + deptId: 0, + deptName: '', + }, + roles: [], + posts: [], + } + + export interface SysUserViewParam { + userId: number; + } + + export interface SysUserAddParam { + deptId: number; + userName: string; + nickName: string; + userType: string; + email: string; + phonenumber: string; + sex: string; + avatar: string; + salt: string; + password: string; + status: string; + remark: string; + } + + export interface SysUserUpdateParam { + userId: number; + deptId?: number; + userName?: string; + nickName?: string; + userType?: string; + email?: string; + phonenumber?: string; + sex?: string; + avatar?: string; + status?: string; + updatedBy?: number; + updatedAt?: string; + remark?: string; + } + + export interface SysUserDeleteParam { + userId?: number; + userIds?: number[]; + } + + export interface SysUserResetPasswordParam { + userId: number; + password: string; + } + + export interface UpdateCurrentUserPasswordParam { + oldPassword: string; + newPassword: string; + } + + export async function getUserProfileApi() { + return requestClient.get('/system/user/profile'); + } + + export async function updateCurrentUserAvatar(params: UserProfileData) { + return requestClient.post('/system/user/profile/avatar', { params }); + } + + export async function updateCurrentUserPassword(params: UpdateCurrentUserPasswordParam) { + params.oldPassword = md5(params.oldPassword); + params.newPassword = md5(params.newPassword); + return requestClient.post('/system/user/profile/password', { ...params }); + } + export async function updateCurrentUserProfile(params: UserProfileData|Recordable) { + return requestClient.post('/system/user/profile/update', { ...params }); + } + + export interface SendCurrentUserEmailCodeParam { + captchaId: string; + captchaValue: string; + email: string; + } + + export interface UpdateCurrentUserEmailParam { + code: string; + email: string; + } + + export interface SendCurrentUserPhoneCodeParam { + captchaId: string; + captchaValue: string; + phonenumber: string; + } + + export interface UpdateCurrentUserPhoneParam { + code: string; + phonenumber: string; + } + + export async function sendCurrentUserEmailCode(params: SendCurrentUserEmailCodeParam) { + return requestClient.post('/system/user/profile/email/code', { ...params }); + } + + export async function updateCurrentUserEmail(params: UpdateCurrentUserEmailParam) { + return requestClient.post('/system/user/profile/email', { ...params }); + } + + export async function sendCurrentUserPhoneCode(params: SendCurrentUserPhoneCodeParam) { + return requestClient.post('/system/user/profile/phone/code', { ...params }); + } + + export async function updateCurrentUserPhone(params: UpdateCurrentUserPhoneParam) { + return requestClient.post('/system/user/profile/phone', { ...params }); + } + + export async function getSysUser(params: SysUserViewParam) { + return requestClient.get('/system/user/view', { params }); + } + + export async function addSysUser(params: SysUserAddParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/user/add', { ...params }); + } + + export async function updateSysUser(params: SysUserUpdateParam|{ + [x: string]: any; +}) { + return requestClient.post('/system/user/update', { ...params }); + } + + export async function deleteSysUser(params: SysUserDeleteParam) { + return requestClient.post('/system/user/delete', { ...params }); + } + + export async function resetSysUserPassword(params: SysUserResetPasswordParam) { + params.password = md5(params.password); + return requestClient.post('/system/user/resetPassword', { ...params }); + } + + export async function updateSysUserStatus(params: any) { + return requestClient.post('/system/user/status', { ...params }); + } + + export interface SysUserListByDeptIdParam { + deptId: number; + } + export interface SysUserMini { + userId: number; + userName: string; + nickName: string; + avatar: string; + tenantId: string; + deptId: number; + } + + export interface SysUserMiniListRes { + items: SysUserMini[]; + total: number; + } + + export async function getSysUserListByDeptIdApi(params: SysUserListByDeptIdParam) { + return requestClient.get('/system/user/listByDeptId', { params }); + } + + // ==================== MFA 相关 ==================== + + export interface IsMfaEnabledParam { + userId: number; + } + + export interface IsMfaEnabledRes { + userId: number; + mfaEnabled: number; + } + + export async function isMfaEnabled(params: IsMfaEnabledParam) { + return requestClient.get('/system/user/isMfaEnabled', { params }); + } + + export interface SysUserMfaEnabledModel { + userId: number; + uuid: string; + code: string; + mfaEnabled: number; + } + + export interface SetMfaEnabledRes { + uuid: string; + } + + export async function setMfaEnabled() { + return requestClient.post('/system/user/setMfaEnabled'); + } + + export interface MfaVerifyParam { + uuid: string; + code: string; + mfaEnabled: number; + } + + export interface MfaVerifyRes {} + + export async function mfaVerify(params: MfaVerifyParam) { + return requestClient.post('/system/user/mfaVerify', { ...params }); + } diff --git a/admin-ui/vue/apps/web-antd/src/api/utils/index.ts b/admin-ui/vue/apps/web-antd/src/api/utils/index.ts new file mode 100644 index 0000000..e162956 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/api/utils/index.ts @@ -0,0 +1,52 @@ +import { requestClient } from '#/api/request'; + +/** 创建文件夹 */ +export function Create(params: { displayName: string; parentId: number }) { + return requestClient.post('gallery/gallery/createFolder', { ...params }); +} + +/** 获取文件夹列表 */ +export function List(params: { + keyword?: string; + page?: number; + pageSize?: number; + parentId: number | string; + type?: 'folder' | 'image'; +}) { + return requestClient.get('gallery/gallery/list', { params }); +} + +/** 重命名 */ +export function Rename(params: { displayName: string; galleryId: number }) { + return requestClient.post('gallery/gallery/rename', { ...params }); +} + +/** 批量删除 */ +export function Delete(params: { galleryIds: number[] }) { + return requestClient.post('gallery/gallery/batchDelete', { ...params }); +} + +/** 上传图片 */ +export function Upload(params: { + displayName?: string; + file: File; + newFileType?: number; + parentId: number; + saveOriginalName?: string; +}) { + return requestClient.upload('gallery/gallery/upload', { + ...params, + file: params.file, + }); +} + +/** 获取api.json */ +export async function GetApiJSON() { + const response = await fetch(new URL('/api.json', window.location.origin)); + + if (!response.ok) { + throw new Error('获取 api.json 失败'); + } + + return response.json(); +} diff --git a/admin-ui/vue/apps/web-antd/src/app.vue b/admin-ui/vue/apps/web-antd/src/app.vue new file mode 100644 index 0000000..5f6d937 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/app.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/admin-ui/vue/apps/web-antd/src/assets/icons/custom.ts b/admin-ui/vue/apps/web-antd/src/assets/icons/custom.ts new file mode 100644 index 0000000..743b95b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/assets/icons/custom.ts @@ -0,0 +1,120 @@ +/** 自定义 */ +export const custom = [ + /** 加号 */ + { + key: 'PlusOutlined', + svg: '', + }, + /** 减号 */ + { + key: 'MinusOutlined', + svg: '', + }, + /** 刷新 */ + { + key: 'ReloadOutlined', + svg: '', + }, + /** wifi 图标 */ + { + key: 'WifiOutlined', + svg: '', + }, + /** 提示 */ + { + key: 'AlertOutlined', + svg: '', + }, + /** 解锁 */ + { + key: 'UnlockOutlined', + svg: '', + }, + /** 资金 */ + { + key: 'FundOutlined', + svg: '', + }, + /** 汽车除霜 */ + { + key: 'CarDefrostOutlined', + svg: '', + }, + /** 时间 */ + { + key: 'ClockTimeFour', + svg: '', + }, + /** 音量 */ + { + key: 'SoundOutlined', + svg: '', + }, + /** 折叠菜单 */ + { + key: 'MenuFoldOutlined', + svg: '', + }, + /** 信号 */ + { + key: 'SignalFilled', + svg: '', + }, + /** 垂直右 */ + { + key: 'VerticalRight', + svg: '', + }, + /** 关闭 */ + { + key: 'CloseOutlined', + svg: '', + }, + /** 上 */ + { + key: 'ArrowUpOutlined', + svg: '', + } /** 下 */, + { + key: 'ArrowDownOutlined', + svg: '', + }, + /** 应用商店 */ + { + key: 'AppstoreFiled', + svg: '', + } /** 应用商店 */, + { + key: 'AppstoreOutlined', + svg: '', + }, + /** 数据库 */ + { + key: 'DatabaseFilled', + svg: '', + } /** 数据库 */, + { + key: 'DatabaseOutlined', + svg: '', + }, + /** 代码沙盒 */ + { + key: 'CodeSandboxOutlined', + svg: '', + }, + /** 文件夹 */ + { + key: 'FolderOutlined', + svg: '', + }, + /** 打开的文件夹 */ + { + key: 'FolderOpenOutlined', + svg: '' + }, + /** 选中 */ + { + key: 'CheckCircle', + svg: '' + } +]; diff --git a/admin-ui/vue/apps/web-antd/src/assets/icons/index.ts b/admin-ui/vue/apps/web-antd/src/assets/icons/index.ts new file mode 100644 index 0000000..3ec0d7b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/assets/icons/index.ts @@ -0,0 +1,6 @@ +import type { Icon } from '#/utils/IconManagers'; + +import {custom} from './custom'; +import { mdiSlim } from './mdiSlim'; + +export const iconData: Icon[] = mdiSlim.concat(custom); diff --git a/admin-ui/vue/apps/web-antd/src/assets/icons/mdiSlim.ts b/admin-ui/vue/apps/web-antd/src/assets/icons/mdiSlim.ts new file mode 100644 index 0000000..285e681 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/assets/icons/mdiSlim.ts @@ -0,0 +1,2351 @@ +/** MDI 精简版 */ +export const mdiSlim = [ + { + key: 'AccessPointOutlined', + svg: '', + }, + { + key: 'AccessPointCheckOutlined', + svg: '', + }, + { + key: 'AccessPointNetworkOutlined', + svg: '', + }, + { + key: 'AccessPointNetworkOffOutlined', + svg: '', + }, + { + key: 'AccessPointOffOutlined', + svg: '', + }, + { + key: 'AirHumidifierOutlined', + svg: '', + }, + { + key: 'AirHumidifierOffOutlined', + svg: '', + }, + { + key: 'AirPurifierOutlined', + svg: '', + }, + { + key: 'AlarmLightOutlined', + svg: '', + }, + { + key: 'AlarmLightOffOutlined', + svg: '', + }, + { + key: 'AlarmLightOffOutlineOutlined', + svg: '', + }, + { + key: 'AlarmLightOutlineOutlined', + svg: '', + }, + { + key: 'ArrowBottomRightThinOutlined', + svg: '', + }, + { + key: 'ArrowDownOutlined', + svg: '', + }, + { + key: 'ArrowDownThinOutlined', + svg: '', + }, + { + key: 'ArrowLeftOutlined', + svg: '', + }, + { + key: 'ArrowLeftThinOutlined', + svg: '', + }, + { + key: 'ArrowRightOutlined', + svg: '', + }, + { + key: 'ArrowRightBoldOutlined', + svg: '', + }, + { + key: 'ArrowRightBoldBoxOutlined', + svg: '', + }, + { + key: 'ArrowRightCircleOutlineOutlined', + svg: '', + }, + { + key: 'ArrowRightThinOutlined', + svg: '', + }, + { + key: 'ArrowTopLeftThinOutlined', + svg: '', + }, + { + key: 'ArrowTopRightThinOutlined', + svg: '', + }, + { + key: 'ArrowUpThinOutlined', + svg: '', + }, + { + key: 'AutoFixOutlined', + svg: '', + }, + { + key: 'AutorenewOutlined', + svg: '', + }, + { + key: 'AvTimerOutlined', + svg: '', + }, + { + key: 'BatteryOutlined', + svg: '', + }, + { + key: 'Battery10Outlined', + svg: '', + }, + { + key: 'Battery20Outlined', + svg: '', + }, + { + key: 'Battery30Outlined', + svg: '', + }, + { + key: 'Battery40Outlined', + svg: '', + }, + { + key: 'Battery50Outlined', + svg: '', + }, + { + key: 'Battery60Outlined', + svg: '', + }, + { + key: 'Battery70Outlined', + svg: '', + }, + { + key: 'Battery80Outlined', + svg: '', + }, + { + key: 'Battery90Outlined', + svg: '', + }, + { + key: 'BatteryBluetoothVariantOutlined', + svg: '', + }, + { + key: 'BatteryChargingOutlined', + svg: '', + }, + { + key: 'BatteryCharging10Outlined', + svg: '', + }, + { + key: 'BatteryChargingHighOutlined', + svg: '', + }, + { + key: 'BatteryChargingLowOutlined', + svg: '', + }, + { + key: 'BatteryChargingMediumOutlined', + svg: '', + }, + { + key: 'BatteryChargingOutlineOutlined', + svg: '', + }, + { + key: 'BatteryChargingWirelessOutlined', + svg: '', + }, + { + key: 'BatteryOffOutlineOutlined', + svg: '', + }, + { + key: 'BatteryOutlineOutlined', + svg: '', + }, + { + key: 'BeachOutlined', + svg: '', + }, + { + key: 'BeakerOutlineOutlined', + svg: '', + }, + { + key: 'BellCheckOutlined', + svg: '', + }, + { + key: 'BellCheckOutlineOutlined', + svg: '', + }, + { + key: 'BellOffOutlineOutlined', + svg: '', + }, + { + key: 'BellOutlineOutlined', + svg: '', + }, + { + key: 'BellRingOutlined', + svg: '', + }, + { + key: 'BellRingOutlineOutlined', + svg: '', + }, + { + key: 'BellSleepOutlined', + svg: '', + }, + { + key: 'BellSleepOutlineOutlined', + svg: '', + }, + { + key: 'BikeFastOutlined', + svg: '', + }, + { + key: 'BluetoothOutlined', + svg: '', + }, + { + key: 'BluetoothAudioOutlined', + svg: '', + }, + { + key: 'BluetoothConnectOutlined', + svg: '', + }, + { + key: 'BluetoothOffOutlined', + svg: '', + }, + { + key: 'BluetoothSettingsOutlined', + svg: '', + }, + { + key: 'BluetoothTransferOutlined', + svg: '', + }, + { + key: 'BrightnessAutoOutlined', + svg: '', + }, + { + key: 'BroadcastOutlined', + svg: '', + }, + { + key: 'BroadcastOffOutlined', + svg: '', + }, + { + key: 'CalendarOutlined', + svg: '', + }, + { + key: 'CalendarAccountOutlined', + svg: '', + }, + { + key: 'CalendarCheckOutlined', + svg: '', + }, + { + key: 'CalendarClockOutlined', + svg: '', + }, + { + key: 'CalendarClockOutlineOutlined', + svg: '', + }, + { + key: 'CalendarEditOutlined', + svg: '', + }, + { + key: 'CalendarLockOutlined', + svg: '', + }, + { + key: 'CalendarMonthOutlined', + svg: '', + }, + { + key: 'CalendarMultiselectOutlined', + svg: '', + }, + { + key: 'CalendarRefreshOutlined', + svg: '', + }, + { + key: 'CalendarSearchOutlined', + svg: '', + }, + { + key: 'CalendarSyncOutlined', + svg: '', + }, + { + key: 'CameraOutlined', + svg: '', + }, + { + key: 'CameraMarkerOutlined', + svg: '', + }, + { + key: 'CameraTimerOutlined', + svg: '', + }, + { + key: 'CarOutlined', + svg: '', + }, + { + key: 'CarBatteryOutlined', + svg: '', + }, + { + key: 'CarBrakeAbsOutlined', + svg: '', + }, + { + key: 'CarBrakeAlertOutlined', + svg: '', + }, + { + key: 'CarBrakeFluidLevelOutlined', + svg: '', + }, + { + key: 'CarBrakeHoldOutlined', + svg: '', + }, + { + key: 'CarBrakeLowPressureOutlined', + svg: '', + }, + { + key: 'CarBrakeParkingOutlined', + svg: '', + }, + { + key: 'CarBrakeRetarderOutlined', + svg: '', + }, + { + key: 'CarBrakeTemperatureOutlined', + svg: '', + }, + { + key: 'CarChildSeatOutlined', + svg: '', + }, + { + key: 'CarClockOutlined', + svg: '', + }, + { + key: 'CarCogOutlined', + svg: '', + }, + { + key: 'CarConnectedOutlined', + svg: '', + }, + { + key: 'CarCoolantLevelOutlined', + svg: '', + }, + { + key: 'CarCruiseControlOutlined', + svg: '', + }, + { + key: 'CarDefrostFrontOutlined', + svg: '', + }, + { + key: 'CarDefrostRearOutlined', + svg: '', + }, + { + key: 'CarDoorOutlined', + svg: '', + }, + { + key: 'CarDoorLockOutlined', + svg: '', + }, + { + key: 'CarElectricOutlined', + svg: '', + }, + { + key: 'CarElectricOutlineOutlined', + svg: '', + }, + { + key: 'CarLightAlertOutlined', + svg: '', + }, + { + key: 'CarLightDimmedOutlined', + svg: '', + }, + { + key: 'CarLightFogOutlined', + svg: '', + }, + { + key: 'CarLightHighOutlined', + svg: '', + }, + { + key: 'CarMultipleOutlined', + svg: '', + }, + { + key: 'CarOffOutlined', + svg: '', + }, + { + key: 'CarParkingLightsOutlined', + svg: '', + }, + { + key: 'CarTireAlertOutlined', + svg: '', + }, + { + key: 'CarTractionControlOutlined', + svg: '', + }, + { + key: 'CarWirelessOutlined', + svg: '', + }, + { + key: 'CastOffOutlined', + svg: '', + }, + { + key: 'CastVariantOutlined', + svg: '', + }, + { + key: 'CctvOutlined', + svg: '', + }, + { + key: 'CctvOffOutlined', + svg: '', + }, + { + key: 'CeilingFanOutlined', + svg: '', + }, + { + key: 'CeilingFanLightOutlined', + svg: '', + }, + { + key: 'CeilingLightOutlined', + svg: '', + }, + { + key: 'CeilingLightMultipleOutlined', + svg: '', + }, + { + key: 'CeilingLightMultipleOutlineOutlined', + svg: '', + }, + { + key: 'CeilingLightOutlineOutlined', + svg: '', + }, + { + key: 'CellphoneLinkOutlined', + svg: '', + }, + { + key: 'CellphoneLinkOffOutlined', + svg: '', + }, + { + key: 'ChartArcOutlined', + svg: '', + }, + { + key: 'ChartAreasplineOutlined', + svg: '', + }, + { + key: 'ChartAreasplineVariantOutlined', + svg: '', + }, + { + key: 'ChartBarOutlined', + svg: '', + }, + { + key: 'ChartBarStackedOutlined', + svg: '', + }, + { + key: 'ChartBellCurveOutlined', + svg: '', + }, + { + key: 'ChartBellCurveCumulativeOutlined', + svg: '', + }, + { + key: 'ChartBoxOutlineOutlined', + svg: '', + }, + { + key: 'ChartLineOutlined', + svg: '', + }, + { + key: 'ChartTimelineVariantOutlined', + svg: '', + }, + { + key: 'ChartTimelineVariantShimmerOutlined', + svg: '', + }, + { + key: 'CheckOutlined', + svg: '', + }, + { + key: 'CheckAllOutlined', + svg: '', + }, + { + key: 'CheckBoldOutlined', + svg: '', + }, + { + key: 'CheckCircleOutlined', + svg: '', + }, + { + key: 'CheckCircleOutlineOutlined', + svg: '', + }, + { + key: 'CheckDecagramOutlined', + svg: '', + }, + { + key: 'CheckDecagramOutlineOutlined', + svg: '', + }, + { + key: 'CheckNetworkOutlined', + svg: '', + }, + { + key: 'CheckNetworkOutlineOutlined', + svg: '', + }, + { + key: 'CheckOutlineOutlined', + svg: '', + }, + { + key: 'CheckUnderlineOutlined', + svg: '', + }, + { + key: 'ChevronDoubleDownOutlined', + svg: '', + }, + { + key: 'ChevronDoubleLeftOutlined', + svg: '', + }, + { + key: 'ChevronDoubleRightOutlined', + svg: '', + }, + { + key: 'ChevronDoubleUpOutlined', + svg: '', + }, + { + key: 'ChevronRightOutlined', + svg: '', + }, + { + key: 'ChevronRightBoxOutlineOutlined', + svg: '', + }, + { + key: 'ChevronRightCircleOutlineOutlined', + svg: '', + }, + { + key: 'CircleOutlineOutlined', + svg: '', + }, + { + key: 'CircleSlice1Outlined', + svg: '', + }, + { + key: 'CircleSlice2Outlined', + svg: '', + }, + { + key: 'CircleSlice3Outlined', + svg: '', + }, + { + key: 'CircleSlice4Outlined', + svg: '', + }, + { + key: 'CircleSlice5Outlined', + svg: '', + }, + { + key: 'CircleSlice6Outlined', + svg: '', + }, + { + key: 'CircleSlice7Outlined', + svg: '', + }, + { + key: 'CircleSlice8Outlined', + svg: '', + }, + { + key: 'CloudLockOutlined', + svg: '', + }, + { + key: 'CloudLockOutlineOutlined', + svg: '', + }, + { + key: 'CloudOffOutlineOutlined', + svg: '', + }, + { + key: 'CloudOutlineOutlined', + svg: '', + }, + { + key: 'CogOutlined', + svg: '', + }, + { + key: 'CogBoxOutlined', + svg: '', + }, + { + key: 'CogClockwiseOutlined', + svg: '', + }, + { + key: 'CogCounterclockwiseOutlined', + svg: '', + }, + { + key: 'CogOffOutlined', + svg: '', + }, + { + key: 'CogOffOutlineOutlined', + svg: '', + }, + { + key: 'CogOutlineOutlined', + svg: '', + }, + { + key: 'CogPauseOutlined', + svg: '', + }, + { + key: 'CogPauseOutlineOutlined', + svg: '', + }, + { + key: 'CogPlayOutlined', + svg: '', + }, + { + key: 'CogPlayOutlineOutlined', + svg: '', + }, + { + key: 'CogRefreshOutlined', + svg: '', + }, + { + key: 'CogRefreshOutlineOutlined', + svg: '', + }, + { + key: 'CogSyncOutlined', + svg: '', + }, + { + key: 'CogSyncOutlineOutlined', + svg: '', + }, + { + key: 'CogTransferOutlined', + svg: '', + }, + { + key: 'CogTransferOutlineOutlined', + svg: '', + }, + { + key: 'CogsOutlined', + svg: '', + }, + { + key: 'ConnectionOutlined', + svg: '', + }, + { + key: 'ConsoleNetworkOutlined', + svg: '', + }, + { + key: 'ConsoleNetworkOutlineOutlined', + svg: '', + }, + { + key: 'ContactlessPaymentOutlined', + svg: '', + }, + { + key: 'ContactlessPaymentCircleOutlined', + svg: '', + }, + { + key: 'ContactlessPaymentCircleOutlineOutlined', + svg: '', + }, + { + key: 'CoolantTemperatureOutlined', + svg: '', + }, + { + key: 'Cpu32BitOutlined', + svg: '', + }, + { + key: 'Cpu64BitOutlined', + svg: '', + }, + { + key: 'CubeOutlineOutlined', + svg: '', + }, + { + key: 'CurtainsOutlined', + svg: '', + }, + { + key: 'CurtainsClosedOutlined', + svg: '', + }, + { + key: 'DeskphoneOutlined', + svg: '', + }, + { + key: 'DesktopClassicOutlined', + svg: '', + }, + { + key: 'DesktopTowerOutlined', + svg: '', + }, + { + key: 'DesktopTowerMonitorOutlined', + svg: '', + }, + { + key: 'DeveloperBoardOutlined', + svg: '', + }, + { + key: 'DevicesOutlined', + svg: '', + }, + { + key: 'DharmachakraOutlined', + svg: '', + }, + { + key: 'DishwasherOutlined', + svg: '', + }, + { + key: 'DishwasherAlertOutlined', + svg: '', + }, + { + key: 'DishwasherOffOutlined', + svg: '', + }, + { + key: 'DoorOutlined', + svg: '', + }, + { + key: 'DoorClosedOutlined', + svg: '', + }, + { + key: 'DoorClosedLockOutlined', + svg: '', + }, + { + key: 'DoorOpenOutlined', + svg: '', + }, + { + key: 'DoorSlidingOutlined', + svg: '', + }, + { + key: 'DoorSlidingLockOutlined', + svg: '', + }, + { + key: 'DoorSlidingOpenOutlined', + svg: '', + }, + { + key: 'DoorbellOutlined', + svg: '', + }, + { + key: 'DoorbellVideoOutlined', + svg: '', + }, + { + key: 'EarHearingOutlined', + svg: '', + }, + { + key: 'EarHearingOffOutlined', + svg: '', + }, + { + key: 'ElectricSwitchOutlined', + svg: '', + }, + { + key: 'ElectricSwitchClosedOutlined', + svg: '', + }, + { + key: 'EngineOutlined', + svg: '', + }, + { + key: 'EngineOffOutlined', + svg: '', + }, + { + key: 'EngineOffOutlineOutlined', + svg: '', + }, + { + key: 'EngineOutlineOutlined', + svg: '', + }, + { + key: 'EyeOutlined', + svg: '', + }, + { + key: 'EyeCheckOutlineOutlined', + svg: '', + }, + { + key: 'EyeOffOutlined', + svg: '', + }, + { + key: 'EyeOffOutlineOutlined', + svg: '', + }, + { + key: 'FanOutlined', + svg: '', + }, + { + key: 'FanAlertOutlined', + svg: '', + }, + { + key: 'FanAutoOutlined', + svg: '', + }, + { + key: 'FanChevronDownOutlined', + svg: '', + }, + { + key: 'FanChevronUpOutlined', + svg: '', + }, + { + key: 'FanMinusOutlined', + svg: '', + }, + { + key: 'FanOffOutlined', + svg: '', + }, + { + key: 'FanPlusOutlined', + svg: '', + }, + { + key: 'FanRemoveOutlined', + svg: '', + }, + { + key: 'FanSpeed1Outlined', + svg: '', + }, + { + key: 'FanSpeed2Outlined', + svg: '', + }, + { + key: 'FanSpeed3Outlined', + svg: '', + }, + { + key: 'FilterOutlineOutlined', + svg: '', + }, + { + key: 'FireOutlined', + svg: '', + }, + { + key: 'FireAlertOutlined', + svg: '', + }, + { + key: 'FireCircleOutlined', + svg: '', + }, + { + key: 'FireOffOutlined', + svg: '', + }, + { + key: 'FishOutlined', + svg: '', + }, + { + key: 'FishOffOutlined', + svg: '', + }, + { + key: 'FishbowlOutlined', + svg: '', + }, + { + key: 'FishbowlOutlineOutlined', + svg: '', + }, + { + key: 'FlagOutlined', + svg: '', + }, + { + key: 'FlareOutlined', + svg: '', + }, + { + key: 'FlashOutlined', + svg: '', + }, + { + key: 'FlashOffOutlined', + svg: '', + }, + { + key: 'FlashOutlineOutlined', + svg: '', + }, + { + key: 'FlashlightOutlined', + svg: '', + }, + { + key: 'FlashlightOffOutlined', + svg: '', + }, + { + key: 'FlaskEmptyOutlineOutlined', + svg: '', + }, + { + key: 'FlowerOutlined', + svg: '', + }, + { + key: 'FoodAppleOutlined', + svg: '', + }, + { + key: 'FoodAppleOutlineOutlined', + svg: '', + }, + { + key: 'FoodDrumstickOutlined', + svg: '', + }, + { + key: 'FoodDrumstickOffOutlined', + svg: '', + }, + { + key: 'FridgeIndustrialOffOutlineOutlined', + svg: '', + }, + { + key: 'FridgeIndustrialOutlineOutlined', + svg: '', + }, + { + key: 'FruitCherriesOutlined', + svg: '', + }, + { + key: 'FruitCherriesOffOutlined', + svg: '', + }, + { + key: 'FruitGrapesOutlined', + svg: '', + }, + { + key: 'FruitPineappleOutlined', + svg: '', + }, + { + key: 'FruitWatermelonOutlined', + svg: '', + }, + { + key: 'GasStationOffOutlineOutlined', + svg: '', + }, + { + key: 'GasStationOutlineOutlined', + svg: '', + }, + { + key: 'GateOutlined', + svg: '', + }, + { + key: 'GateAlertOutlined', + svg: '', + }, + { + key: 'GaugeOutlined', + svg: '', + }, + { + key: 'GaugeEmptyOutlined', + svg: '', + }, + { + key: 'GhostOffOutlineOutlined', + svg: '', + }, + { + key: 'GhostOutlineOutlined', + svg: '', + }, + { + key: 'GlassCocktailOutlined', + svg: '', + }, + { + key: 'GlassCocktailOffOutlined', + svg: '', + }, + { + key: 'GlassMugOutlined', + svg: '', + }, + { + key: 'GlassMugOffOutlined', + svg: '', + }, + { + key: 'HamburgerOutlined', + svg: '', + }, + { + key: 'HamburgerOffOutlined', + svg: '', + }, + { + key: 'HandBackLeftOffOutlineOutlined', + svg: '', + }, + { + key: 'HandBackLeftOutlineOutlined', + svg: '', + }, + { + key: 'HeadphonesOutlined', + svg: '', + }, + { + key: 'HeadphonesOffOutlined', + svg: '', + }, + { + key: 'HeartOutlined', + svg: '', + }, + { + key: 'HeartBrokenOutlined', + svg: '', + }, + { + key: 'HeartMultipleOutlineOutlined', + svg: '', + }, + { + key: 'HeartOffOutlineOutlined', + svg: '', + }, + { + key: 'HeartPulseOutlined', + svg: '', + }, + { + key: 'HelicopterOutlined', + svg: '', + }, + { + key: 'HexagonOutlineOutlined', + svg: '', + }, + { + key: 'HexagonSlice1Outlined', + svg: '', + }, + { + key: 'HexagonSlice2Outlined', + svg: '', + }, + { + key: 'HexagonSlice3Outlined', + svg: '', + }, + { + key: 'HexagonSlice4Outlined', + svg: '', + }, + { + key: 'HexagonSlice5Outlined', + svg: '', + }, + { + key: 'HexagonSlice6Outlined', + svg: '', + }, + { + key: 'HexagramOutlined', + svg: '', + }, + { + key: 'HexagramOutlineOutlined', + svg: '', + }, + { + key: 'HydroPowerOutlined', + svg: '', + }, + { + key: 'InformationOffOutlineOutlined', + svg: '', + }, + { + key: 'InformationOutlineOutlined', + svg: '', + }, + { + key: 'KettleOffOutlineOutlined', + svg: '', + }, + { + key: 'KettleOutlineOutlined', + svg: '', + }, + { + key: 'LanCheckOutlined', + svg: '', + }, + { + key: 'LanDisconnectOutlined', + svg: '', + }, + { + key: 'LedOffOutlined', + svg: '', + }, + { + key: 'LedOnOutlined', + svg: '', + }, + { + key: 'LedOutlineOutlined', + svg: '', + }, + { + key: 'LedVariantOffOutlined', + svg: '', + }, + { + key: 'LedVariantOnOutlined', + svg: '', + }, + { + key: 'LedVariantOutlineOutlined', + svg: '', + }, + { + key: 'LightSwitchOutlined', + svg: '', + }, + { + key: 'LightbulbOutlined', + svg: '', + }, + { + key: 'LightbulbAutoOutlined', + svg: '', + }, + { + key: 'LightbulbAutoOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbCflOutlined', + svg: '', + }, + { + key: 'LightbulbCflOffOutlined', + svg: '', + }, + { + key: 'LightbulbCflSpiralOutlined', + svg: '', + }, + { + key: 'LightbulbCflSpiralOffOutlined', + svg: '', + }, + { + key: 'LightbulbGroupOutlined', + svg: '', + }, + { + key: 'LightbulbGroupOffOutlined', + svg: '', + }, + { + key: 'LightbulbGroupOffOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbGroupOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbMultipleOutlined', + svg: '', + }, + { + key: 'LightbulbMultipleOffOutlined', + svg: '', + }, + { + key: 'LightbulbMultipleOffOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbMultipleOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbOffOutlined', + svg: '', + }, + { + key: 'LightbulbOffOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbOnOutlined', + svg: '', + }, + { + key: 'LightbulbOnOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbOutlineOutlined', + svg: '', + }, + { + key: 'LightbulbSpotOutlined', + svg: '', + }, + { + key: 'LightbulbSpotOffOutlined', + svg: '', + }, + { + key: 'LightbulbVariantOutlined', + svg: '', + }, + { + key: 'LightbulbVariantOutlineOutlined', + svg: '', + }, + { + key: 'LinkLockOutlined', + svg: '', + }, + { + key: 'LinkOffOutlined', + svg: '', + }, + { + key: 'LinkVariantOutlined', + svg: '', + }, + { + key: 'LinkVariantOffOutlined', + svg: '', + }, + { + key: 'LockOutlined', + svg: '', + }, + { + key: 'LockAlertOutlined', + svg: '', + }, + { + key: 'LockAlertOutlineOutlined', + svg: '', + }, + { + key: 'LockCheckOutlined', + svg: '', + }, + { + key: 'LockCheckOutlineOutlined', + svg: '', + }, + { + key: 'LockOpenAlertOutlineOutlined', + svg: '', + }, + { + key: 'LockOpenOutlineOutlined', + svg: '', + }, + { + key: 'LockOutlineOutlined', + svg: '', + }, + { + key: 'LockResetOutlined', + svg: '', + }, + { + key: 'LotionOutlined', + svg: '', + }, + { + key: 'MagnetOutlined', + svg: '', + }, + { + key: 'MemoryOutlined', + svg: '', + }, + { + key: 'MicrophoneOutlined', + svg: '', + }, + { + key: 'MicrophoneOutlineOutlined', + svg: '', + }, + { + key: 'MicrophoneVariantOutlined', + svg: '', + }, + { + key: 'MicrophoneVariantOffOutlined', + svg: '', + }, + { + key: 'MoleculeCoOutlined', + svg: '', + }, + { + key: 'MoleculeCo2Outlined', + svg: '', + }, + { + key: 'MotionPauseOutlined', + svg: '', + }, + { + key: 'MotionPauseOutlineOutlined', + svg: '', + }, + { + key: 'MotionPlayOutlined', + svg: '', + }, + { + key: 'MotionPlayOutlineOutlined', + svg: '', + }, + { + key: 'MuffinOutlined', + svg: '', + }, + { + key: 'MusicNoteEighthOutlined', + svg: '', + }, + { + key: 'MusicNoteOffOutlined', + svg: '', + }, + { + key: 'NetworkOutlined', + svg: '', + }, + { + key: 'NetworkOffOutlined', + svg: '', + }, + { + key: 'NetworkOffOutlineOutlined', + svg: '', + }, + { + key: 'NetworkOutlineOutlined', + svg: '', + }, + { + key: 'OilOutlined', + svg: '', + }, + { + key: 'OilLampOutlined', + svg: '', + }, + { + key: 'OilLevelOutlined', + svg: '', + }, + { + key: 'OilTemperatureOutlined', + svg: '', + }, + { + key: 'OpacityOutlined', + svg: '', + }, + { + key: 'PackageVariantOutlined', + svg: '', + }, + { + key: 'PackageVariantClosedOutlined', + svg: '', + }, + { + key: 'PinOffOutlineOutlined', + svg: '', + }, + { + key: 'PinOutlineOutlined', + svg: '', + }, + { + key: 'PlusOutlined', + svg: '', + }, + { + key: 'PlusBoxOutlined', + svg: '', + }, + { + key: 'PlusBoxMultipleOutlineOutlined', + svg: '', + }, + { + key: 'PlusBoxOutlineOutlined', + svg: '', + }, + { + key: 'PlusCircleOutlineOutlined', + svg: '', + }, + { + key: 'PlusNetworkOutlineOutlined', + svg: '', + }, + { + key: 'PowerOutlined', + svg: '', + }, + { + key: 'PowerCycleOutlined', + svg: '', + }, + { + key: 'PowerOffOutlined', + svg: '', + }, + { + key: 'PowerOnOutlined', + svg: '', + }, + { + key: 'PowerPlugOutlined', + svg: '', + }, + { + key: 'PowerPlugOffOutlined', + svg: '', + }, + { + key: 'PowerPlugOffOutlineOutlined', + svg: '', + }, + { + key: 'PowerPlugOutlineOutlined', + svg: '', + }, + { + key: 'PowerSettingsOutlined', + svg: '', + }, + { + key: 'PowerSleepOutlined', + svg: '', + }, + { + key: 'PowerSocketOutlined', + svg: '', + }, + { + key: 'PowerSocketAuOutlined', + svg: '', + }, + { + key: 'PowerSocketChOutlined', + svg: '', + }, + { + key: 'PowerSocketDeOutlined', + svg: '', + }, + { + key: 'PowerSocketEuOutlined', + svg: '', + }, + { + key: 'PowerSocketFrOutlined', + svg: '', + }, + { + key: 'PowerSocketItOutlined', + svg: '', + }, + { + key: 'PowerSocketJpOutlined', + svg: '', + }, + { + key: 'PowerSocketUkOutlined', + svg: '', + }, + { + key: 'PowerSocketUsOutlined', + svg: '', + }, + { + key: 'PowerStandbyOutlined', + svg: '', + }, + { + key: 'PrinterOffOutlineOutlined', + svg: '', + }, + { + key: 'PrinterOutlineOutlined', + svg: '', + }, + { + key: 'ProjectorScreenVariantOffOutlineOutlined', + svg: '', + }, + { + key: 'ProjectorScreenVariantOutlineOutlined', + svg: '', + }, + { + key: 'RefreshOutlined', + svg: '', + }, + { + key: 'RefreshAutoOutlined', + svg: '', + }, + { + key: 'RefreshCircleOutlined', + svg: '', + }, + { + key: 'RestartOutlined', + svg: '', + }, + { + key: 'RestartOffOutlined', + svg: '', + }, + { + key: 'RobotOffOutlineOutlined', + svg: '', + }, + { + key: 'RobotOutlineOutlined', + svg: '', + }, + { + key: 'RocketOutlined', + svg: '', + }, + { + key: 'RocketLaunchOutlined', + svg: '', + }, + { + key: 'RocketLaunchOutlineOutlined', + svg: '', + }, + { + key: 'RocketOutlineOutlined', + svg: '', + }, + { + key: 'RollerSkateOutlined', + svg: '', + }, + { + key: 'RollerSkateOffOutlined', + svg: '', + }, + { + key: 'RouterNetworkOutlined', + svg: '', + }, + { + key: 'RouterWirelessOutlined', + svg: '', + }, + { + key: 'RouterWirelessOffOutlined', + svg: '', + }, + { + key: 'RouterWirelessSettingsOutlined', + svg: '', + }, + { + key: 'RunOutlined', + svg: '', + }, + { + key: 'RunFastOutlined', + svg: '', + }, + { + key: 'SecurityOutlined', + svg: '', + }, + { + key: 'SecurityNetworkOutlined', + svg: '', + }, + { + key: 'SeedOutlined', + svg: '', + }, + { + key: 'SeedOffOutlined', + svg: '', + }, + { + key: 'SeedOffOutlineOutlined', + svg: '', + }, + { + key: 'SeedOutlineOutlined', + svg: '', + }, + { + key: 'ShowerHeadOutlined', + svg: '', + }, + { + key: 'SignalOutlined', + svg: '', + }, + { + key: 'Signal2GOutlined', + svg: '', + }, + { + key: 'Signal3GOutlined', + svg: '', + }, + { + key: 'Signal4GOutlined', + svg: '', + }, + { + key: 'Signal5GOutlined', + svg: '', + }, + { + key: 'SignalCellular1Outlined', + svg: '', + }, + { + key: 'SignalCellular2Outlined', + svg: '', + }, + { + key: 'SignalCellular3Outlined', + svg: '', + }, + { + key: 'SignalCellularOutlineOutlined', + svg: '', + }, + { + key: 'SignalDistanceVariantOutlined', + svg: '', + }, + { + key: 'SignalVariantOutlined', + svg: '', + }, + { + key: 'SilverwareOutlined', + svg: '', + }, + { + key: 'SlackOutlined', + svg: '', + }, + { + key: 'SmokingOutlined', + svg: '', + }, + { + key: 'SnowflakeOutlined', + svg: '', + }, + { + key: 'SpaOutlineOutlined', + svg: '', + }, + { + key: 'SpeedometerOutlined', + svg: '', + }, + { + key: 'SpeedometerMediumOutlined', + svg: '', + }, + { + key: 'SpeedometerSlowOutlined', + svg: '', + }, + { + key: 'SwapHorizontalOutlined', + svg: '', + }, + { + key: 'SwapHorizontalCircleOutlineOutlined', + svg: '', + }, + { + key: 'SwapVerticalOutlined', + svg: '', + }, + { + key: 'TemperatureCelsiusOutlined', + svg: '', + }, + { + key: 'TemperatureFahrenheitOutlined', + svg: '', + }, + { + key: 'TemperatureKelvinOutlined', + svg: '', + }, + { + key: 'TestTubeOutlined', + svg: '', + }, + { + key: 'TestTubeEmptyOutlined', + svg: '', + }, + { + key: 'TestTubeOffOutlined', + svg: '', + }, + { + key: 'ThermometerOutlined', + svg: '', + }, + { + key: 'ThermometerAlertOutlined', + svg: '', + }, + { + key: 'ThermometerBluetoothOutlined', + svg: '', + }, + { + key: 'ThermometerChevronDownOutlined', + svg: '', + }, + { + key: 'ThermometerChevronUpOutlined', + svg: '', + }, + { + key: 'ThermometerHighOutlined', + svg: '', + }, + { + key: 'ThermometerLinesOutlined', + svg: '', + }, + { + key: 'ThermometerLowOutlined', + svg: '', + }, + { + key: 'ThermometerOffOutlined', + svg: '', + }, + { + key: 'ThermometerPlusOutlined', + svg: '', + }, + { + key: 'ThermostatOutlined', + svg: '', + }, + { + key: 'ThermostatBoxOutlined', + svg: '', + }, + { + key: 'TimerOutlined', + svg: '', + }, + { + key: 'Timer10Outlined', + svg: '', + }, + { + key: 'Timer3Outlined', + svg: '', + }, + { + key: 'TimerCogOutlined', + svg: '', + }, + { + key: 'TimerCogOutlineOutlined', + svg: '', + }, + { + key: 'TimerOffOutlined', + svg: '', + }, + { + key: 'TimerOffOutlineOutlined', + svg: '', + }, + { + key: 'TimerOutlineOutlined', + svg: '', + }, + { + key: 'TimerSandOutlined', + svg: '', + }, + { + key: 'TimerSettingsOutlineOutlined', + svg: '', + }, + { + key: 'TimetableOutlined', + svg: '', + }, + { + key: 'TireOutlined', + svg: '', + }, + { + key: 'ToggleSwitchOutlined', + svg: '', + }, + { + key: 'ToggleSwitchOffOutlined', + svg: '', + }, + { + key: 'ToggleSwitchOffOutlineOutlined', + svg: '', + }, + { + key: 'ToggleSwitchOutlineOutlined', + svg: '', + }, + { + key: 'UmbrellaOutlined', + svg: '', + }, + { + key: 'UmbrellaBeachOutlined', + svg: '', + }, + { + key: 'UmbrellaBeachOutlineOutlined', + svg: '', + }, + { + key: 'UmbrellaClosedOutlined', + svg: '', + }, + { + key: 'UmbrellaClosedOutlineOutlined', + svg: '', + }, + { + key: 'UmbrellaClosedVariantOutlined', + svg: '', + }, + { + key: 'UmbrellaOutlineOutlined', + svg: '', + }, + { + key: 'ValveOutlined', + svg: '', + }, + { + key: 'ValveClosedOutlined', + svg: '', + }, + { + key: 'ValveOpenOutlined', + svg: '', + }, + { + key: 'VolumeHighOutlined', + svg: '', + }, + { + key: 'VolumeLowOutlined', + svg: '', + }, + { + key: 'VolumeMuteOutlined', + svg: '', + }, + { + key: 'VolumeOffOutlined', + svg: '', + }, + { + key: 'VolumeVariantOffOutlined', + svg: '', + }, + { + key: 'WallSconceOutlined', + svg: '', + }, + { + key: 'WallSconceFlatOutlined', + svg: '', + }, + { + key: 'WallSconceFlatOutlineOutlined', + svg: '', + }, + { + key: 'WallSconceFlatVariantOutlined', + svg: '', + }, + { + key: 'WallSconceOutlineOutlined', + svg: '', + }, + { + key: 'WallSconceRoundOutlined', + svg: '', + }, + { + key: 'WallSconceRoundVariantOutlined', + svg: '', + }, + { + key: 'WallSconceRoundVariantOutlineOutlined', + svg: '', + }, + { + key: 'WatchVibrateOutlined', + svg: '', + }, + { + key: 'WatchVibrateOffOutlined', + svg: '', + }, + { + key: 'WaterOutlined', + svg: '', + }, + { + key: 'WaterAlertOutlined', + svg: '', + }, + { + key: 'WaterAlertOutlineOutlined', + svg: '', + }, + { + key: 'WaterCheckOutlined', + svg: '', + }, + { + key: 'WaterCheckOutlineOutlined', + svg: '', + }, + { + key: 'WaterOffOutlined', + svg: '', + }, + { + key: 'WaterOffOutlineOutlined', + svg: '', + }, + { + key: 'WaterOutlineOutlined', + svg: '', + }, + { + key: 'WaterPoloOutlined', + svg: '', + }, + { + key: 'WaterPumpOutlined', + svg: '', + }, + { + key: 'WaterPumpOffOutlined', + svg: '', + }, + { + key: 'WaterRemoveOutlined', + svg: '', + }, + { + key: 'WaterRemoveOutlineOutlined', + svg: '', + }, + { + key: 'WaterWellOutlined', + svg: '', + }, + { + key: 'WaterWellOutlineOutlined', + svg: '', + }, + { + key: 'WaterfallOutlined', + svg: '', + }, + { + key: 'WateringCanOutlined', + svg: '', + }, + { + key: 'WateringCanOutlineOutlined', + svg: '', + }, + { + key: 'WaveOutlined', + svg: '', + }, + { + key: 'WavesOutlined', + svg: '', + }, + { + key: 'WeatherCloudyOutlined', + svg: '', + }, + { + key: 'WeatherCloudyAlertOutlined', + svg: '', + }, + { + key: 'WeatherCloudyArrowRightOutlined', + svg: '', + }, + { + key: 'WeatherFogOutlined', + svg: '', + }, + { + key: 'WeatherHailOutlined', + svg: '', + }, + { + key: 'WeatherHazyOutlined', + svg: '', + }, + { + key: 'WeatherHurricaneOutlined', + svg: '', + }, + { + key: 'WeatherLightningOutlined', + svg: '', + }, + { + key: 'WeatherLightningRainyOutlined', + svg: '', + }, + { + key: 'WeatherNightOutlined', + svg: '', + }, + { + key: 'WeatherNightPartlyCloudyOutlined', + svg: '', + }, + { + key: 'WeatherPartlyCloudyOutlined', + svg: '', + }, + { + key: 'WeatherPartlyLightningOutlined', + svg: '', + }, + { + key: 'WeatherPartlyRainyOutlined', + svg: '', + }, + { + key: 'WeatherPartlySnowyOutlined', + svg: '', + }, + { + key: 'WeatherPartlySnowyRainyOutlined', + svg: '', + }, + { + key: 'WeatherPouringOutlined', + svg: '', + }, + { + key: 'WeatherRainyOutlined', + svg: '', + }, + { + key: 'WeatherSnowyOutlined', + svg: '', + }, + { + key: 'WeatherSnowyHeavyOutlined', + svg: '', + }, + { + key: 'WeatherSnowyRainyOutlined', + svg: '', + }, + { + key: 'WeatherSunnyOutlined', + svg: '', + }, + { + key: 'WeatherSunnyAlertOutlined', + svg: '', + }, + { + key: 'WeatherSunnyOffOutlined', + svg: '', + }, + { + key: 'WeatherSunsetOutlined', + svg: '', + }, + { + key: 'WeatherSunsetDownOutlined', + svg: '', + }, + { + key: 'WeatherTornadoOutlined', + svg: '', + }, + { + key: 'WeatherWindyOutlined', + svg: '', + }, + { + key: 'WeatherWindyVariantOutlined', + svg: '', + }, + { + key: 'WebcamOutlined', + svg: '', + }, + { + key: 'WebcamOffOutlined', + svg: '', + }, + { + key: 'WifiOutlined', + svg: '', + }, + { + key: 'WifiOffOutlined', + svg: '', + }, + { + key: 'WifiStrengthOffOutlined', + svg: '', + }, + { + key: 'WifiStrengthOffOutlineOutlined', + svg: '', + }, + { + key: 'WindowCloseOutlined', + svg: '', + }, + { + key: 'WindowClosedOutlined', + svg: '', + }, + { + key: 'WindowClosedVariantOutlined', + svg: '', + }, + { + key: 'WindowMaximizeOutlined', + svg: '', + }, + { + key: 'WindowMinimizeOutlined', + svg: '', + }, + { + key: 'WindowOpenOutlined', + svg: '', + }, + { + key: 'WindowOpenVariantOutlined', + svg: '', + }, + { + key: 'WindowShutterOutlined', + svg: '', + }, + { + key: 'WindowShutterAlertOutlined', + svg: '', + }, + { + key: 'WindowShutterOpenOutlined', + svg: '', + }, +] diff --git a/admin-ui/vue/apps/web-antd/src/bootstrap.ts b/admin-ui/vue/apps/web-antd/src/bootstrap.ts new file mode 100644 index 0000000..ec72112 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/bootstrap.ts @@ -0,0 +1,76 @@ +import { createApp, watchEffect } from 'vue'; + +import { registerAccessDirective } from '@vben/access'; +import { registerLoadingDirective } from '@vben/common-ui/es/loading'; +import { preferences } from '@vben/preferences'; +import { initStores } from '@vben/stores'; +import '@vben/styles'; +import '@vben/styles/antd'; + +import { useTitle } from '@vueuse/core'; + +import { $t, setupI18n } from '#/locales'; + +import { initComponentAdapter } from './adapter/component'; +import { initSetupVbenForm } from './adapter/form'; +import App from './app.vue'; +import { router } from './router'; + +async function bootstrap(namespace: string) { + // 初始化组件适配器 + await initComponentAdapter(); + + // 初始化表单组件 + await initSetupVbenForm(); + + // // 设置弹窗的默认配置 + // setDefaultModalProps({ + // fullscreenButton: false, + // }); + // // 设置抽屉的默认配置 + // setDefaultDrawerProps({ + // zIndex: 1020, + // }); + + const app = createApp(App); + + // 注册v-loading指令 + registerLoadingDirective(app, { + loading: 'loading', // 在这里可以自定义指令名称,也可以明确提供false表示不注册这个指令 + spinning: 'spinning', + }); + + // 国际化 i18n 配置 + await setupI18n(app); + + // 配置 pinia-tore + await initStores(app, { namespace }); + + // 安装权限指令 + registerAccessDirective(app); + + // 初始化 tippy + const { initTippy } = await import('@vben/common-ui/es/tippy'); + initTippy(app); + + // 配置路由及路由守卫 + app.use(router); + + // 配置Motion插件 + const { MotionPlugin } = await import('@vben/plugins/motion'); + app.use(MotionPlugin); + + // 动态更新标题 + watchEffect(() => { + if (preferences.app.dynamicTitle) { + const routeTitle = router.currentRoute.value.meta?.title; + const pageTitle = + (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name; + useTitle(pageTitle); + } + }); + + app.mount('#app'); +} + +export { bootstrap }; diff --git a/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue b/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue new file mode 100644 index 0000000..82ddf97 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue b/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue new file mode 100644 index 0000000..f3d524b --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue b/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue new file mode 100644 index 0000000..e8ec865 --- /dev/null +++ b/admin-ui/vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts new file mode 100644 index 0000000..e2d4773 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts @@ -0,0 +1 @@ +export { default as Textarea } from './Textarea.vue'; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue new file mode 100644 index 0000000..299b669 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue @@ -0,0 +1,44 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue new file mode 100644 index 0000000..615562f --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue @@ -0,0 +1,48 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts new file mode 100644 index 0000000..ac3e34b --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts @@ -0,0 +1,2 @@ +export { default as ToggleGroup } from './ToggleGroup.vue'; +export { default as ToggleGroupItem } from './ToggleGroupItem.vue'; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue new file mode 100644 index 0000000..779a60c --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue @@ -0,0 +1,47 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts new file mode 100644 index 0000000..ecc1e3f --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts @@ -0,0 +1,2 @@ +export * from './toggle'; +export { default as Toggle } from './Toggle.vue'; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts new file mode 100644 index 0000000..d251328 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts @@ -0,0 +1,27 @@ +import type { VariantProps } from 'class-variance-authority'; + +import { cva } from 'class-variance-authority'; + +export const toggleVariants = cva( + 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground', + { + defaultVariants: { + size: 'default', + variant: 'default', + }, + variants: { + size: { + default: 'h-9 px-3', + lg: 'h-10 px-3', + sm: 'h-8 px-2', + }, + variant: { + default: 'bg-transparent', + outline: + 'border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground', + }, + }, + }, +); + +export type ToggleVariants = VariantProps; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue new file mode 100644 index 0000000..95aef73 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue @@ -0,0 +1,16 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue new file mode 100644 index 0000000..0a6be32 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue @@ -0,0 +1,48 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue new file mode 100644 index 0000000..6ad95a0 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue @@ -0,0 +1,13 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue new file mode 100644 index 0000000..52d1e64 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue @@ -0,0 +1,13 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts new file mode 100644 index 0000000..94e681c --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts @@ -0,0 +1,4 @@ +export { default as Tooltip } from './Tooltip.vue'; +export { default as TooltipContent } from './TooltipContent.vue'; +export { default as TooltipProvider } from './TooltipProvider.vue'; +export { default as TooltipTrigger } from './TooltipTrigger.vue'; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts new file mode 100644 index 0000000..d390f63 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts @@ -0,0 +1,4 @@ +export { default as VbenTree } from './tree.vue'; +export type { TreeProps } from './types'; +export { treePropsDefaults } from './types'; +export type { FlattenedItem } from 'reka-ui'; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue new file mode 100644 index 0000000..c2c7607 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue @@ -0,0 +1,467 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts new file mode 100644 index 0000000..53118ba --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts @@ -0,0 +1,62 @@ +import type { Arrayable } from '@vueuse/core'; +import type { FlattenedItem } from 'reka-ui'; + +import type { Recordable } from '@vben-core/typings'; + +export interface TreeProps { + /** 单选时允许取消已有选项 */ + allowClear?: boolean; + /** 非关联选择时,自动选中上级节点 */ + autoCheckParent?: boolean; + /** 显示边框 */ + bordered?: boolean; + /** 取消父子关联选择 */ + checkStrictly?: boolean; + /** 子级字段名 */ + childrenField?: string; + /** 默认展开的键 */ + defaultExpandedKeys?: Array; + /** 默认展开的级别(优先级高于defaultExpandedKeys) */ + defaultExpandedLevel?: number; + /** 默认值 */ + defaultValue?: Arrayable; + /** 禁用 */ + disabled?: boolean; + /** 禁用字段名 */ + disabledField?: string; + /** 自定义节点类名 */ + getNodeClass?: (item: FlattenedItem>) => string; + iconField?: string; + /** label字段 */ + labelField?: string; + /** 是否多选 */ + multiple?: boolean; + /** 显示由iconField指定的图标 */ + showIcon?: boolean; + /** 启用展开收缩动画 */ + transition?: boolean; + /** 树数据 */ + treeData: Recordable[]; + /** 值字段 */ + valueField?: string; +} + +export function treePropsDefaults() { + return { + allowClear: false, + autoCheckParent: true, + bordered: false, + checkStrictly: false, + defaultExpandedKeys: () => [], + defaultExpandedLevel: 0, + disabled: false, + disabledField: 'disabled', + iconField: 'icon', + labelField: 'label', + multiple: false, + showIcon: true, + transition: true, + valueField: 'value', + childrenField: 'children', + }; +} diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs new file mode 100644 index 0000000..f17f556 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config'; diff --git a/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/tsconfig.json b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/tsconfig.json new file mode 100644 index 0000000..0a46bc5 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/shadcn-ui/tsconfig.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@vben-core/shadcn-ui/*": ["./src/*"] + } + }, + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/build.config.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/build.config.ts new file mode 100644 index 0000000..18eaa60 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/build.config.ts @@ -0,0 +1,21 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: [ + { + builder: 'mkdist', + input: './src', + loaders: ['vue'], + pattern: ['**/*.vue'], + }, + { + builder: 'mkdist', + format: 'esm', + input: './src', + loaders: ['js'], + pattern: ['**/*.ts'], + }, + ], +}); diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/package.json b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/package.json new file mode 100644 index 0000000..0bb4dc4 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/package.json @@ -0,0 +1,47 @@ +{ + "name": "@vben-core/tabs-ui", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/@vben-core/uikit/tabs-ui" + }, + "license": "MIT", + "type": "module", + "scripts": { + "build": "pnpm unbuild", + "prepublishOnly": "npm run build" + }, + "files": [ + "dist" + ], + "sideEffects": [ + "**/*.css" + ], + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "exports": { + ".": { + "types": "./src/index.ts", + "development": "./src/index.ts", + "default": "./dist/index.mjs" + } + }, + "publishConfig": { + "exports": { + ".": { + "default": "./dist/index.mjs" + } + } + }, + "dependencies": { + "@vben-core/composables": "workspace:*", + "@vben-core/icons": "workspace:*", + "@vben-core/shadcn-ui": "workspace:*", + "@vben-core/typings": "workspace:*", + "@vueuse/core": "catalog:", + "vue": "catalog:" + } +} diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs new file mode 100644 index 0000000..3d80704 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config/postcss'; diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/index.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/index.ts new file mode 100644 index 0000000..eafeaa6 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/index.ts @@ -0,0 +1,2 @@ +export { default as TabsChrome } from './tabs-chrome/tabs.vue'; +export { default as Tabs } from './tabs/tabs.vue'; diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue new file mode 100644 index 0000000..faa1b94 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue new file mode 100644 index 0000000..effa93c --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue @@ -0,0 +1,148 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts new file mode 100644 index 0000000..a26899e --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts @@ -0,0 +1,2 @@ +export { default as TabsToolMore } from './tool-more.vue'; +export { default as TabsToolScreen } from './tool-screen.vue'; diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue new file mode 100644 index 0000000..24f43a9 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue @@ -0,0 +1,18 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue new file mode 100644 index 0000000..acbf14e --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue @@ -0,0 +1,19 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/index.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/index.ts new file mode 100644 index 0000000..6d562db --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/index.ts @@ -0,0 +1,3 @@ +export * from './components/widgets'; +export { default as TabsView } from './tabs-view.vue'; +export type { IContextMenuItem } from '@vben-core/shadcn-ui'; diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue new file mode 100644 index 0000000..7549419 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue @@ -0,0 +1,106 @@ + + + diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/types.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/types.ts new file mode 100644 index 0000000..19ecf03 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/types.ts @@ -0,0 +1,73 @@ +import type { IContextMenuItem } from '@vben-core/shadcn-ui'; +import type { TabDefinition, TabsStyleType } from '@vben-core/typings'; + +export type TabsEmits = { + close: [string]; + sortTabs: [number, number]; + unpin: [TabDefinition]; +}; + +export interface TabsProps { + active?: string; + /** + * @zh_CN content class + * @default tabs-chrome + */ + contentClass?: string; + /** + * @zh_CN 右键菜单 + */ + contextMenus?: (data: any) => IContextMenuItem[]; + /** + * @zh_CN 是否可以拖拽 + */ + draggable?: boolean; + /** + * @zh_CN 间隙 + * @default 7 + * 仅限 tabs-chrome + */ + gap?: number; + /** + * @zh_CN tab 最大宽度 + * 仅限 tabs-chrome + */ + maxWidth?: number; + /** + * @zh_CN 点击中键时关闭Tab + */ + middleClickToClose?: boolean; + + /** + * @zh_CN tab最小宽度 + * 仅限 tabs-chrome + */ + minWidth?: number; + + /** + * @zh_CN 是否显示图标 + */ + showIcon?: boolean; + /** + * @zh_CN 标签页风格 + */ + styleType?: TabsStyleType; + + /** + * @zh_CN 选项卡数据 + */ + tabs?: TabDefinition[]; + + /** + * @zh_CN 是否响应滚轮事件 + */ + wheelable?: boolean; +} + +export interface TabConfig extends TabDefinition { + affixTab: boolean; + closable: boolean; + icon: string; + key: string; + title: string; +} diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts new file mode 100644 index 0000000..b9c2e8a --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts @@ -0,0 +1,124 @@ +import type { Sortable } from '@vben-core/composables'; +import type { EmitType } from '@vben-core/typings'; + +import type { TabsProps } from './types'; + +import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'; + +import { useIsMobile, useSortable } from '@vben-core/composables'; + +// 可能会找到拖拽的子元素,这里需要确保拖拽的dom时tab元素 +function findParentElement(element: HTMLElement) { + const parentCls = 'group'; + return element.classList.contains(parentCls) + ? element + : element.closest(`.${parentCls}`); +} + +export function useTabsDrag(props: TabsProps, emit: EmitType) { + const sortableInstance = ref(null); + + async function initTabsSortable() { + await nextTick(); + + const el = document.querySelectorAll( + `.${props.contentClass}`, + )?.[0] as HTMLElement; + + if (!el) { + console.warn('Element not found for sortable initialization'); + return; + } + + const resetElState = async () => { + el.style.cursor = 'default'; + // el.classList.remove('dragging'); + el.querySelector('.draggable')?.classList.remove('dragging'); + }; + + const { initializeSortable } = useSortable(el, { + filter: (_evt, target: HTMLElement) => { + const parent = findParentElement(target); + const draggable = parent?.classList.contains('draggable'); + return !draggable || !props.draggable; + }, + onEnd(evt) { + const { newIndex, oldIndex } = evt; + // const fromElement = evt.item; + const { srcElement } = (evt as any).originalEvent; + + if (!srcElement) { + resetElState(); + return; + } + + const srcParent = findParentElement(srcElement); + + if (!srcParent) { + resetElState(); + return; + } + + if (!srcParent.classList.contains('draggable')) { + resetElState(); + + return; + } + + if ( + oldIndex !== undefined && + newIndex !== undefined && + !Number.isNaN(oldIndex) && + !Number.isNaN(newIndex) && + oldIndex !== newIndex + ) { + emit('sortTabs', oldIndex, newIndex); + } + resetElState(); + }, + onMove(evt) { + const parent = findParentElement(evt.related); + if (parent?.classList.contains('draggable') && props.draggable) { + const isCurrentAffix = evt.dragged.classList.contains('affix-tab'); + const isRelatedAffix = evt.related.classList.contains('affix-tab'); + // 不允许在固定的tab和非固定的tab之间互相拖拽 + return isCurrentAffix === isRelatedAffix; + } else { + return false; + } + }, + onStart: () => { + el.style.cursor = 'grabbing'; + el.querySelector('.draggable')?.classList.add('dragging'); + // el.classList.add('dragging'); + }, + }); + + sortableInstance.value = await initializeSortable(); + } + + async function init() { + const { isMobile } = useIsMobile(); + + // 移动端下tab不需要拖拽 + if (isMobile.value) { + return; + } + await nextTick(); + initTabsSortable(); + } + + onMounted(init); + + watch( + () => props.styleType, + () => { + sortableInstance.value?.destroy(); + init(); + }, + ); + + onUnmounted(() => { + sortableInstance.value?.destroy(); + }); +} diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts new file mode 100644 index 0000000..aef32df --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts @@ -0,0 +1,202 @@ +import type { TabsProps } from './types'; + +import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'; + +import { VbenScrollbar } from '@vben-core/shadcn-ui'; + +import { useDebounceFn } from '@vueuse/core'; + +type DomElement = Element | null | undefined; + +export function useTabsViewScroll(props: TabsProps) { + let resizeObserver: null | ResizeObserver = null; + let mutationObserver: MutationObserver | null = null; + let tabItemCount = 0; + const scrollbarRef = ref | null>(null); + const scrollViewportEl = ref(null); + const showScrollButton = ref(false); + const scrollIsAtLeft = ref(true); + const scrollIsAtRight = ref(false); + + function getScrollClientWidth() { + const scrollbarEl = scrollbarRef.value?.$el; + if (!scrollbarEl || !scrollViewportEl.value) return {}; + + const scrollbarWidth = scrollbarEl.clientWidth; + const scrollViewWidth = scrollViewportEl.value.clientWidth; + + return { + scrollbarWidth, + scrollViewWidth, + }; + } + + function scrollDirection( + direction: 'left' | 'right', + distance: number = 150, + ) { + const { scrollbarWidth, scrollViewWidth } = getScrollClientWidth(); + + if (!scrollbarWidth || !scrollViewWidth) return; + + if (scrollbarWidth > scrollViewWidth) return; + + scrollViewportEl.value?.scrollBy({ + behavior: 'smooth', + left: + direction === 'left' + ? -(scrollbarWidth - distance) + : +(scrollbarWidth - distance), + }); + } + + async function initScrollbar() { + await nextTick(); + + const scrollbarEl = scrollbarRef.value?.$el; + if (!scrollbarEl) { + return; + } + + const viewportEl = scrollbarEl?.querySelector( + 'div[data-reka-scroll-area-viewport]', + ); + + scrollViewportEl.value = viewportEl; + calcShowScrollbarButton(); + + await nextTick(); + scrollToActiveIntoView(); + + // 监听大小变化 + resizeObserver?.disconnect(); + resizeObserver = new ResizeObserver( + useDebounceFn((_entries: ResizeObserverEntry[]) => { + calcShowScrollbarButton(); + scrollToActiveIntoView(); + }, 100), + ); + resizeObserver.observe(viewportEl); + + tabItemCount = props.tabs?.length || 0; + mutationObserver?.disconnect(); + // 使用 MutationObserver 仅监听子节点数量变化 + mutationObserver = new MutationObserver(() => { + const count = viewportEl.querySelectorAll( + `div[data-tab-item="true"]`, + ).length; + + if (count > tabItemCount) { + scrollToActiveIntoView(); + } + + if (count !== tabItemCount) { + calcShowScrollbarButton(); + tabItemCount = count; + } + }); + + // 配置为仅监听子节点的添加和移除 + mutationObserver.observe(viewportEl, { + attributes: false, + childList: true, + subtree: true, + }); + } + + async function scrollToActiveIntoView() { + if (!scrollViewportEl.value) { + return; + } + await nextTick(); + const viewportEl = scrollViewportEl.value; + const { scrollbarWidth } = getScrollClientWidth(); + const { scrollWidth } = viewportEl; + + if (scrollbarWidth >= scrollWidth) { + return; + } + + requestAnimationFrame(() => { + const activeItem = viewportEl?.querySelector('.is-active'); + activeItem?.scrollIntoView({ behavior: 'smooth', inline: 'start' }); + }); + } + + /** + * 计算tabs 宽度,用于判断是否显示左右滚动按钮 + */ + async function calcShowScrollbarButton() { + if (!scrollViewportEl.value) { + return; + } + + const { scrollbarWidth } = getScrollClientWidth(); + + showScrollButton.value = + scrollViewportEl.value.scrollWidth > scrollbarWidth; + } + + const handleScrollAt = useDebounceFn(({ left, right }) => { + scrollIsAtLeft.value = left; + scrollIsAtRight.value = right; + }, 100); + + function handleWheel({ deltaY }: WheelEvent) { + scrollViewportEl.value?.scrollBy({ + // behavior: 'smooth', + left: deltaY * 3, + }); + } + + watch( + () => props.active, + async () => { + // 200为了等待 tab 切换动画完成 + // setTimeout(() => { + scrollToActiveIntoView(); + // }, 300); + }, + { + flush: 'post', + }, + ); + + // watch( + // () => props.tabs?.length, + // async () => { + // await nextTick(); + // calcShowScrollbarButton(); + // }, + // { + // flush: 'post', + // }, + // ); + + watch( + () => props.styleType, + () => { + initScrollbar(); + }, + ); + + onMounted(initScrollbar); + + onUnmounted(() => { + resizeObserver?.disconnect(); + mutationObserver?.disconnect(); + resizeObserver = null; + mutationObserver = null; + }); + + return { + handleScrollAt, + handleWheel, + initScrollbar, + scrollbarRef, + scrollDirection, + scrollIsAtLeft, + scrollIsAtRight, + showScrollButton, + }; +} diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs new file mode 100644 index 0000000..f17f556 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config'; diff --git a/admin-ui/vue/packages/@core/ui-kit/tabs-ui/tsconfig.json b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/@core/ui-kit/tabs-ui/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/constants/README.md b/admin-ui/vue/packages/constants/README.md new file mode 100644 index 0000000..67936a6 --- /dev/null +++ b/admin-ui/vue/packages/constants/README.md @@ -0,0 +1,19 @@ +# @vben/constants + +用于多个 `app` 公用的常量,继承了 `@vben-core/shared/constants` 的所有能力。业务上有通用常量可以放在这里。 + +## 用法 + +### 添加依赖 + +```bash +# 进入目标应用目录,例如 apps/xxxx-app +# cd apps/xxxx-app +pnpm add @vben/constants +``` + +### 使用 + +```ts +import { LOGIN_PATH } from '@vben/constants'; +``` diff --git a/admin-ui/vue/packages/constants/package.json b/admin-ui/vue/packages/constants/package.json new file mode 100644 index 0000000..249418f --- /dev/null +++ b/admin-ui/vue/packages/constants/package.json @@ -0,0 +1,25 @@ +{ + "name": "@vben/constants", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/constants" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/shared": "workspace:*" + } +} diff --git a/admin-ui/vue/packages/constants/src/core.ts b/admin-ui/vue/packages/constants/src/core.ts new file mode 100644 index 0000000..7d56375 --- /dev/null +++ b/admin-ui/vue/packages/constants/src/core.ts @@ -0,0 +1,29 @@ +/** + * @zh_CN 登录页面 url 地址 + */ +export const LOGIN_PATH = '/auth/login'; + +/** + * @zh_CN 默认首页地址 + */ +export const DEFAULT_HOME_PATH = '/analytics'; + + +export interface LanguageOption { + label: string; + value: 'en-US' | 'zh-CN'; +} + +/** + * Supported languages + */ +export const SUPPORT_LANGUAGES: LanguageOption[] = [ + { + label: '简体中文', + value: 'zh-CN', + }, + { + label: 'English', + value: 'en-US', + }, +]; diff --git a/admin-ui/vue/packages/constants/src/dict-enum.ts b/admin-ui/vue/packages/constants/src/dict-enum.ts new file mode 100644 index 0000000..8a3d3e7 --- /dev/null +++ b/admin-ui/vue/packages/constants/src/dict-enum.ts @@ -0,0 +1,23 @@ +export enum DictEnum { + SYS_COMMON_STATUS = 'sys_common_status', + SYS_DEVICE_TYPE = 'sys_device_type', // 设备类型 + SYS_GRANT_TYPE = 'sys_grant_type', // 授权类型 + SYS_NORMAL_DISABLE = 'sys_normal_disable', // 字符状态0正常1启用 + SYS_DEPT_TYPE = 'sys_dept_type', // 组织类型0部门1公司 + SYS_NOTICE_STATUS = 'sys_notice_status', // 通知状态 + SYS_NOTICE_TYPE = 'sys_notice_type', // 通知类型 + SYS_OPER_TYPE = 'sys_oper_type', // 操作类型 + SYS_OSS_ACCESS_POLICY = 'oss_access_policy', // oss权限桶类型 + SYS_SHOW_HIDE = 'sys_show_hide', // 显示状态 + SYS_USER_SEX = 'sys_user_sex', // 性别 + SYS_YES_NO = 'sys_yes_no', // 是否 + SYS_YES_NO_NUM = 'sys_yes_no_num', // 是否数字 + SYS_GEN_STATUS = 'sys_gen_status', // 生成状态 + WF_BUSINESS_STATUS = 'wf_business_status', // 业务状态 + WF_FORM_TYPE = 'wf_form_type', // 表单类型 + WF_TASK_STATUS = 'wf_task_status', // 任务状态 + SYS_JOB_GROUP = 'sys_job_group', // 任务分组 + SYS_MISSFIRE_POLICY = 'sys_missfire_policy', // 任务计划执行策略\ + SYS_JOB_CONCURRENT = 'sys_job_concurrent', // 任务是否并发 + AGENT_SCOPE_TYPE = 'agent_scope_type', // 渠道适用类型:0-所有客户 1-指定客户 +} diff --git a/admin-ui/vue/packages/constants/src/index.ts b/admin-ui/vue/packages/constants/src/index.ts new file mode 100644 index 0000000..8870dbb --- /dev/null +++ b/admin-ui/vue/packages/constants/src/index.ts @@ -0,0 +1,3 @@ +export * from './core'; +export * from '@vben-core/shared/constants'; +export * from './dict-enum'; \ No newline at end of file diff --git a/admin-ui/vue/packages/constants/tsconfig.json b/admin-ui/vue/packages/constants/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/constants/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/effects/README.md b/admin-ui/vue/packages/effects/README.md new file mode 100644 index 0000000..4965b51 --- /dev/null +++ b/admin-ui/vue/packages/effects/README.md @@ -0,0 +1,10 @@ +## Effects 目录 + +`effects` 目录专门用于存放与轻微耦合相关的代码和逻辑。如果你的包具有以下特点,建议将其放置在 `effects` 目录下: + +- **状态管理**:使用状态管理框架 `pinia`,并包含处理副作用(如异步操作、API 调用)的部分。 +- **用户偏好设置**:使用 `@vben-core/preferences` 处理用户偏好设置,涉及本地存储或浏览器缓存逻辑(如使用 `localStorage`)。 +- **导航和路由**:处理导航、页面跳转等场景,需要管理路由变化的逻辑。 +- **组件库依赖**:包含与特定组件库紧密耦合或依赖大型仓库的部分。 + +通过将相关代码归类到 `effects` 目录,可以使项目结构更加清晰,便于维护和扩展。 diff --git a/admin-ui/vue/packages/effects/access/package.json b/admin-ui/vue/packages/effects/access/package.json new file mode 100644 index 0000000..c23018a --- /dev/null +++ b/admin-ui/vue/packages/effects/access/package.json @@ -0,0 +1,29 @@ +{ + "name": "@vben/access", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/effects/permissions" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben/preferences": "workspace:*", + "@vben/stores": "workspace:*", + "@vben/types": "workspace:*", + "@vben/utils": "workspace:*", + "vue": "catalog:" + } +} diff --git a/admin-ui/vue/packages/effects/access/src/access-control.vue b/admin-ui/vue/packages/effects/access/src/access-control.vue new file mode 100644 index 0000000..370e995 --- /dev/null +++ b/admin-ui/vue/packages/effects/access/src/access-control.vue @@ -0,0 +1,47 @@ + + + + diff --git a/admin-ui/vue/packages/effects/access/src/accessible.ts b/admin-ui/vue/packages/effects/access/src/accessible.ts new file mode 100644 index 0000000..73e253a --- /dev/null +++ b/admin-ui/vue/packages/effects/access/src/accessible.ts @@ -0,0 +1,184 @@ +import type { Component, DefineComponent } from 'vue'; + +import type { + AccessModeType, + GenerateMenuAndRoutesOptions, + RouteRecordRaw, +} from '@vben/types'; + +import { defineComponent, h } from 'vue'; + +import { + cloneDeep, + generateMenus, + generateRoutesByBackend, + generateRoutesByFrontend, + isFunction, + isString, + mapTree, +} from '@vben/utils'; + +async function generateAccessible( + mode: AccessModeType, + options: GenerateMenuAndRoutesOptions, +) { + const { router } = options; + + options.routes = cloneDeep(options.routes); + // 生成路由 + const accessibleRoutes = await generateRoutes(mode, options); + + const root = findRootRoute(router); + + // 获取已有的路由名称列表 + const names = root?.children?.map((item) => item.name) ?? []; + + // 动态添加到router实例内 + accessibleRoutes.forEach((route) => { + if (root && !route.meta?.noBasicLayout) { + // 为了兼容之前的版本用法,如果包含子路由,则将component移除,以免出现多层BasicLayout + // 如果你的项目已经跟进了本次修改,移除了所有自定义菜单首级的BasicLayout,可以将这段if代码删除 + if (route.children && route.children.length > 0) { + delete route.component; + } + // 根据router name判断,如果路由已经存在,则不再添加 + if (names?.includes(route.name)) { + // 找到已存在的路由索引并更新,不更新会造成切换用户时,一级目录未更新,homePath 在二级目录导致的404问题 + const index = root.children?.findIndex( + (item) => item.name === route.name, + ); + if (index !== undefined && index !== -1 && root.children) { + root.children[index] = route; + } + } else { + root.children?.push(route); + } + } else { + router.addRoute(route); + } + }); + + if (root) { + if (root.name) { + router.removeRoute(root.name); + } + router.addRoute(root); + } + + // 生成菜单 + const accessibleMenus = generateMenus(accessibleRoutes, options.router); + + return { accessibleMenus, accessibleRoutes }; +} + +function findRootRoute(router: GenerateMenuAndRoutesOptions['router']) { + const routes = router.getRoutes(); + + // Route paths are not unique: an empty-path backend child can normalize to '/'. + const namedRoot = routes.find((item) => item.name === 'Root'); + if (namedRoot) { + return namedRoot; + } + + // Keep a path-independent fallback for applications that rename the core route. + const titledRoot = routes.find((item) => item.meta.title === 'Root'); + if (titledRoot) { + return titledRoot; + } + + const childNames = new Set( + routes.flatMap((item) => item.children?.map((child) => child.name) ?? []), + ); + const topLevelLayouts = routes.filter( + (item) => + item.children?.length && + !item.aliasOf && + (item.name === undefined || !childNames.has(item.name)), + ); + + return topLevelLayouts.length === 1 ? topLevelLayouts[0] : undefined; +} + +/** + * Generate routes + * @param mode + * @param options + */ +async function generateRoutes( + mode: AccessModeType, + options: GenerateMenuAndRoutesOptions, +) { + const { forbiddenComponent, roles, routes } = options; + + let resultRoutes: RouteRecordRaw[] = routes; + switch (mode) { + case 'backend': { + resultRoutes = await generateRoutesByBackend(options); + break; + } + case 'frontend': { + resultRoutes = await generateRoutesByFrontend( + routes, + roles || [], + forbiddenComponent, + ); + break; + } + case 'mixed': { + const [frontend_resultRoutes, backend_resultRoutes] = await Promise.all([ + generateRoutesByFrontend(routes, roles || [], forbiddenComponent), + generateRoutesByBackend(options), + ]); + + resultRoutes = [...frontend_resultRoutes, ...backend_resultRoutes]; + break; + } + } + + /** + * 调整路由树,做以下处理: + * 1. 对未添加redirect的路由添加redirect + * 2. 将懒加载的组件名称修改为当前路由的名称(如果启用了keep-alive的话) + */ + resultRoutes = mapTree(resultRoutes, (route) => { + // 重新包装component,使用与路由名称相同的name以支持keep-alive的条件缓存。 + if ( + route.meta?.keepAlive && + isFunction(route.component) && + route.name && + isString(route.name) + ) { + const originalComponent = route.component as () => Promise<{ + default: Component | DefineComponent; + }>; + route.component = async () => { + const component = await originalComponent(); + if (!component.default) return component; + return defineComponent({ + name: route.name as string, + setup(props, { attrs, slots }) { + return () => h(component.default, { ...props, ...attrs }, slots); + }, + }); + }; + } + + // 如果有redirect或者没有子路由,则直接返回 + if (route.redirect || !route.children || route.children.length === 0) { + return route; + } + const firstChild = route.children[0]; + + // 如果子路由不是以/开头,则直接返回,这种情况需要计算全部父级的path才能得出正确的path,这里不做处理 + if (!firstChild?.path || !firstChild.path.startsWith('/')) { + return route; + } + + route.redirect = firstChild.path; + return route; + }); + + return resultRoutes; +} + +export { generateAccessible }; diff --git a/admin-ui/vue/packages/effects/access/src/directive.ts b/admin-ui/vue/packages/effects/access/src/directive.ts new file mode 100644 index 0000000..35d9d51 --- /dev/null +++ b/admin-ui/vue/packages/effects/access/src/directive.ts @@ -0,0 +1,42 @@ +/** + * Global authority directive + * Used for fine-grained control of component permissions + * @Example v-access:role="[ROLE_NAME]" or v-access:role="ROLE_NAME" + * @Example v-access:code="[ROLE_CODE]" or v-access:code="ROLE_CODE" + */ +import type { App, Directive, DirectiveBinding } from 'vue'; + +import { useAccess } from './use-access'; + +function isAccessible( + el: Element, + binding: DirectiveBinding, +) { + const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess(); + + const value = binding.value; + + if (!value) return; + const authMethod = + accessMode.value === 'frontend' && binding.arg === 'role' + ? hasAccessByRoles + : hasAccessByCodes; + + const values = Array.isArray(value) ? value : [value]; + + if (!authMethod(values)) { + el?.remove(); + } +} + +const mounted = (el: Element, binding: DirectiveBinding) => { + isAccessible(el, binding); +}; + +const authDirective: Directive = { + mounted, +}; + +export function registerAccessDirective(app: App) { + app.directive('access', authDirective); +} diff --git a/admin-ui/vue/packages/effects/access/src/index.ts b/admin-ui/vue/packages/effects/access/src/index.ts new file mode 100644 index 0000000..392aa53 --- /dev/null +++ b/admin-ui/vue/packages/effects/access/src/index.ts @@ -0,0 +1,4 @@ +export { default as AccessControl } from './access-control.vue'; +export * from './accessible'; +export * from './directive'; +export * from './use-access'; diff --git a/admin-ui/vue/packages/effects/access/src/use-access.ts b/admin-ui/vue/packages/effects/access/src/use-access.ts new file mode 100644 index 0000000..939cdbe --- /dev/null +++ b/admin-ui/vue/packages/effects/access/src/use-access.ts @@ -0,0 +1,53 @@ +import { computed } from 'vue'; + +import { preferences, updatePreferences } from '@vben/preferences'; +import { useAccessStore, useUserStore } from '@vben/stores'; + +function useAccess() { + const accessStore = useAccessStore(); + const userStore = useUserStore(); + const accessMode = computed(() => { + return preferences.app.accessMode; + }); + + /** + * 基于角色判断是否有权限 + * @description: Determine whether there is permission,The role is judged by the user's role + * @param roles + */ + function hasAccessByRoles(roles: string[]) { + const userRoleSet = new Set(userStore.userRoles); + const intersection = roles.filter((item) => userRoleSet.has(item)); + return intersection.length > 0; + } + + /** + * 基于权限码判断是否有权限 + * @description: Determine whether there is permission,The permission code is judged by the user's permission code + * @param codes + */ + function hasAccessByCodes(codes: string[]) { + const userCodesSet = new Set(accessStore.accessCodes); + + const intersection = codes.filter((item) => userCodesSet.has(item)); + return intersection.length > 0; + } + + async function toggleAccessMode() { + updatePreferences({ + app: { + accessMode: + preferences.app.accessMode === 'frontend' ? 'backend' : 'frontend', + }, + }); + } + + return { + accessMode, + hasAccessByCodes, + hasAccessByRoles, + toggleAccessMode, + }; +} + +export { useAccess }; diff --git a/admin-ui/vue/packages/effects/access/tsconfig.json b/admin-ui/vue/packages/effects/access/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/effects/access/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/effects/common-ui/package.json b/admin-ui/vue/packages/effects/common-ui/package.json new file mode 100644 index 0000000..5a34a26 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/package.json @@ -0,0 +1,54 @@ +{ + "name": "@vben/common-ui", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/effects/common-ui" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./es/tippy": { + "types": "./src/components/tippy/index.ts", + "default": "./src/components/tippy/index.ts" + }, + "./es/loading": { + "types": "./src/components/loading/index.ts", + "default": "./src/components/loading/index.ts" + } + }, + "dependencies": { + "@vben-core/form-ui": "workspace:*", + "@vben-core/popup-ui": "workspace:*", + "@vben-core/preferences": "workspace:*", + "@vben-core/shadcn-ui": "workspace:*", + "@vben-core/shared": "workspace:*", + "@vben/constants": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/locales": "workspace:*", + "@vben/types": "workspace:*", + "@vueuse/core": "catalog:", + "@vueuse/integrations": "catalog:", + "json-bigint": "catalog:", + "qrcode": "catalog:", + "tippy.js": "catalog:", + "vue": "catalog:", + "vue-json-viewer": "catalog:", + "vue-router": "catalog:", + "vue-tippy": "catalog:" + }, + "devDependencies": { + "@types/qrcode": "catalog:" + } +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/api-component/api-component.vue b/admin-ui/vue/packages/effects/common-ui/src/components/api-component/api-component.vue new file mode 100644 index 0000000..38419a7 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/api-component/api-component.vue @@ -0,0 +1,299 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/api-component/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/api-component/index.ts new file mode 100644 index 0000000..9815763 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/api-component/index.ts @@ -0,0 +1 @@ +export { default as ApiComponent } from './api-component.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts new file mode 100644 index 0000000..a3f61fd --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts @@ -0,0 +1,19 @@ +import type { CaptchaPoint } from '../types'; + +import { reactive } from 'vue'; + +export function useCaptchaPoints() { + const points = reactive([]); + function addPoint(point: CaptchaPoint) { + points.push(point); + } + + function clearPoints() { + points.splice(0); + } + return { + addPoint, + clearPoints, + points, + }; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/index.ts new file mode 100644 index 0000000..13634cd --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/index.ts @@ -0,0 +1,7 @@ +export { default as PointSelectionCaptcha } from './point-selection-captcha/index.vue'; +export { default as PointSelectionCaptchaCard } from './point-selection-captcha/index.vue'; + +export { default as SliderCaptcha } from './slider-captcha/index.vue'; +export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue'; +export { default as SliderTranslateCaptcha } from './slider-translate-captcha/index.vue'; +export type * from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue new file mode 100644 index 0000000..ece28d0 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue @@ -0,0 +1,176 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue new file mode 100644 index 0000000..dcb8039 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue @@ -0,0 +1,84 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue new file mode 100644 index 0000000..cad3cdd --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue @@ -0,0 +1,244 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue new file mode 100644 index 0000000..7f97bdc --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue @@ -0,0 +1,65 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue new file mode 100644 index 0000000..0884ccb --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue @@ -0,0 +1,40 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue new file mode 100644 index 0000000..0e79f7b --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue new file mode 100644 index 0000000..8894589 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue @@ -0,0 +1,213 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue new file mode 100644 index 0000000..81b7342 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue @@ -0,0 +1,311 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/captcha/types.ts b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/types.ts new file mode 100644 index 0000000..cd1efdf --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/captcha/types.ts @@ -0,0 +1,211 @@ +import type { CSSProperties } from 'vue'; + +import type { ClassType } from '@vben/types'; + +export interface CaptchaData { + /** + * x + */ + x: number; + /** + * y + */ + y: number; + /** + * 时间戳 + */ + t: number; +} +export interface CaptchaPoint extends CaptchaData { + /** + * 数据索引 + */ + i: number; +} +export interface PointSelectionCaptchaCardProps { + /** + * 验证码图片 + */ + captchaImage: string; + /** + * 验证码图片高度 + * @default '220px' + */ + height?: number | string; + /** + * 水平内边距 + * @default '12px' + */ + paddingX?: number | string; + /** + * 垂直内边距 + * @default '16px' + */ + paddingY?: number | string; + /** + * 标题 + * @default '请按图依次点击' + */ + title?: string; + /** + * 验证码图片宽度 + * @default '300px' + */ + width?: number | string; +} + +export interface PointSelectionCaptchaProps + extends PointSelectionCaptchaCardProps { + /** + * 是否展示确定按钮 + * @default false + */ + showConfirm?: boolean; + /** + * 提示图片 + * @default '' + */ + hintImage?: string; + /** + * 提示文本 + * @default '' + */ + hintText?: string; +} + +export interface SliderCaptchaProps { + class?: ClassType; + /** + * @description 滑块的样式 + * @default {} + */ + actionStyle?: CSSProperties; + + /** + * @description 滑块条的样式 + * @default {} + */ + barStyle?: CSSProperties; + + /** + * @description 内容的样式 + * @default {} + */ + contentStyle?: CSSProperties; + + /** + * @description 组件的样式 + * @default {} + */ + wrapperStyle?: CSSProperties; + + /** + * @description 是否作为插槽使用,用于联动组件,可参考旋转校验组件 + * @default false + */ + isSlot?: boolean; + + /** + * @description 验证成功的提示 + * @default '验证通过' + */ + successText?: string; + + /** + * @description 提示文字 + * @default '请按住滑块拖动' + */ + text?: string; +} + +export interface SliderRotateCaptchaProps { + /** + * @description 旋转的角度 + * @default 20 + */ + diffDegree?: number; + + /** + * @description 图片的宽度 + * @default 260 + */ + imageSize?: number; + + /** + * @description 图片的样式 + * @default {} + */ + imageWrapperStyle?: CSSProperties; + + /** + * @description 最大旋转角度 + * @default 270 + */ + maxDegree?: number; + + /** + * @description 最小旋转角度 + * @default 90 + */ + minDegree?: number; + + /** + * @description 图片的地址 + */ + src?: string; + /** + * @description 默认提示文本 + */ + defaultTip?: string; +} + +export interface SliderTranslateCaptchaProps { + /** + * @description 拼图的宽度 + * @default 420 + */ + canvasWidth?: number; + /** + * @description 拼图的高度 + * @default 280 + */ + canvasHeight?: number; + /** + * @description 切块上正方形的长度 + * @default 42 + */ + squareLength?: number; + /** + * @description 切块上圆形的半径 + * @default 10 + */ + circleRadius?: number; + /** + * @description 图片的地址 + */ + src?: string; + /** + * @description 允许的最大差距 + * @default 3 + */ + diffDistance?: number; + /** + * @description 默认提示文本 + */ + defaultTip?: string; +} + +export interface CaptchaVerifyPassingData { + isPassing: boolean; + time: number | string; +} + +export interface SliderCaptchaActionType { + resume: () => void; +} + +export interface SliderRotateVerifyPassingData { + event: MouseEvent | TouchEvent; + moveDistance: number; + moveX: number; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/col-page/col-page.vue b/admin-ui/vue/packages/effects/common-ui/src/components/col-page/col-page.vue new file mode 100644 index 0000000..c3f9d68 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/col-page/col-page.vue @@ -0,0 +1,107 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/col-page/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/col-page/index.ts new file mode 100644 index 0000000..11b3305 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/col-page/index.ts @@ -0,0 +1,2 @@ +export { default as ColPage } from './col-page.vue'; +export * from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/col-page/types.ts b/admin-ui/vue/packages/effects/common-ui/src/components/col-page/types.ts new file mode 100644 index 0000000..491d1e6 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/col-page/types.ts @@ -0,0 +1,26 @@ +import type { PageProps } from '../page/types'; + +export interface ColPageProps extends PageProps { + /** + * 左侧宽度 + * @default 30 + */ + leftWidth?: number; + leftMinWidth?: number; + leftMaxWidth?: number; + leftCollapsedWidth?: number; + leftCollapsible?: boolean; + /** + * 右侧宽度 + * @default 70 + */ + rightWidth?: number; + rightMinWidth?: number; + rightCollapsedWidth?: number; + rightMaxWidth?: number; + rightCollapsible?: boolean; + + resizable?: boolean; + splitLine?: boolean; + splitHandle?: boolean; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/count-to/count-to.vue b/admin-ui/vue/packages/effects/common-ui/src/components/count-to/count-to.vue new file mode 100644 index 0000000..d6b0943 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/count-to/count-to.vue @@ -0,0 +1,123 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/count-to/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/count-to/index.ts new file mode 100644 index 0000000..d942796 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/count-to/index.ts @@ -0,0 +1,2 @@ +export { default as CountTo } from './count-to.vue'; +export * from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/count-to/types.ts b/admin-ui/vue/packages/effects/common-ui/src/components/count-to/types.ts new file mode 100644 index 0000000..0b3bd82 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/count-to/types.ts @@ -0,0 +1,53 @@ +import type { CubicBezierPoints, EasingFunction } from '@vueuse/core'; + +import type { StyleValue } from 'vue'; + +import { TransitionPresets as TransitionPresetsData } from '@vueuse/core'; + +export type TransitionPresets = keyof typeof TransitionPresetsData; + +export const TransitionPresetsKeys = Object.keys( + TransitionPresetsData, +) as TransitionPresets[]; + +export interface CountToProps { + /** 初始值 */ + startVal?: number; + /** 当前值 */ + endVal: number; + /** 是否禁用动画 */ + disabled?: boolean; + /** 延迟动画开始的时间 */ + delay?: number; + /** 持续时间 */ + duration?: number; + /** 小数位数 */ + decimals?: number; + /** 小数点 */ + decimal?: string; + /** 分隔符 */ + separator?: string; + /** 前缀 */ + prefix?: string; + /** 后缀 */ + suffix?: string; + /** 过渡效果 */ + transition?: CubicBezierPoints | EasingFunction | TransitionPresets; + /** 整数部分的类名 */ + mainClass?: string; + /** 小数部分的类名 */ + decimalClass?: string; + /** 前缀部分的类名 */ + prefixClass?: string; + /** 后缀部分的类名 */ + suffixClass?: string; + + /** 整数部分的样式 */ + mainStyle?: StyleValue; + /** 小数部分的样式 */ + decimalStyle?: StyleValue; + /** 前缀部分的样式 */ + prefixStyle?: StyleValue; + /** 后缀部分的样式 */ + suffixStyle?: StyleValue; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue b/admin-ui/vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue new file mode 100644 index 0000000..12f44bd --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue @@ -0,0 +1,232 @@ + + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/ellipsis-text/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/ellipsis-text/index.ts new file mode 100644 index 0000000..67a236c --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/ellipsis-text/index.ts @@ -0,0 +1 @@ +export { default as EllipsisText } from './ellipsis-text.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue b/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue new file mode 100644 index 0000000..c602274 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue @@ -0,0 +1,318 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/icons.ts b/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/icons.ts new file mode 100644 index 0000000..694e904 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/icons.ts @@ -0,0 +1,56 @@ +import type { Recordable } from '@vben/types'; + +/** + * 一个缓存对象,在不刷新页面时,无需重复请求远程接口 + */ +export const ICONS_MAP: Recordable = {}; + +interface IconifyResponse { + prefix: string; + total: number; + title: string; + uncategorized?: string[]; + categories?: Recordable; + aliases?: Recordable; +} + +const PENDING_REQUESTS: Recordable> = {}; + +/** + * 通过Iconify接口获取图标集数据。 + * 同一时间多个图标选择器同时请求同一个图标集时,实际上只会发起一次请求(所有请求共享同一份结果)。 + * 请求结果会被缓存,刷新页面前同一个图标集不会再次请求 + * @param prefix 图标集名称 + * @returns 图标集中包含的所有图标名称 + */ +export async function fetchIconsData(prefix: string): Promise { + if (Reflect.has(ICONS_MAP, prefix) && ICONS_MAP[prefix]) { + return ICONS_MAP[prefix]; + } + if (Reflect.has(PENDING_REQUESTS, prefix) && PENDING_REQUESTS[prefix]) { + return PENDING_REQUESTS[prefix]; + } + PENDING_REQUESTS[prefix] = (async () => { + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 1000 * 10); + const response: IconifyResponse = await fetch( + `https://api.iconify.design/collection?prefix=${prefix}`, + { signal: controller.signal }, + ).then((res) => res.json()); + clearTimeout(timeoutId); + const list = response.uncategorized || []; + if (response.categories) { + for (const category in response.categories) { + list.push(...(response.categories[category] || [])); + } + } + ICONS_MAP[prefix] = list.map((v) => `${prefix}:${v}`); + } catch (error) { + console.error(`Failed to fetch icons for prefix ${prefix}:`, error); + return [] as string[]; + } + return ICONS_MAP[prefix]; + })(); + return PENDING_REQUESTS[prefix]; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/index.ts new file mode 100644 index 0000000..3dabc86 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/icon-picker/index.ts @@ -0,0 +1 @@ +export { default as IconPicker } from './icon-picker.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/index.ts new file mode 100644 index 0000000..9ff0d5e --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/index.ts @@ -0,0 +1,35 @@ +export * from './api-component'; +export * from './captcha'; +export * from './col-page'; +export * from './count-to'; +export * from './ellipsis-text'; +export * from './icon-picker'; +export * from './json-viewer'; +export * from './loading'; +export * from './page'; +export * from './resize'; +export * from './tippy'; +export * from './tree'; +export * from '@vben-core/form-ui'; +export * from '@vben-core/popup-ui'; + +// 给文档用 +export { + VbenAvatar, + VbenButton, + VbenButtonGroup, + VbenCheckbox, + VbenCheckButtonGroup, + VbenContextMenu, + VbenCountToAnimator, + VbenFullScreen, + VbenInputPassword, + VbenLoading, + VbenLogo, + VbenPinInput, + VbenSelect, + VbenSpinner, +} from '@vben-core/shadcn-ui'; + +export type { FlattenedItem } from '@vben-core/shadcn-ui'; +export { globalShareState } from '@vben-core/shared/global-state'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/json-preview/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/json-preview/index.ts new file mode 100644 index 0000000..332d22c --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/json-preview/index.ts @@ -0,0 +1 @@ +export { default as JsonPreview } from './json-preview.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue b/admin-ui/vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue new file mode 100644 index 0000000..58c7aaa --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/index.ts new file mode 100644 index 0000000..1aec78b --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/index.ts @@ -0,0 +1,3 @@ +export { default as JsonViewer } from './index.vue'; + +export * from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/index.vue b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/index.vue new file mode 100644 index 0000000..f66c318 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/index.vue @@ -0,0 +1,112 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/style.scss b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/style.scss new file mode 100644 index 0000000..47acb89 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/style.scss @@ -0,0 +1,98 @@ +.default-json-theme { + font-family: Consolas, Menlo, Courier, monospace; + font-size: 14px; + color: hsl(var(--foreground)); + white-space: nowrap; + background: hsl(var(--background)); + + &.jv-container.boxed { + border: 1px solid hsl(var(--border)); + } + + .jv-ellipsis { + display: inline-block; + padding: 0 4px 2px; + font-size: 0.9em; + line-height: 0.9; + vertical-align: 2px; + color: hsl(var(--secondary-foreground)); + cursor: pointer; + user-select: none; + background-color: hsl(var(--secondary)); + border-radius: 3px; + } + + .jv-button { + color: hsl(var(--primary)); + } + + .jv-key { + color: hsl(var(--heavy-foreground)); + } + + .jv-item { + &.jv-array { + color: hsl(var(--heavy-foreground)); + } + + &.jv-boolean { + color: hsl(var(--red-400)); + } + + &.jv-function { + color: hsl(var(--destructive-foreground)); + } + + &.jv-number { + color: hsl(var(--info-foreground)); + } + + &.jv-number-float { + color: hsl(var(--info-foreground)); + } + + &.jv-number-integer { + color: hsl(var(--info-foreground)); + } + + &.jv-object { + color: hsl(var(--accent-darker)); + } + + &.jv-undefined { + color: hsl(var(--secondary-foreground)); + } + + &.jv-string { + color: hsl(var(--primary)); + overflow-wrap: break-word; + white-space: normal; + } + } + + &.jv-container .jv-code { + padding: 10px; + + &.boxed:not(.open) { + padding-bottom: 20px; + margin-bottom: 10px; + } + + &.open { + padding-bottom: 10px; + } + + .jv-toggle { + &::before { + padding: 0 2px; + border-radius: 2px; + } + + &:hover { + &::before { + background: hsl(var(--accent-foreground)); + } + } + } + } +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/types.ts b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/types.ts new file mode 100644 index 0000000..8f3a206 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/json-viewer/types.ts @@ -0,0 +1,44 @@ +export interface JsonViewerProps { + /** 要展示的结构数据 */ + value: any; + /** 展开深度 */ + expandDepth?: number; + /** 是否可复制 */ + copyable?: boolean; + /** 是否排序 */ + sort?: boolean; + /** 显示边框 */ + boxed?: boolean; + /** 主题 */ + theme?: string; + /** 是否展开 */ + expanded?: boolean; + /** 时间格式化函数 */ + timeformat?: (time: Date | number | string) => string; + /** 预览模式 */ + previewMode?: boolean; + /** 显示数组索引 */ + showArrayIndex?: boolean; + /** 显示双引号 */ + showDoubleQuotes?: boolean; +} + +export interface JsonViewerAction { + action: string; + text: string; + trigger: HTMLElement; +} + +export interface JsonViewerValue { + value: any; + path: string; + depth: number; + el: HTMLElement; +} + +export interface JsonViewerToggle { + /** 鼠标事件 */ + event: MouseEvent; + /** 当前展开状态 */ + open: boolean; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/loading/directive.ts b/admin-ui/vue/packages/effects/common-ui/src/components/loading/directive.ts new file mode 100644 index 0000000..973a605 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/loading/directive.ts @@ -0,0 +1,132 @@ +import type { App, Directive, DirectiveBinding } from 'vue'; + +import { h, render } from 'vue'; + +import { VbenLoading, VbenSpinner } from '@vben-core/shadcn-ui'; +import { isString } from '@vben-core/shared/utils'; + +const LOADING_INSTANCE_KEY = Symbol('loading'); +const SPINNER_INSTANCE_KEY = Symbol('spinner'); + +const CLASS_NAME_RELATIVE = 'spinner-parent--relative'; + +const loadingDirective: Directive = { + mounted(el, binding) { + const instance = h(VbenLoading, getOptions(binding)); + render(instance, el); + + el.classList.add(CLASS_NAME_RELATIVE); + el[LOADING_INSTANCE_KEY] = instance; + }, + unmounted(el) { + const instance = el[LOADING_INSTANCE_KEY]; + el.classList.remove(CLASS_NAME_RELATIVE); + render(null, el); + instance.el.remove(); + + el[LOADING_INSTANCE_KEY] = null; + }, + + updated(el, binding) { + const instance = el[LOADING_INSTANCE_KEY]; + const options = getOptions(binding); + if (options && instance?.component) { + try { + Object.keys(options).forEach((key) => { + instance.component.props[key] = options[key]; + }); + instance.component.update(); + } catch (error) { + console.error( + 'Failed to update loading component in directive:', + error, + ); + } + } + }, +}; + +function getOptions(binding: DirectiveBinding) { + if (binding.value === undefined) { + return { spinning: true }; + } else if (typeof binding.value === 'boolean') { + return { spinning: binding.value }; + } else { + return { ...binding.value }; + } +} + +const spinningDirective: Directive = { + mounted(el, binding) { + const instance = h(VbenSpinner, getOptions(binding)); + render(instance, el); + + el.classList.add(CLASS_NAME_RELATIVE); + el[SPINNER_INSTANCE_KEY] = instance; + }, + unmounted(el) { + const instance = el[SPINNER_INSTANCE_KEY]; + el.classList.remove(CLASS_NAME_RELATIVE); + render(null, el); + instance.el.remove(); + + el[SPINNER_INSTANCE_KEY] = null; + }, + + updated(el, binding) { + const instance = el[SPINNER_INSTANCE_KEY]; + const options = getOptions(binding); + if (options && instance?.component) { + try { + Object.keys(options).forEach((key) => { + instance.component.props[key] = options[key]; + }); + instance.component.update(); + } catch (error) { + console.error( + 'Failed to update spinner component in directive:', + error, + ); + } + } + }, +}; + +type loadingDirectiveParams = { + /** 是否注册loading指令。如果提供一个string,则将指令注册为指定的名称 */ + loading?: boolean | string; + /** 是否注册spinning指令。如果提供一个string,则将指令注册为指定的名称 */ + spinning?: boolean | string; +}; + +/** + * 注册loading指令 + * @param app + * @param params + */ +export function registerLoadingDirective( + app: App, + params?: loadingDirectiveParams, +) { + // 注入一个样式供指令使用,确保容器是相对定位 + const style = document.createElement('style'); + style.id = CLASS_NAME_RELATIVE; + style.innerHTML = ` + .${CLASS_NAME_RELATIVE} { + position: relative !important; + } + `; + document.head.append(style); + if (params?.loading !== false) { + app.directive( + isString(params?.loading) ? params.loading : 'loading', + loadingDirective, + ); + } + if (params?.spinning !== false) { + app.directive( + isString(params?.spinning) ? params.spinning : 'spinning', + spinningDirective, + ); + } +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/loading/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/loading/index.ts new file mode 100644 index 0000000..2fbfb04 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/loading/index.ts @@ -0,0 +1,3 @@ +export * from './directive'; +export { default as Loading } from './loading.vue'; +export { default as Spinner } from './spinner.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/loading/loading.vue b/admin-ui/vue/packages/effects/common-ui/src/components/loading/loading.vue new file mode 100644 index 0000000..faf49e6 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/loading/loading.vue @@ -0,0 +1,39 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/loading/spinner.vue b/admin-ui/vue/packages/effects/common-ui/src/components/loading/spinner.vue new file mode 100644 index 0000000..caee2bb --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/loading/spinner.vue @@ -0,0 +1,28 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/page/__tests__/page.test.ts b/admin-ui/vue/packages/effects/common-ui/src/components/page/__tests__/page.test.ts new file mode 100644 index 0000000..a89061f --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/page/__tests__/page.test.ts @@ -0,0 +1,89 @@ +import { mount } from '@vue/test-utils'; + +import { describe, expect, it } from 'vitest'; + +import { Page } from '..'; + +describe('page.vue', () => { + it('renders title when passed', () => { + const wrapper = mount(Page, { + props: { + title: 'Test Title', + }, + }); + + expect(wrapper.text()).toContain('Test Title'); + }); + + it('renders description when passed', () => { + const wrapper = mount(Page, { + props: { + description: 'Test Description', + }, + }); + + expect(wrapper.text()).toContain('Test Description'); + }); + + it('renders default slot content', () => { + const wrapper = mount(Page, { + slots: { + default: '

Default Slot Content

', + }, + }); + + expect(wrapper.html()).toContain('

Default Slot Content

'); + }); + + it('renders footer slot when showFooter is true', () => { + const wrapper = mount(Page, { + props: { + showFooter: true, + }, + slots: { + footer: '

Footer Slot Content

', + }, + }); + + expect(wrapper.html()).toContain('

Footer Slot Content

'); + }); + + it('applies the custom contentClass', () => { + const wrapper = mount(Page, { + props: { + contentClass: 'custom-class', + }, + }); + + const contentDiv = wrapper.find('.p-4'); + expect(contentDiv.classes()).toContain('custom-class'); + }); + + it('does not render title slot if title prop is provided', () => { + const wrapper = mount(Page, { + props: { + title: 'Test Title', + }, + slots: { + title: '

Title Slot Content

', + }, + }); + + expect(wrapper.text()).toContain('Title Slot Content'); + expect(wrapper.html()).not.toContain('Test Title'); + }); + + it('does not render description slot if description prop is provided', () => { + const wrapper = mount(Page, { + props: { + description: 'Test Description', + }, + slots: { + description: '

Description Slot Content

', + }, + }); + + expect(wrapper.text()).toContain('Description Slot Content'); + expect(wrapper.html()).not.toContain('Test Description'); + }); +}); diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/page/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/page/index.ts new file mode 100644 index 0000000..fd9e02f --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/page/index.ts @@ -0,0 +1,2 @@ +export { default as Page } from './page.vue'; +export * from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/page/page.vue b/admin-ui/vue/packages/effects/common-ui/src/components/page/page.vue new file mode 100644 index 0000000..4a0ea54 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/page/page.vue @@ -0,0 +1,100 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/page/types.ts b/admin-ui/vue/packages/effects/common-ui/src/components/page/types.ts new file mode 100644 index 0000000..c7331ae --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/page/types.ts @@ -0,0 +1,17 @@ +export interface PageProps { + title?: string; + description?: string; + contentClass?: string; + /** + * 根据content可见高度自适应 + */ + autoContentHeight?: boolean; + headerClass?: string; + footerClass?: string; + /** + * Custom height offset value (in pixels) to adjust content area sizing + * when used with autoContentHeight + * @default 0 + */ + heightOffset?: number; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/resize/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/resize/index.ts new file mode 100644 index 0000000..f937522 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/resize/index.ts @@ -0,0 +1 @@ +export { default as VResize } from './resize.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/resize/resize.vue b/admin-ui/vue/packages/effects/common-ui/src/components/resize/resize.vue new file mode 100644 index 0000000..68be4d9 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/resize/resize.vue @@ -0,0 +1,1120 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/tippy/directive.ts b/admin-ui/vue/packages/effects/common-ui/src/components/tippy/directive.ts new file mode 100644 index 0000000..ed277d6 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/tippy/directive.ts @@ -0,0 +1,100 @@ +import type { ComputedRef, Directive } from 'vue'; + +import { useTippy } from 'vue-tippy'; + +export default function useTippyDirective(isDark: ComputedRef) { + const directive: Directive = { + mounted(el, binding, vnode) { + const opts = + typeof binding.value === 'string' + ? { content: binding.value } + : binding.value || {}; + + const modifiers = Object.keys(binding.modifiers || {}); + const placement = modifiers.find((modifier) => modifier !== 'arrow'); + const withArrow = modifiers.includes('arrow'); + + if (placement) { + opts.placement = opts.placement || placement; + } + + if (withArrow) { + opts.arrow = opts.arrow === undefined ? true : opts.arrow; + } + + if (vnode.props && vnode.props.onTippyShow) { + opts.onShow = function (...args: any[]) { + return vnode.props?.onTippyShow(...args); + }; + } + + if (vnode.props && vnode.props.onTippyShown) { + opts.onShown = function (...args: any[]) { + return vnode.props?.onTippyShown(...args); + }; + } + + if (vnode.props && vnode.props.onTippyHidden) { + opts.onHidden = function (...args: any[]) { + return vnode.props?.onTippyHidden(...args); + }; + } + + if (vnode.props && vnode.props.onTippyHide) { + opts.onHide = function (...args: any[]) { + return vnode.props?.onTippyHide(...args); + }; + } + + if (vnode.props && vnode.props.onTippyMount) { + opts.onMount = function (...args: any[]) { + return vnode.props?.onTippyMount(...args); + }; + } + + if (el.getAttribute('title') && !opts.content) { + opts.content = el.getAttribute('title'); + el.removeAttribute('title'); + } + + if (el.getAttribute('content') && !opts.content) { + opts.content = el.getAttribute('content'); + } + + useTippy(el, opts); + }, + unmounted(el) { + if (el.$tippy) { + el.$tippy.destroy(); + } else if (el._tippy) { + el._tippy.destroy(); + } + }, + + updated(el, binding) { + const opts = + typeof binding.value === 'string' + ? { content: binding.value, theme: isDark.value ? '' : 'light' } + : Object.assign( + { theme: isDark.value ? '' : 'light' }, + binding.value, + ); + + if (el.getAttribute('title') && !opts.content) { + opts.content = el.getAttribute('title'); + el.removeAttribute('title'); + } + + if (el.getAttribute('content') && !opts.content) { + opts.content = el.getAttribute('content'); + } + + if (el.$tippy) { + el.$tippy.setProps(opts || {}); + } else if (el._tippy) { + el._tippy.setProps(opts || {}); + } + }, + }; + return directive; +} diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/tippy/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/tippy/index.ts new file mode 100644 index 0000000..6080e58 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/tippy/index.ts @@ -0,0 +1,67 @@ +import type { DefaultProps, Props } from 'tippy.js'; + +import type { App, SetupContext } from 'vue'; + +import { h, watchEffect } from 'vue'; +import { setDefaultProps, Tippy as TippyComponent } from 'vue-tippy'; + +import { usePreferences } from '@vben-core/preferences'; + +import useTippyDirective from './directive'; + +import 'tippy.js/dist/tippy.css'; +import 'tippy.js/dist/backdrop.css'; +import 'tippy.js/themes/light.css'; +import 'tippy.js/animations/scale.css'; +import 'tippy.js/animations/shift-toward.css'; +import 'tippy.js/animations/shift-away.css'; +import 'tippy.js/animations/perspective.css'; + +const { isDark } = usePreferences(); +export type TippyProps = Partial< + Props & { + animation?: + | 'fade' + | 'perspective' + | 'scale' + | 'shift-away' + | 'shift-toward' + | boolean; + theme?: 'auto' | 'dark' | 'light'; + } +>; + +export function initTippy(app: App, options?: DefaultProps) { + setDefaultProps({ + allowHTML: true, + delay: [500, 200], + theme: isDark.value ? '' : 'light', + ...options, + }); + if (!options || !Reflect.has(options, 'theme') || options.theme === 'auto') { + watchEffect(() => { + setDefaultProps({ theme: isDark.value ? '' : 'light' }); + }); + } + + app.directive('tippy', useTippyDirective(isDark)); +} + +export const Tippy = (props: any, { attrs, slots }: SetupContext) => { + let theme: string = (attrs.theme as string) ?? 'auto'; + if (theme === 'auto') { + theme = isDark.value ? '' : 'light'; + } + if (theme === 'dark') { + theme = ''; + } + return h( + TippyComponent, + { + ...props, + ...attrs, + theme, + }, + slots, + ); +}; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/tree/index.ts b/admin-ui/vue/packages/effects/common-ui/src/components/tree/index.ts new file mode 100644 index 0000000..ce3bc5c --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/tree/index.ts @@ -0,0 +1 @@ +export { default as Tree } from './tree.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/components/tree/tree.vue b/admin-ui/vue/packages/effects/common-ui/src/components/tree/tree.vue new file mode 100644 index 0000000..1f2fcc1 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/components/tree/tree.vue @@ -0,0 +1,25 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/index.ts b/admin-ui/vue/packages/effects/common-ui/src/index.ts new file mode 100644 index 0000000..27bd718 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/index.ts @@ -0,0 +1,2 @@ +export * from './components'; +export * from './ui'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/about/about.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/about/about.ts new file mode 100644 index 0000000..c4cf957 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/about/about.ts @@ -0,0 +1,14 @@ +import type { Component } from 'vue'; + +interface AboutProps { + description?: string; + name?: string; + title?: string; +} + +interface DescriptionItem { + content: Component | string; + title: string; +} + +export type { AboutProps, DescriptionItem }; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/about/about.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/about/about.vue new file mode 100644 index 0000000..bee8b34 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/about/about.vue @@ -0,0 +1,183 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/about/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/about/index.ts new file mode 100644 index 0000000..5860f5b --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/about/index.ts @@ -0,0 +1 @@ +export { default as About } from './about.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue new file mode 100644 index 0000000..3ed9a6b --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue @@ -0,0 +1,13 @@ + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/code-login.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/code-login.vue new file mode 100644 index 0000000..d7563d8 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/code-login.vue @@ -0,0 +1,127 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue new file mode 100644 index 0000000..80b123c --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue new file mode 100644 index 0000000..9c82df4 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue @@ -0,0 +1,116 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/index.ts new file mode 100644 index 0000000..ac5e1e0 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/index.ts @@ -0,0 +1,7 @@ +export { default as AuthenticationCodeLogin } from './code-login.vue'; +export { default as AuthenticationForgetPassword } from './forget-password.vue'; +export { default as AuthenticationLoginExpiredModal } from './login-expired-modal.vue'; +export { default as AuthenticationLogin } from './login.vue'; +export { default as AuthenticationQrCodeLogin } from './qrcode-login.vue'; +export { default as AuthenticationRegister } from './register.vue'; +export type { AuthenticationProps } from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue new file mode 100644 index 0000000..ef5e6a0 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue @@ -0,0 +1,95 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/login.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/login.vue new file mode 100644 index 0000000..bcb8f21 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/login.vue @@ -0,0 +1,186 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue new file mode 100644 index 0000000..c8f235c --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue @@ -0,0 +1,105 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/register.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/register.vue new file mode 100644 index 0000000..69a69d4 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/register.vue @@ -0,0 +1,121 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue new file mode 100644 index 0000000..8c39ebf --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue @@ -0,0 +1,71 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/types.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/types.ts new file mode 100644 index 0000000..cb297e2 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/authentication/types.ts @@ -0,0 +1,70 @@ +interface AuthenticationProps { + /** + * @zh_CN 验证码登录路径 + */ + codeLoginPath?: string; + /** + * @zh_CN 忘记密码路径 + */ + forgetPasswordPath?: string; + + /** + * @zh_CN 是否处于加载处理状态 + */ + loading?: boolean; + + /** + * @zh_CN 二维码登录路径 + */ + qrCodeLoginPath?: string; + + /** + * @zh_CN 注册路径 + */ + registerPath?: string; + + /** + * @zh_CN 是否显示验证码登录 + */ + showCodeLogin?: boolean; + /** + * @zh_CN 是否显示忘记密码 + */ + showForgetPassword?: boolean; + + /** + * @zh_CN 是否显示二维码登录 + */ + showQrcodeLogin?: boolean; + + /** + * @zh_CN 是否显示注册按钮 + */ + showRegister?: boolean; + + /** + * @zh_CN 是否显示记住账号 + */ + showRememberMe?: boolean; + + /** + * @zh_CN 是否显示第三方登录 + */ + showThirdPartyLogin?: boolean; + + /** + * @zh_CN 登录框子标题 + */ + subTitle?: string; + + /** + * @zh_CN 登录框标题 + */ + title?: string; + /** + * @zh_CN 提交按钮文本 + */ + submitButtonText?: string; +} + +export type { AuthenticationProps }; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue new file mode 100644 index 0000000..294d517 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue @@ -0,0 +1,24 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue new file mode 100644 index 0000000..453ee5c --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue @@ -0,0 +1,40 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue new file mode 100644 index 0000000..18c4929 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue @@ -0,0 +1,55 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts new file mode 100644 index 0000000..7c67b87 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts @@ -0,0 +1,3 @@ +export { default as AnalysisChartCard } from './analysis-chart-card.vue'; +export { default as AnalysisChartsTabs } from './analysis-charts-tabs.vue'; +export { default as AnalysisOverview } from './analysis-overview.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/index.ts new file mode 100644 index 0000000..bc74424 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/index.ts @@ -0,0 +1,3 @@ +export * from './analysis'; +export type * from './typing'; +export * from './workbench'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/typing.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/typing.ts new file mode 100644 index 0000000..48fc9c7 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/typing.ts @@ -0,0 +1,48 @@ +import type { Component } from 'vue'; + +interface AnalysisOverviewItem { + icon: Component | string; + title: string; + totalTitle: string; + totalValue: number; + value: number; +} + +interface WorkbenchProjectItem { + color?: string; + content: string; + date: string; + group: string; + icon: Component | string; + title: string; + url?: string; +} + +interface WorkbenchTrendItem { + avatar: string; + content: string; + date: string; + title: string; +} + +interface WorkbenchTodoItem { + completed: boolean; + content: string; + date: string; + title: string; +} + +interface WorkbenchQuickNavItem { + color?: string; + icon: Component | string; + title: string; + url?: string; +} + +export type { + AnalysisOverviewItem, + WorkbenchProjectItem, + WorkbenchQuickNavItem, + WorkbenchTodoItem, + WorkbenchTrendItem, +}; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts new file mode 100644 index 0000000..76b7af1 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts @@ -0,0 +1,5 @@ +export { default as WorkbenchHeader } from './workbench-header.vue'; +export { default as WorkbenchProject } from './workbench-project.vue'; +export { default as WorkbenchQuickNav } from './workbench-quick-nav.vue'; +export { default as WorkbenchTodo } from './workbench-todo.vue'; +export { default as WorkbenchTrends } from './workbench-trends.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue new file mode 100644 index 0000000..a3ea3eb --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue @@ -0,0 +1,46 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue new file mode 100644 index 0000000..590c334 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue @@ -0,0 +1,65 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue new file mode 100644 index 0000000..86dc5c6 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue @@ -0,0 +1,56 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue new file mode 100644 index 0000000..ef34cd0 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue @@ -0,0 +1,63 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue new file mode 100644 index 0000000..06f2a5e --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue @@ -0,0 +1,64 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/fallback.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/fallback.ts new file mode 100644 index 0000000..5f8e193 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/fallback.ts @@ -0,0 +1,25 @@ +interface FallbackProps { + /** + * 描述 + */ + description?: string; + /** + * @zh_CN 首页路由地址 + * @default / + */ + homePath?: string; + /** + * @zh_CN 默认显示的图片 + * @default pageNotFoundSvg + */ + image?: string; + /** + * @zh_CN 内置类型 + */ + status?: '403' | '404' | '500' | 'coming-soon' | 'offline'; + /** + * @zh_CN 页面提示语 + */ + title?: string; +} +export type { FallbackProps }; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/fallback.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/fallback.vue new file mode 100644 index 0000000..76eafca --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/fallback.vue @@ -0,0 +1,164 @@ + + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue new file mode 100644 index 0000000..e390867 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue @@ -0,0 +1,151 @@ + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue new file mode 100644 index 0000000..385cf6a --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue @@ -0,0 +1,154 @@ + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue new file mode 100644 index 0000000..97326b7 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue @@ -0,0 +1,215 @@ + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue new file mode 100644 index 0000000..e511c43 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue @@ -0,0 +1,262 @@ + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue new file mode 100644 index 0000000..9e50b19 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue @@ -0,0 +1,112 @@ + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg new file mode 100644 index 0000000..951a905 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/index.ts new file mode 100644 index 0000000..f56f665 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/fallback/index.ts @@ -0,0 +1,2 @@ +export type * from './fallback'; +export { default as Fallback } from './fallback.vue'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/index.ts new file mode 100644 index 0000000..8b1db55 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/index.ts @@ -0,0 +1,5 @@ +export * from './about'; +export * from './authentication'; +export * from './dashboard'; +export * from './fallback'; +export * from './profile'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/base-setting.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/base-setting.vue new file mode 100644 index 0000000..1ef1c1a --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/base-setting.vue @@ -0,0 +1,56 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/index.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/index.ts new file mode 100644 index 0000000..209a2e8 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/index.ts @@ -0,0 +1,6 @@ +export { default as ProfileBaseSetting } from './base-setting.vue'; +export { default as ProfileNotificationSetting } from './notification-setting.vue'; +export { default as ProfilePasswordSetting } from './password-setting.vue'; +export { default as Profile } from './profile.vue'; +export { default as ProfileSecuritySetting } from './security-setting.vue'; +export type * from './types'; diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue new file mode 100644 index 0000000..9a3e488 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue @@ -0,0 +1,53 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/password-setting.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/password-setting.vue new file mode 100644 index 0000000..1d90e08 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/password-setting.vue @@ -0,0 +1,56 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/profile.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/profile.vue new file mode 100644 index 0000000..5ab39e6 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/profile.vue @@ -0,0 +1,62 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/security-setting.vue b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/security-setting.vue new file mode 100644 index 0000000..9a3e488 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/security-setting.vue @@ -0,0 +1,53 @@ + + diff --git a/admin-ui/vue/packages/effects/common-ui/src/ui/profile/types.ts b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/types.ts new file mode 100644 index 0000000..e600bde --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/src/ui/profile/types.ts @@ -0,0 +1,21 @@ +import type { BasicUserInfo } from '@vben/types'; + +export interface Props { + title?: string; + userInfo: BasicUserInfo | null; + tabs: { + label: string; + value: string; + }[]; +} + +export interface FormSchemaItem { + description: string; + fieldName: string; + label: string; + value: boolean; +} + +export interface SettingProps { + formSchema: FormSchemaItem[]; +} diff --git a/admin-ui/vue/packages/effects/common-ui/tsconfig.json b/admin-ui/vue/packages/effects/common-ui/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/effects/common-ui/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/effects/hooks/README.md b/admin-ui/vue/packages/effects/hooks/README.md new file mode 100644 index 0000000..54d9ff7 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/README.md @@ -0,0 +1,19 @@ +# @vben/hooks + +用于多个 `app` 公用的 hook,继承了 `@vben/hooks` 的所有能力。业务上有通用 hooks 可以放在这里。 + +## 用法 + +### 添加依赖 + +```bash +# 进入目标应用目录,例如 apps/xxxx-app +# cd apps/xxxx-app +pnpm add @vben/hooks +``` + +### 使用 + +```ts +import { useNamespace } from '@vben/hooks'; +``` diff --git a/admin-ui/vue/packages/effects/hooks/package.json b/admin-ui/vue/packages/effects/hooks/package.json new file mode 100644 index 0000000..76d83a5 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/package.json @@ -0,0 +1,33 @@ +{ + "name": "@vben/hooks", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/effects/hooks" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/composables": "workspace:*", + "@vben/preferences": "workspace:*", + "@vben/stores": "workspace:*", + "@vben/types": "workspace:*", + "@vben/utils": "workspace:*", + "@vueuse/core": "catalog:", + "vue": "catalog:", + "vue-router": "catalog:", + "watermark-js-plus": "catalog:" + } +} diff --git a/admin-ui/vue/packages/effects/hooks/src/index.ts b/admin-ui/vue/packages/effects/hooks/src/index.ts new file mode 100644 index 0000000..c189fd7 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/index.ts @@ -0,0 +1,9 @@ +export * from './use-app-config'; +export * from './use-content-maximize'; +export * from './use-design-tokens'; +export * from './use-hover-toggle'; +export * from './use-pagination'; +export * from './use-refresh'; +export * from './use-tabs'; +export * from './use-watermark'; +export * from '@vben-core/composables'; diff --git a/admin-ui/vue/packages/effects/hooks/src/use-app-config.ts b/admin-ui/vue/packages/effects/hooks/src/use-app-config.ts new file mode 100644 index 0000000..41f383c --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-app-config.ts @@ -0,0 +1,36 @@ +import type { + ApplicationConfig, + VbenAdminProAppConfigRaw, +} from '@vben/types/global'; + +/** + * 由 vite-inject-app-config 注入的全局配置 + */ +export function useAppConfig( + env: Record, + isProduction: boolean, +): ApplicationConfig { + // 生产环境下,直接使用 window._VBEN_ADMIN_PRO_APP_CONF_ 全局变量 + const config = isProduction + ? window._VBEN_ADMIN_PRO_APP_CONF_ + : (env as VbenAdminProAppConfigRaw); + + const { + VITE_GLOB_API_URL, + VITE_GLOB_AUTH_DINGDING_CORP_ID, + VITE_GLOB_AUTH_DINGDING_CLIENT_ID, + } = config; + + const applicationConfig: ApplicationConfig = { + apiURL: VITE_GLOB_API_URL, + auth: {}, + }; + if (VITE_GLOB_AUTH_DINGDING_CORP_ID && VITE_GLOB_AUTH_DINGDING_CLIENT_ID) { + applicationConfig.auth.dingding = { + clientId: VITE_GLOB_AUTH_DINGDING_CLIENT_ID, + corpId: VITE_GLOB_AUTH_DINGDING_CORP_ID, + }; + } + + return applicationConfig; +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-content-maximize.ts b/admin-ui/vue/packages/effects/hooks/src/use-content-maximize.ts new file mode 100644 index 0000000..77d1fab --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-content-maximize.ts @@ -0,0 +1,24 @@ +import { updatePreferences, usePreferences } from '@vben/preferences'; +/** + * 主体区域最大化 + */ +export function useContentMaximize() { + const { contentIsMaximize } = usePreferences(); + + function toggleMaximize() { + const isMaximize = contentIsMaximize.value; + + updatePreferences({ + header: { + hidden: !isMaximize, + }, + sidebar: { + hidden: !isMaximize, + }, + }); + } + return { + contentIsMaximize, + toggleMaximize, + }; +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-design-tokens.ts b/admin-ui/vue/packages/effects/hooks/src/use-design-tokens.ts new file mode 100644 index 0000000..6a076f3 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-design-tokens.ts @@ -0,0 +1,321 @@ +import { reactive, watch } from 'vue'; + +import { preferences, usePreferences } from '@vben/preferences'; +import { convertToRgb, updateCSSVariables } from '@vben/utils'; + +/** + * 用于适配各个框架的设计系统 + */ + +export function useAntdDesignTokens() { + const rootStyles = getComputedStyle(document.documentElement); + + const tokens = reactive({ + borderRadius: '' as any, + colorBgBase: '', + colorBgContainer: '', + colorBgElevated: '', + colorBgLayout: '', + colorBgMask: '', + colorBorder: '', + colorBorderSecondary: '', + colorError: '', + colorInfo: '', + colorPrimary: '', + colorSuccess: '', + colorTextBase: '', + colorWarning: '', + zIndexPopupBase: 2000, // 调整基础弹层层级,避免下拉等组件被弹窗或者最大化状态下的表格遮挡 + }); + + const getCssVariableValue = (variable: string, isColor: boolean = true) => { + const value = rootStyles.getPropertyValue(variable); + return isColor ? `hsl(${value})` : value; + }; + + watch( + () => preferences.theme, + () => { + tokens.colorPrimary = getCssVariableValue('--primary'); + + tokens.colorInfo = getCssVariableValue('--primary'); + + tokens.colorError = getCssVariableValue('--destructive'); + + tokens.colorWarning = getCssVariableValue('--warning'); + + tokens.colorSuccess = getCssVariableValue('--success'); + + tokens.colorTextBase = getCssVariableValue('--foreground'); + + getCssVariableValue('--primary-foreground'); + + tokens.colorBorderSecondary = tokens.colorBorder = + getCssVariableValue('--border'); + + tokens.colorBgElevated = getCssVariableValue('--popover'); + + tokens.colorBgContainer = getCssVariableValue('--card'); + + tokens.colorBgBase = getCssVariableValue('--background'); + + const radius = Number.parseFloat(getCssVariableValue('--radius', false)); + // 1rem = 16px + tokens.borderRadius = radius * 16; + + tokens.colorBgLayout = getCssVariableValue('--background-deep'); + tokens.colorBgMask = getCssVariableValue('--overlay'); + }, + { immediate: true }, + ); + + return { + tokens, + }; +} + +export function useNaiveDesignTokens() { + const rootStyles = getComputedStyle(document.documentElement); + + const commonTokens = reactive({ + baseColor: '', + bodyColor: '', + borderColor: '', + borderRadius: '', + cardColor: '', + dividerColor: '', + errorColor: '', + errorColorHover: '', + errorColorPressed: '', + errorColorSuppl: '', + invertedColor: '', + modalColor: '', + popoverColor: '', + primaryColor: '', + primaryColorHover: '', + primaryColorPressed: '', + primaryColorSuppl: '', + successColor: '', + successColorHover: '', + successColorPressed: '', + successColorSuppl: '', + tableColor: '', + textColorBase: '', + warningColor: '', + warningColorHover: '', + warningColorPressed: '', + warningColorSuppl: '', + }); + + const getCssVariableValue = (variable: string, isColor: boolean = true) => { + const value = rootStyles.getPropertyValue(variable); + return isColor ? convertToRgb(`hsl(${value})`) : value; + }; + + watch( + () => preferences.theme, + () => { + commonTokens.primaryColor = getCssVariableValue('--primary'); + commonTokens.primaryColorHover = getCssVariableValue('--primary-600'); + commonTokens.primaryColorPressed = getCssVariableValue('--primary-700'); + commonTokens.primaryColorSuppl = getCssVariableValue('--primary-800'); + + commonTokens.errorColor = getCssVariableValue('--destructive'); + commonTokens.errorColorHover = getCssVariableValue('--destructive-600'); + commonTokens.errorColorPressed = getCssVariableValue('--destructive-700'); + commonTokens.errorColorSuppl = getCssVariableValue('--destructive-800'); + + commonTokens.warningColor = getCssVariableValue('--warning'); + commonTokens.warningColorHover = getCssVariableValue('--warning-600'); + commonTokens.warningColorPressed = getCssVariableValue('--warning-700'); + commonTokens.warningColorSuppl = getCssVariableValue('--warning-800'); + + commonTokens.successColor = getCssVariableValue('--success'); + commonTokens.successColorHover = getCssVariableValue('--success-600'); + commonTokens.successColorPressed = getCssVariableValue('--success-700'); + commonTokens.successColorSuppl = getCssVariableValue('--success-800'); + + commonTokens.textColorBase = getCssVariableValue('--foreground'); + + commonTokens.baseColor = getCssVariableValue('--primary-foreground'); + + commonTokens.dividerColor = commonTokens.borderColor = + getCssVariableValue('--border'); + + commonTokens.modalColor = commonTokens.popoverColor = + getCssVariableValue('--popover'); + + commonTokens.tableColor = commonTokens.cardColor = + getCssVariableValue('--card'); + + commonTokens.bodyColor = getCssVariableValue('--background'); + commonTokens.invertedColor = getCssVariableValue('--background-deep'); + + commonTokens.borderRadius = getCssVariableValue('--radius', false); + }, + { immediate: true }, + ); + return { + commonTokens, + }; +} + +export function useElementPlusDesignTokens() { + const { isDark } = usePreferences(); + const rootStyles = getComputedStyle(document.documentElement); + + const getCssVariableValueRaw = (variable: string) => { + return rootStyles.getPropertyValue(variable); + }; + + const getCssVariableValue = (variable: string, isColor: boolean = true) => { + const value = getCssVariableValueRaw(variable); + return isColor ? convertToRgb(`hsl(${value})`) : value; + }; + + watch( + () => preferences.theme, + () => { + const background = getCssVariableValue('--background'); + const border = getCssVariableValue('--border'); + const accent = getCssVariableValue('--accent'); + + const variables: Record = { + '--el-bg-color': background, + '--el-bg-color-overlay': getCssVariableValue('--popover'), + '--el-bg-color-page': getCssVariableValue('--background-deep'), + '--el-border-color': border, + '--el-border-color-dark': border, + '--el-border-color-extra-light': border, + '--el-border-color-hover': accent, + '--el-border-color-light': border, + '--el-border-color-lighter': border, + + '--el-border-radius-base': getCssVariableValue('--radius', false), + '--el-color-danger': getCssVariableValue('--destructive-500'), + '--el-color-danger-dark-2': isDark.value + ? getCssVariableValue('--destructive-400') + : getCssVariableValue('--destructive-600'), + '--el-color-danger-light-3': isDark.value + ? getCssVariableValue('--destructive-600') + : getCssVariableValue('--destructive-400'), + '--el-color-danger-light-5': isDark.value + ? getCssVariableValue('--destructive-700') + : getCssVariableValue('--destructive-300'), + '--el-color-danger-light-7': isDark.value + ? getCssVariableValue('--destructive-800') + : getCssVariableValue('--destructive-200'), + '--el-color-danger-light-8': isDark.value + ? getCssVariableValue('--destructive-900') + : getCssVariableValue('--destructive-100'), + '--el-color-danger-light-9': isDark.value + ? getCssVariableValue('--destructive-950') + : getCssVariableValue('--destructive-50'), + + '--el-color-error': getCssVariableValue('--destructive-500'), + '--el-color-error-dark-2': isDark.value + ? getCssVariableValue('--destructive-400') + : getCssVariableValue('--destructive-600'), + '--el-color-error-light-3': isDark.value + ? getCssVariableValue('--destructive-600') + : getCssVariableValue('--destructive-400'), + '--el-color-error-light-5': isDark.value + ? getCssVariableValue('--destructive-700') + : getCssVariableValue('--destructive-300'), + '--el-color-error-light-7': isDark.value + ? getCssVariableValue('--destructive-800') + : getCssVariableValue('--destructive-200'), + '--el-color-error-light-8': isDark.value + ? getCssVariableValue('--destructive-900') + : getCssVariableValue('--destructive-100'), + '--el-color-error-light-9': isDark.value + ? getCssVariableValue('--destructive-950') + : getCssVariableValue('--destructive-50'), + + '--el-color-info-light-5': border, + '--el-color-info-light-8': border, + '--el-color-info-light-9': getCssVariableValue('--info'), // getCssVariableValue('--secondary'), + + '--el-color-primary': getCssVariableValue('--primary-500'), + '--el-color-primary-dark-2': isDark.value + ? getCssVariableValue('--primary-400') + : getCssVariableValue('--primary-600'), + '--el-color-primary-light-3': isDark.value + ? getCssVariableValue('--primary-600') + : getCssVariableValue('--primary-400'), + '--el-color-primary-light-5': isDark.value + ? getCssVariableValue('--primary-700') + : getCssVariableValue('--primary-300'), + '--el-color-primary-light-7': isDark.value + ? getCssVariableValue('--primary-800') + : getCssVariableValue('--primary-200'), + '--el-color-primary-light-8': isDark.value + ? getCssVariableValue('--primary-900') + : getCssVariableValue('--primary-100'), + '--el-color-primary-light-9': isDark.value + ? getCssVariableValue('--primary-950') + : getCssVariableValue('--primary-50'), + + '--el-color-success': getCssVariableValue('--success-500'), + '--el-color-success-dark-2': isDark.value + ? getCssVariableValue('--success-400') + : getCssVariableValue('--success-600'), + '--el-color-success-light-3': isDark.value + ? getCssVariableValue('--success-600') + : getCssVariableValue('--success-400'), + '--el-color-success-light-5': isDark.value + ? getCssVariableValue('--success-700') + : getCssVariableValue('--success-300'), + '--el-color-success-light-7': isDark.value + ? getCssVariableValue('--success-800') + : getCssVariableValue('--success-200'), + '--el-color-success-light-8': isDark.value + ? getCssVariableValue('--success-900') + : getCssVariableValue('--success-100'), + '--el-color-success-light-9': isDark.value + ? getCssVariableValue('--success-950') + : getCssVariableValue('--success-50'), + + '--el-color-warning': getCssVariableValue('--warning-500'), + '--el-color-warning-dark-2': isDark.value + ? getCssVariableValue('--warning-400') + : getCssVariableValue('--warning-600'), + '--el-color-warning-light-3': isDark.value + ? getCssVariableValue('--warning-600') + : getCssVariableValue('--warning-400'), + '--el-color-warning-light-5': isDark.value + ? getCssVariableValue('--warning-700') + : getCssVariableValue('--warning-300'), + '--el-color-warning-light-7': isDark.value + ? getCssVariableValue('--warning-800') + : getCssVariableValue('--warning-200'), + '--el-color-warning-light-8': isDark.value + ? getCssVariableValue('--warning-900') + : getCssVariableValue('--warning-100'), + '--el-color-warning-light-9': isDark.value + ? getCssVariableValue('--warning-950') + : getCssVariableValue('--warning-50'), + + '--el-fill-color': getCssVariableValue('--accent'), + '--el-fill-color-blank': background, + '--el-fill-color-light': getCssVariableValue('--accent'), + '--el-fill-color-lighter': getCssVariableValue('--accent-lighter'), + + '--el-fill-color-dark': getCssVariableValue('--accent-dark'), + '--el-fill-color-darker': getCssVariableValue('--accent-darker'), + + // 解决ElLoading背景色问题 + '--el-mask-color': isDark.value + ? 'rgba(0,0,0,.8)' + : 'rgba(255,255,255,.9)', + + '--el-text-color-primary': getCssVariableValue('--foreground'), + + '--el-text-color-regular': getCssVariableValue('--foreground'), + }; + + updateCSSVariables(variables, `__vben_design_styles__`); + }, + { immediate: true }, + ); +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-hover-toggle.ts b/admin-ui/vue/packages/effects/hooks/src/use-hover-toggle.ts new file mode 100644 index 0000000..0bed41d --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-hover-toggle.ts @@ -0,0 +1,163 @@ +import type { Arrayable, MaybeElementRef } from '@vueuse/core'; + +import type { Ref } from 'vue'; + +import { computed, effectScope, onUnmounted, ref, unref, watch } from 'vue'; + +import { isFunction } from '@vben/utils'; + +import { useElementHover } from '@vueuse/core'; + +interface HoverDelayOptions { + /** 鼠标进入延迟时间 */ + enterDelay?: (() => number) | number; + /** 鼠标离开延迟时间 */ + leaveDelay?: (() => number) | number; +} + +const DEFAULT_LEAVE_DELAY = 500; // 鼠标离开延迟时间,默认为 500ms +const DEFAULT_ENTER_DELAY = 0; // 鼠标进入延迟时间,默认为 0(立即响应) + +/** + * 监测鼠标是否在元素内部,如果在元素内部则返回 true,否则返回 false + * @param refElement 所有需要检测的元素。支持单个元素、元素数组或响应式引用的元素数组。如果鼠标在任何一个元素内部都会返回 true + * @param delay 延迟更新状态的时间,可以是数字或包含进入/离开延迟的配置对象 + * @returns 返回一个数组,第一个元素是一个 ref,表示鼠标是否在元素内部,第二个元素是一个控制器,可以通过 enable 和 disable 方法来控制监听器的启用和禁用 + */ +export function useHoverToggle( + refElement: Arrayable | Ref, + delay: (() => number) | HoverDelayOptions | number = DEFAULT_LEAVE_DELAY, +) { + // 兼容旧版本API + const normalizedOptions: HoverDelayOptions = + typeof delay === 'number' || isFunction(delay) + ? { enterDelay: DEFAULT_ENTER_DELAY, leaveDelay: delay } + : { + enterDelay: DEFAULT_ENTER_DELAY, + leaveDelay: DEFAULT_LEAVE_DELAY, + ...delay, + }; + + const value = ref(false); + const enterTimer = ref | undefined>(); + const leaveTimer = ref | undefined>(); + const hoverScopes = ref[]>([]); + + // 使用计算属性包装 refElement,使其响应式变化 + const refs = computed(() => { + const raw = unref(refElement); + if (raw === null) return []; + return Array.isArray(raw) ? raw : [raw]; + }); + // 存储所有 hover 状态 + const isHovers = ref>>([]); + + // 更新 hover 监听的函数 + function updateHovers() { + // 停止并清理之前的作用域 + hoverScopes.value.forEach((scope) => scope.stop()); + hoverScopes.value = []; + + isHovers.value = refs.value.map((refEle) => { + if (!refEle) { + return ref(false); + } + const eleRef = computed(() => { + const ele = unref(refEle); + return ele instanceof Element ? ele : (ele?.$el as Element); + }); + + // 为每个元素创建独立的作用域 + const scope = effectScope(); + const hoverRef = scope.run(() => useElementHover(eleRef)) || ref(false); + hoverScopes.value.push(scope); + + return hoverRef; + }); + } + + // 监听元素数量变化,避免过度执行 + const elementsCount = computed(() => { + const raw = unref(refElement); + if (raw === null) return 0; + return Array.isArray(raw) ? raw.length : 1; + }); + + // 初始设置 + updateHovers(); + + // 只在元素数量变化时重新设置监听器 + const stopWatcher = watch(elementsCount, updateHovers, { deep: false }); + + const isOutsideAll = computed(() => isHovers.value.every((v) => !v.value)); + + function clearTimers() { + if (enterTimer.value) { + clearTimeout(enterTimer.value); + enterTimer.value = undefined; + } + if (leaveTimer.value) { + clearTimeout(leaveTimer.value); + leaveTimer.value = undefined; + } + } + + function setValueDelay(val: boolean) { + clearTimers(); + + if (val) { + // 鼠标进入 + const enterDelay = normalizedOptions.enterDelay ?? DEFAULT_ENTER_DELAY; + const delayTime = isFunction(enterDelay) ? enterDelay() : enterDelay; + + if (delayTime <= 0) { + value.value = true; + } else { + enterTimer.value = setTimeout(() => { + value.value = true; + enterTimer.value = undefined; + }, delayTime); + } + } else { + // 鼠标离开 + const leaveDelay = normalizedOptions.leaveDelay ?? DEFAULT_LEAVE_DELAY; + const delayTime = isFunction(leaveDelay) ? leaveDelay() : leaveDelay; + + if (delayTime <= 0) { + value.value = false; + } else { + leaveTimer.value = setTimeout(() => { + value.value = false; + leaveTimer.value = undefined; + }, delayTime); + } + } + } + + const hoverWatcher = watch( + isOutsideAll, + (val) => { + setValueDelay(!val); + }, + { immediate: true }, + ); + + const controller = { + enable() { + hoverWatcher.resume(); + }, + disable() { + hoverWatcher.pause(); + }, + }; + + onUnmounted(() => { + clearTimers(); + // 停止监听器 + stopWatcher(); + // 停止所有剩余的作用域 + hoverScopes.value.forEach((scope) => scope.stop()); + }); + + return [value, controller] as [typeof value, typeof controller]; +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-pagination.ts b/admin-ui/vue/packages/effects/hooks/src/use-pagination.ts new file mode 100644 index 0000000..0115606 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-pagination.ts @@ -0,0 +1,72 @@ +import type { Ref } from 'vue'; + +import { computed, ref, unref, watch } from 'vue'; + +/** + * Paginates an array of items + * @param list The array to paginate + * @param pageNo The current page number (1-based) + * @param pageSize Number of items per page + * @returns Paginated array slice + * @throws {Error} If pageNo or pageSize are invalid + */ +function pagination(list: T[], pageNo: number, pageSize: number): T[] { + if (pageNo < 1) throw new Error('Page number must be positive'); + if (pageSize < 1) throw new Error('Page size must be positive'); + + const offset = (pageNo - 1) * Number(pageSize); + const ret = + offset + pageSize >= list.length + ? list.slice(offset) + : list.slice(offset, offset + pageSize); + return ret; +} + +export function usePagination( + list: Ref, + pageSize: number, + totalChangeToFirstPage = true, +) { + const currentPage = ref(1); + const pageSizeRef = ref(pageSize); + + const totalPages = computed(() => + Math.ceil(unref(list).length / unref(pageSizeRef)), + ); + + const paginationList = computed(() => { + return pagination(unref(list), unref(currentPage), unref(pageSizeRef)); + }); + + const total = computed(() => { + return unref(list).length; + }); + + if (totalChangeToFirstPage) { + watch(total, () => { + setCurrentPage(1); + }); + } + + function setCurrentPage(page: number) { + if (page === 1 && unref(totalPages) === 0) { + currentPage.value = 1; + } else { + if (page < 1 || page > unref(totalPages)) { + throw new Error('Invalid page number'); + } + currentPage.value = page; + } + } + + function setPageSize(pageSize: number) { + if (pageSize < 1) { + throw new Error('Page size must be positive'); + } + pageSizeRef.value = pageSize; + // Reset to first page to prevent invalid state + currentPage.value = 1; + } + + return { setCurrentPage, total, setPageSize, paginationList, currentPage }; +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-refresh.ts b/admin-ui/vue/packages/effects/hooks/src/use-refresh.ts new file mode 100644 index 0000000..b3a5cae --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-refresh.ts @@ -0,0 +1,16 @@ +import { useRouter } from 'vue-router'; + +import { useTabbarStore } from '@vben/stores'; + +export function useRefresh() { + const router = useRouter(); + const tabbarStore = useTabbarStore(); + + async function refresh() { + await tabbarStore.refresh(router); + } + + return { + refresh, + }; +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-tabs.ts b/admin-ui/vue/packages/effects/hooks/src/use-tabs.ts new file mode 100644 index 0000000..5267211 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-tabs.ts @@ -0,0 +1,133 @@ +import type { ComputedRef } from 'vue'; +import type { RouteLocationNormalized } from 'vue-router'; + +import { useRoute, useRouter } from 'vue-router'; + +import { useTabbarStore } from '@vben/stores'; + +export function useTabs() { + const router = useRouter(); + const route = useRoute(); + const tabbarStore = useTabbarStore(); + + async function closeLeftTabs(tab?: RouteLocationNormalized) { + await tabbarStore.closeLeftTabs(tab || route); + } + + async function closeAllTabs() { + await tabbarStore.closeAllTabs(router); + } + + async function closeRightTabs(tab?: RouteLocationNormalized) { + await tabbarStore.closeRightTabs(tab || route); + } + + async function closeOtherTabs(tab?: RouteLocationNormalized) { + await tabbarStore.closeOtherTabs(tab || route); + } + + async function closeCurrentTab(tab?: RouteLocationNormalized) { + await tabbarStore.closeTab(tab || route, router); + } + + async function pinTab(tab?: RouteLocationNormalized) { + await tabbarStore.pinTab(tab || route); + } + + async function unpinTab(tab?: RouteLocationNormalized) { + await tabbarStore.unpinTab(tab || route); + } + + async function toggleTabPin(tab?: RouteLocationNormalized) { + await tabbarStore.toggleTabPin(tab || route); + } + + async function refreshTab(name?: string) { + await tabbarStore.refresh(name || router); + } + + async function openTabInNewWindow(tab?: RouteLocationNormalized) { + await tabbarStore.openTabInNewWindow(tab || route); + } + + async function closeTabByKey(key: string) { + await tabbarStore.closeTabByKey(key, router); + } + + /** + * 设置当前标签页的标题 + * + * @description 支持设置静态标题字符串或动态计算标题 + * @description 动态标题会在每次渲染时重新计算,适用于多语言或状态相关的标题 + * + * @param title - 标题内容 + * - 静态标题: 直接传入字符串 + * - 动态标题: 传入 ComputedRef + * + * @example + * // 静态标题 + * setTabTitle('标签页') + * + * // 动态标题(多语言) + * setTabTitle(computed(() => t('page.title'))) + */ + async function setTabTitle(title: ComputedRef | string) { + tabbarStore.setUpdateTime(); + await tabbarStore.setTabTitle(route, title); + } + + async function resetTabTitle() { + tabbarStore.setUpdateTime(); + await tabbarStore.resetTabTitle(route); + } + + /** + * 获取操作是否禁用 + * @param tab + */ + function getTabDisableState(tab: RouteLocationNormalized = route) { + const tabs = tabbarStore.getTabs; + const affixTabs = tabbarStore.affixTabs; + const index = tabs.findIndex((item) => item.path === tab.path); + + const disabled = tabs.length <= 1; + + const { meta } = tab; + const affixTab = meta?.affixTab ?? false; + const isCurrentTab = route.path === tab.path; + + // 当前处于最左侧或者减去固定标签页的数量等于0 + const disabledCloseLeft = + index === 0 || index - affixTabs.length <= 0 || !isCurrentTab; + + const disabledCloseRight = !isCurrentTab || index === tabs.length - 1; + + const disabledCloseOther = + disabled || !isCurrentTab || tabs.length - affixTabs.length <= 1; + return { + disabledCloseAll: disabled, + disabledCloseCurrent: !!affixTab || disabled, + disabledCloseLeft, + disabledCloseOther, + disabledCloseRight, + disabledRefresh: !isCurrentTab, + }; + } + + return { + closeAllTabs, + closeCurrentTab, + closeLeftTabs, + closeOtherTabs, + closeRightTabs, + closeTabByKey, + getTabDisableState, + openTabInNewWindow, + pinTab, + refreshTab, + resetTabTitle, + setTabTitle, + toggleTabPin, + unpinTab, + }; +} diff --git a/admin-ui/vue/packages/effects/hooks/src/use-watermark.ts b/admin-ui/vue/packages/effects/hooks/src/use-watermark.ts new file mode 100644 index 0000000..8484a08 --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/src/use-watermark.ts @@ -0,0 +1,84 @@ +import type { Watermark, WatermarkOptions } from 'watermark-js-plus'; + +import { nextTick, onUnmounted, readonly, ref } from 'vue'; + +const watermark = ref(); +const unmountedHooked = ref(false); +const cachedOptions = ref>({ + advancedStyle: { + colorStops: [ + { + color: 'gray', + offset: 0, + }, + { + color: 'gray', + offset: 1, + }, + ], + type: 'linear', + }, + // fontSize: '20px', + content: '', + contentType: 'multi-line-text', + globalAlpha: 0.25, + gridLayoutOptions: { + cols: 2, + gap: [20, 20], + matrix: [ + [1, 0], + [0, 1], + ], + rows: 2, + }, + height: 200, + layout: 'grid', + rotate: 30, + width: 160, +}); + +export function useWatermark() { + async function initWatermark(options: Partial) { + const { Watermark } = await import('watermark-js-plus'); + + cachedOptions.value = { + ...cachedOptions.value, + ...options, + }; + watermark.value = new Watermark(cachedOptions.value); + await watermark.value?.create(); + } + + async function updateWatermark(options: Partial) { + if (watermark.value) { + await nextTick(); + await watermark.value?.changeOptions({ + ...cachedOptions.value, + ...options, + }); + } else { + await initWatermark(options); + } + } + + function destroyWatermark() { + if (watermark.value) { + watermark.value.destroy(); + watermark.value = undefined; + } + } + + // 只在第一次调用时注册卸载钩子,防止重复注册以致于在路由切换时销毁了水印 + if (!unmountedHooked.value) { + unmountedHooked.value = true; + onUnmounted(() => { + destroyWatermark(); + }); + } + + return { + destroyWatermark, + updateWatermark, + watermark: readonly(watermark), + }; +} diff --git a/admin-ui/vue/packages/effects/hooks/tsconfig.json b/admin-ui/vue/packages/effects/hooks/tsconfig.json new file mode 100644 index 0000000..b13aa7a --- /dev/null +++ b/admin-ui/vue/packages/effects/hooks/tsconfig.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "compilerOptions": { + "types": ["vite/client", "@vben/types/global"] + }, + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/effects/layouts/package.json b/admin-ui/vue/packages/effects/layouts/package.json new file mode 100644 index 0000000..3c195d3 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/package.json @@ -0,0 +1,43 @@ +{ + "name": "@vben/layouts", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/effects/layouts" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/composables": "workspace:*", + "@vben-core/form-ui": "workspace:*", + "@vben-core/layout-ui": "workspace:*", + "@vben-core/menu-ui": "workspace:*", + "@vben-core/popup-ui": "workspace:*", + "@vben-core/shadcn-ui": "workspace:*", + "@vben-core/shared": "workspace:*", + "@vben-core/tabs-ui": "workspace:*", + "@vben/constants": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/locales": "workspace:*", + "@vben/preferences": "workspace:*", + "@vben/stores": "workspace:*", + "@vben/types": "workspace:*", + "@vben/utils": "workspace:*", + "@vueuse/core": "catalog:", + "vue": "catalog:", + "vue-router": "catalog:" + } +} diff --git a/admin-ui/vue/packages/effects/layouts/src/authentication/authentication.vue b/admin-ui/vue/packages/effects/layouts/src/authentication/authentication.vue new file mode 100644 index 0000000..6d3bf8c --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/authentication/authentication.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/authentication/form.vue b/admin-ui/vue/packages/effects/layouts/src/authentication/form.vue new file mode 100644 index 0000000..fa73e12 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/authentication/form.vue @@ -0,0 +1,38 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/authentication/icons/slogan.vue b/admin-ui/vue/packages/effects/layouts/src/authentication/icons/slogan.vue new file mode 100644 index 0000000..82cc119 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/authentication/icons/slogan.vue @@ -0,0 +1,4568 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/authentication/index.ts b/admin-ui/vue/packages/effects/layouts/src/authentication/index.ts new file mode 100644 index 0000000..d7c1c29 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/authentication/index.ts @@ -0,0 +1,2 @@ +export { default as AuthPageLayout } from './authentication.vue'; +export * from './types'; diff --git a/admin-ui/vue/packages/effects/layouts/src/authentication/toolbar.vue b/admin-ui/vue/packages/effects/layouts/src/authentication/toolbar.vue new file mode 100644 index 0000000..94d321a --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/authentication/toolbar.vue @@ -0,0 +1,49 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/authentication/types.ts b/admin-ui/vue/packages/effects/layouts/src/authentication/types.ts new file mode 100644 index 0000000..c4c1c7f --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/authentication/types.ts @@ -0,0 +1 @@ +export type ToolbarType = 'color' | 'language' | 'layout' | 'theme'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/README.md b/admin-ui/vue/packages/effects/layouts/src/basic/README.md new file mode 100644 index 0000000..b1266ea --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/README.md @@ -0,0 +1,7 @@ +## layout + +### header + +- 支持N个自定义插槽,命名方式:header-right-n,header-left-n +- header-left-n ,排序方式:0-19 ,breadcrumb 21-x +- header-right-n ,排序方式:0-49,global-search,51-59,theme-toggle,61-69,language-toggle,71-79,fullscreen,81-89,notification,91-149,user-dropdown,151-x diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/content/content-spinner.vue b/admin-ui/vue/packages/effects/layouts/src/basic/content/content-spinner.vue new file mode 100644 index 0000000..e97e4b6 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/content/content-spinner.vue @@ -0,0 +1,12 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/content/content.vue b/admin-ui/vue/packages/effects/layouts/src/basic/content/content.vue new file mode 100644 index 0000000..8b8a639 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/content/content.vue @@ -0,0 +1,148 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/content/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/content/index.ts new file mode 100644 index 0000000..8372b20 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/content/index.ts @@ -0,0 +1,2 @@ +export { default as LayoutContentSpinner } from './content-spinner.vue'; +export { default as LayoutContent } from './content.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/content/use-content-spinner.ts b/admin-ui/vue/packages/effects/layouts/src/basic/content/use-content-spinner.ts new file mode 100644 index 0000000..dfe3c53 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/content/use-content-spinner.ts @@ -0,0 +1,50 @@ +import { computed, ref } from 'vue'; +import { useRouter } from 'vue-router'; + +import { preferences } from '@vben/preferences'; + +function useContentSpinner() { + const spinning = ref(false); + const startTime = ref(0); + const router = useRouter(); + const minShowTime = 500; // 最小显示时间 + const enableLoading = computed(() => preferences.transition.loading); + + // 结束加载动画 + const onEnd = () => { + if (!enableLoading.value) { + return; + } + const processTime = performance.now() - startTime.value; + if (processTime < minShowTime) { + setTimeout(() => { + spinning.value = false; + }, minShowTime - processTime); + } else { + spinning.value = false; + } + }; + + // 路由前置守卫 + router.beforeEach((to) => { + if (to.meta.loaded || !enableLoading.value || to.meta.iframeSrc) { + return true; + } + startTime.value = performance.now(); + spinning.value = true; + return true; + }); + + // 路由后置守卫 + router.afterEach((to) => { + if (to.meta.loaded || !enableLoading.value || to.meta.iframeSrc) { + return true; + } + onEnd(); + return true; + }); + + return { spinning }; +} + +export { useContentSpinner }; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/copyright/copyright.vue b/admin-ui/vue/packages/effects/layouts/src/basic/copyright/copyright.vue new file mode 100644 index 0000000..de49c7c --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/copyright/copyright.vue @@ -0,0 +1,48 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/copyright/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/copyright/index.ts new file mode 100644 index 0000000..e0620da --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/copyright/index.ts @@ -0,0 +1 @@ +export { default as Copyright } from './copyright.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/footer/footer.vue b/admin-ui/vue/packages/effects/layouts/src/basic/footer/footer.vue new file mode 100644 index 0000000..6fc256d --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/footer/footer.vue @@ -0,0 +1,11 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/footer/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/footer/index.ts new file mode 100644 index 0000000..7e149a2 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/footer/index.ts @@ -0,0 +1 @@ +export { default as LayoutFooter } from './footer.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/header/header.vue b/admin-ui/vue/packages/effects/layouts/src/basic/header/header.vue new file mode 100644 index 0000000..44ec671 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/header/header.vue @@ -0,0 +1,195 @@ + + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/header/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/header/index.ts new file mode 100644 index 0000000..44f0729 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/header/index.ts @@ -0,0 +1 @@ +export { default as LayoutHeader } from './header.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/index.ts new file mode 100644 index 0000000..b3a01cd --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/index.ts @@ -0,0 +1 @@ +export { default as BasicLayout } from './layout.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/layout.vue b/admin-ui/vue/packages/effects/layouts/src/basic/layout.vue new file mode 100644 index 0000000..605f3cf --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/layout.vue @@ -0,0 +1,412 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/extra-menu.vue b/admin-ui/vue/packages/effects/layouts/src/basic/menu/extra-menu.vue new file mode 100644 index 0000000..5f194a7 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/extra-menu.vue @@ -0,0 +1,41 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/menu/index.ts new file mode 100644 index 0000000..72b87ad --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/index.ts @@ -0,0 +1,5 @@ +export { default as LayoutExtraMenu } from './extra-menu.vue'; +export { default as LayoutMenu } from './menu.vue'; +export { default as LayoutMixedMenu } from './mixed-menu.vue'; +export * from './use-extra-menu'; +export * from './use-mixed-menu'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/menu.vue b/admin-ui/vue/packages/effects/layouts/src/basic/menu/menu.vue new file mode 100644 index 0000000..cbb5cfb --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/menu.vue @@ -0,0 +1,45 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue b/admin-ui/vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue new file mode 100644 index 0000000..ae12cc9 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue @@ -0,0 +1,46 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-extra-menu.ts b/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-extra-menu.ts new file mode 100644 index 0000000..e2afb74 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-extra-menu.ts @@ -0,0 +1,133 @@ +import type { ComputedRef } from 'vue'; + +import type { MenuRecordRaw } from '@vben/types'; + +import { computed, ref, watch } from 'vue'; +import { useRoute } from 'vue-router'; + +import { preferences } from '@vben/preferences'; +import { useAccessStore } from '@vben/stores'; +import { findRootMenuByPath } from '@vben/utils'; + +import { useNavigation } from './use-navigation'; + +function useExtraMenu(useRootMenus?: ComputedRef) { + const accessStore = useAccessStore(); + const { navigation, willOpenedByWindow } = useNavigation(); + + const menus = computed(() => useRootMenus?.value ?? accessStore.accessMenus); + + /** 记录当前顶级菜单下哪个子菜单最后激活 */ + const defaultSubMap = new Map(); + const extraRootMenus = ref([]); + const route = useRoute(); + const extraMenus = ref([]); + const sidebarExtraVisible = ref(false); + const extraActiveMenu = ref(''); + const parentLevel = computed(() => + preferences.app.layout === 'header-mixed-nav' ? 1 : 0, + ); + + /** + * 选择混合菜单事件 + * @param menu + */ + const handleMixedMenuSelect = async (menu: MenuRecordRaw) => { + const _extraMenus = menu?.children ?? []; + const hasChildren = _extraMenus.length > 0; + + if (!willOpenedByWindow(menu.path)) { + extraMenus.value = _extraMenus ?? []; + extraActiveMenu.value = menu.parents?.[parentLevel.value] ?? menu.path; + sidebarExtraVisible.value = hasChildren; + } + + if (!hasChildren) { + await navigation(menu.path); + } else if (preferences.sidebar.autoActivateChild) { + await navigation( + defaultSubMap.has(menu.path) + ? (defaultSubMap.get(menu.path) as string) + : menu.path, + ); + } + }; + + /** + * 选择默认菜单事件 + * @param menu + * @param rootMenu + */ + const handleDefaultSelect = async ( + menu: MenuRecordRaw, + rootMenu?: MenuRecordRaw, + ) => { + extraMenus.value = rootMenu?.children ?? extraRootMenus.value ?? []; + extraActiveMenu.value = menu.parents?.[parentLevel.value] ?? menu.path; + + if (preferences.sidebar.expandOnHover) { + sidebarExtraVisible.value = extraMenus.value.length > 0; + } + }; + + /** + * 侧边菜单鼠标移出事件 + */ + const handleSideMouseLeave = () => { + if (preferences.sidebar.expandOnHover) { + return; + } + + const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath( + menus.value, + route.path, + ); + extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? ''; + extraMenus.value = rootMenu?.children ?? []; + }; + + const handleMenuMouseEnter = (menu: MenuRecordRaw) => { + if (!preferences.sidebar.expandOnHover) { + const { findMenu } = findRootMenuByPath(menus.value, menu.path); + extraMenus.value = findMenu?.children ?? []; + extraActiveMenu.value = menu.parents?.[parentLevel.value] ?? menu.path; + sidebarExtraVisible.value = extraMenus.value.length > 0; + } + }; + + function calcExtraMenus(path: string) { + const currentPath = route.meta?.activePath || path; + const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath( + menus.value, + currentPath, + parentLevel.value, + ); + extraRootMenus.value = rootMenu?.children ?? []; + if (rootMenuPath) defaultSubMap.set(rootMenuPath, currentPath); + extraActiveMenu.value = rootMenuPath ?? findMenu?.path ?? ''; + extraMenus.value = rootMenu?.children ?? []; + if (preferences.sidebar.expandOnHover) { + sidebarExtraVisible.value = extraMenus.value.length > 0; + } + } + + watch( + () => [route.path, preferences.app.layout], + ([path]) => { + calcExtraMenus(path || ''); + }, + { immediate: true }, + ); + + return { + extraActiveMenu, + extraMenus, + handleDefaultSelect, + handleMenuMouseEnter, + handleMixedMenuSelect, + handleSideMouseLeave, + sidebarExtraVisible, + }; +} + +export { useExtraMenu }; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts b/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts new file mode 100644 index 0000000..8424c38 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts @@ -0,0 +1,172 @@ +import type { MenuRecordRaw } from '@vben/types'; + +import { computed, onBeforeMount, ref, watch } from 'vue'; +import { useRoute } from 'vue-router'; + +import { preferences, usePreferences } from '@vben/preferences'; +import { useAccessStore } from '@vben/stores'; +import { findRootMenuByPath } from '@vben/utils'; + +import { useNavigation } from './use-navigation'; + +function useMixedMenu() { + const { navigation, willOpenedByWindow } = useNavigation(); + const accessStore = useAccessStore(); + const route = useRoute(); + const splitSideMenus = ref([]); + const rootMenuPath = ref(''); + const mixedRootMenuPath = ref(''); + const mixExtraMenus = ref([]); + /** 记录当前顶级菜单下哪个子菜单最后激活 */ + const defaultSubMap = new Map(); + const { isMixedNav, isHeaderMixedNav } = usePreferences(); + + const needSplit = computed( + () => + (preferences.navigation.split && isMixedNav.value) || + isHeaderMixedNav.value, + ); + + const sidebarVisible = computed(() => { + const enableSidebar = preferences.sidebar.enable; + if (needSplit.value) { + return enableSidebar && splitSideMenus.value.length > 0; + } + return enableSidebar; + }); + const menus = computed(() => accessStore.accessMenus); + + /** + * 头部菜单 + */ + const headerMenus = computed(() => { + if (!needSplit.value) { + return menus.value; + } + return menus.value.map((item) => { + return { + ...item, + children: [], + }; + }); + }); + + /** + * 侧边菜单 + */ + const sidebarMenus = computed(() => { + return needSplit.value ? splitSideMenus.value : menus.value; + }); + + const mixHeaderMenus = computed(() => { + return isHeaderMixedNav.value ? sidebarMenus.value : headerMenus.value; + }); + + /** + * 侧边菜单激活路径 + */ + const sidebarActive = computed(() => { + return (route?.meta?.activePath as string) ?? route.path; + }); + + /** + * 头部菜单激活路径 + */ + const headerActive = computed(() => { + if (!needSplit.value) { + return route.meta?.activePath ?? route.path; + } + return rootMenuPath.value; + }); + + /** + * 菜单点击事件处理 + * @param key 菜单路径 + * @param mode 菜单模式 + */ + const handleMenuSelect = (key: string, mode?: string) => { + if (!needSplit.value || mode === 'vertical') { + navigation(key); + return; + } + const rootMenu = menus.value.find((item) => item.path === key); + const _splitSideMenus = rootMenu?.children ?? []; + + if (!willOpenedByWindow(key)) { + rootMenuPath.value = rootMenu?.path ?? ''; + splitSideMenus.value = _splitSideMenus; + } + + if (_splitSideMenus.length === 0) { + navigation(key); + } else if (rootMenu && preferences.sidebar.autoActivateChild) { + navigation( + defaultSubMap.has(rootMenu.path) + ? (defaultSubMap.get(rootMenu.path) as string) + : rootMenu.path, + ); + } + }; + + /** + * 侧边菜单展开事件 + * @param key 路由路径 + * @param parentsPath 父级路径 + */ + const handleMenuOpen = (key: string, parentsPath: string[]) => { + if (parentsPath.length <= 1 && preferences.sidebar.autoActivateChild) { + navigation( + defaultSubMap.has(key) ? (defaultSubMap.get(key) as string) : key, + ); + } + }; + + /** + * 计算侧边菜单 + * @param path 路由路径 + */ + function calcSideMenus(path: string = route.path) { + let { rootMenu } = findRootMenuByPath(menus.value, path); + if (!rootMenu) { + rootMenu = menus.value.find((item) => item.path === path); + } + const result = findRootMenuByPath(rootMenu?.children || [], path, 1); + mixedRootMenuPath.value = result.rootMenuPath ?? ''; + mixExtraMenus.value = result.rootMenu?.children ?? []; + rootMenuPath.value = rootMenu?.path ?? ''; + splitSideMenus.value = rootMenu?.children ?? []; + } + + watch( + () => route.path, + (path) => { + const currentPath = route?.meta?.activePath ?? route?.meta?.link ?? path; + if (willOpenedByWindow(currentPath)) { + return; + } + calcSideMenus(currentPath); + if (rootMenuPath.value) + defaultSubMap.set(rootMenuPath.value, currentPath); + }, + { immediate: true }, + ); + + // 初始化计算侧边菜单 + onBeforeMount(() => { + calcSideMenus(route.meta?.activePath || route.path); + }); + + return { + handleMenuSelect, + handleMenuOpen, + headerActive, + headerMenus, + sidebarActive, + sidebarMenus, + mixHeaderMenus, + mixExtraMenus, + sidebarVisible, + }; +} + +export { useMixedMenu }; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-navigation.ts b/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-navigation.ts new file mode 100644 index 0000000..daa6dc7 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/menu/use-navigation.ts @@ -0,0 +1,74 @@ +import type { RouteRecordNormalized } from 'vue-router'; + +import { useRouter } from 'vue-router'; + +import { isHttpUrl, openRouteInNewWindow, openWindow } from '@vben/utils'; + +function useNavigation() { + const router = useRouter(); + const routeMetaMap = new Map(); + + // 初始化路由映射 + const initRouteMetaMap = () => { + const routes = router.getRoutes(); + routes.forEach((route) => { + routeMetaMap.set(route.path, route); + }); + }; + + initRouteMetaMap(); + + // 监听路由变化 + router.afterEach(() => { + initRouteMetaMap(); + }); + + // 检查是否应该在新窗口打开 + const shouldOpenInNewWindow = (path: string): boolean => { + if (isHttpUrl(path)) { + return true; + } + const route = routeMetaMap.get(path); + // 如果有外链或者设置了在新窗口打开,返回 true + return !!(route?.meta?.link || route?.meta?.openInNewWindow); + }; + + const resolveHref = (path: string): string => { + return router.resolve(path).href; + }; + + const navigation = async (path: string) => { + try { + const route = routeMetaMap.get(path); + const { openInNewWindow = false, query = {}, link } = route?.meta ?? {}; + + // 检查是否有外链 + if (link && typeof link === 'string') { + openWindow(link, { target: '_blank' }); + return; + } + + if (isHttpUrl(path)) { + openWindow(path, { target: '_blank' }); + } else if (openInNewWindow) { + openRouteInNewWindow(resolveHref(path)); + } else { + await router.push({ + path, + query, + }); + } + } catch (error) { + console.error('Navigation failed:', error); + throw error; + } + }; + + const willOpenedByWindow = (path: string) => { + return shouldOpenInNewWindow(path); + }; + + return { navigation, willOpenedByWindow }; +} + +export { useNavigation }; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/index.ts b/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/index.ts new file mode 100644 index 0000000..5cc2479 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/index.ts @@ -0,0 +1,2 @@ +export { default as LayoutTabbar } from './tabbar.vue'; +export * from './use-tabbar'; diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue b/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue new file mode 100644 index 0000000..8e4f33b --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue @@ -0,0 +1,75 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts b/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts new file mode 100644 index 0000000..0f0ef34 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts @@ -0,0 +1,227 @@ +import type { RouteLocationNormalizedGeneric } from 'vue-router'; + +import type { TabDefinition } from '@vben/types'; + +import type { IContextMenuItem } from '@vben-core/tabs-ui'; + +import { computed, ref, watch } from 'vue'; +import { useRoute, useRouter } from 'vue-router'; + +import { useContentMaximize, useTabs } from '@vben/hooks'; +import { + ArrowLeftToLine, + ArrowRightLeft, + ArrowRightToLine, + ExternalLink, + FoldHorizontal, + Fullscreen, + Minimize2, + Pin, + PinOff, + RotateCw, + X, +} from '@vben/icons'; +import { $t, useI18n } from '@vben/locales'; +import { getTabKey, useAccessStore, useTabbarStore } from '@vben/stores'; +import { filterTree } from '@vben/utils'; + +export function useTabbar() { + const router = useRouter(); + const route = useRoute(); + const accessStore = useAccessStore(); + const tabbarStore = useTabbarStore(); + const { contentIsMaximize, toggleMaximize } = useContentMaximize(); + const { + closeAllTabs, + closeCurrentTab, + closeLeftTabs, + closeOtherTabs, + closeRightTabs, + closeTabByKey, + getTabDisableState, + openTabInNewWindow, + refreshTab, + toggleTabPin, + } = useTabs(); + + /** + * 当前路径对应的tab的key + */ + const currentActive = computed(() => { + return getTabKey(route); + }); + + const { locale } = useI18n(); + const currentTabs = ref(); + watch( + [ + () => tabbarStore.getTabs, + () => tabbarStore.updateTime, + () => locale.value, + ], + ([tabs]) => { + currentTabs.value = tabs.map((item) => wrapperTabLocale(item)); + }, + ); + + /** + * 初始化固定标签页 + */ + const initAffixTabs = () => { + const affixTabs = filterTree(router.getRoutes(), (route) => { + return !!route.meta?.affixTab; + }); + tabbarStore.setAffixTabs(affixTabs); + }; + + // 点击tab,跳转路由 + const handleClick = (key: string) => { + const { fullPath, path } = tabbarStore.getTabByKey(key); + router.push(fullPath || path); + }; + + // 关闭tab + const handleClose = async (key: string) => { + await closeTabByKey(key); + }; + + function wrapperTabLocale(tab: RouteLocationNormalizedGeneric) { + return { + ...tab, + meta: { + ...tab?.meta, + title: $t(tab?.meta?.title as string), + }, + }; + } + + watch( + () => accessStore.accessMenus, + () => { + initAffixTabs(); + }, + { immediate: true }, + ); + + watch( + () => route.fullPath, + () => { + const meta = route.matched?.[route.matched.length - 1]?.meta; + tabbarStore.addTab({ + ...route, + meta: meta || route.meta, + }); + }, + { immediate: true }, + ); + + const createContextMenus = (tab: TabDefinition) => { + const { + disabledCloseAll, + disabledCloseCurrent, + disabledCloseLeft, + disabledCloseOther, + disabledCloseRight, + disabledRefresh, + } = getTabDisableState(tab); + + const affixTab = tab?.meta?.affixTab ?? false; + + const menus: IContextMenuItem[] = [ + { + disabled: disabledCloseCurrent, + handler: async () => { + await closeCurrentTab(tab); + }, + icon: X, + key: 'close', + text: $t('preferences.tabbar.contextMenu.close'), + }, + { + handler: async () => { + await toggleTabPin(tab); + }, + icon: affixTab ? PinOff : Pin, + key: 'affix', + text: affixTab + ? $t('preferences.tabbar.contextMenu.unpin') + : $t('preferences.tabbar.contextMenu.pin'), + }, + { + handler: async () => { + if (!contentIsMaximize.value) { + await router.push(tab.fullPath); + } + toggleMaximize(); + }, + icon: contentIsMaximize.value ? Minimize2 : Fullscreen, + key: contentIsMaximize.value ? 'restore-maximize' : 'maximize', + text: contentIsMaximize.value + ? $t('preferences.tabbar.contextMenu.restoreMaximize') + : $t('preferences.tabbar.contextMenu.maximize'), + }, + { + disabled: disabledRefresh, + handler: () => refreshTab(), + icon: RotateCw, + key: 'reload', + text: $t('preferences.tabbar.contextMenu.reload'), + }, + { + handler: async () => { + await openTabInNewWindow(tab); + }, + icon: ExternalLink, + key: 'open-in-new-window', + separator: true, + text: $t('preferences.tabbar.contextMenu.openInNewWindow'), + }, + + { + disabled: disabledCloseLeft, + handler: async () => { + await closeLeftTabs(tab); + }, + icon: ArrowLeftToLine, + key: 'close-left', + text: $t('preferences.tabbar.contextMenu.closeLeft'), + }, + { + disabled: disabledCloseRight, + handler: async () => { + await closeRightTabs(tab); + }, + icon: ArrowRightToLine, + key: 'close-right', + separator: true, + text: $t('preferences.tabbar.contextMenu.closeRight'), + }, + { + disabled: disabledCloseOther, + handler: async () => { + await closeOtherTabs(tab); + }, + icon: FoldHorizontal, + key: 'close-other', + text: $t('preferences.tabbar.contextMenu.closeOther'), + }, + { + disabled: disabledCloseAll, + handler: closeAllTabs, + icon: ArrowRightLeft, + key: 'close-all', + text: $t('preferences.tabbar.contextMenu.closeAll'), + }, + ]; + + return menus.filter((item) => tabbarStore.getMenuList.includes(item.key)); + }; + + return { + createContextMenus, + currentActive, + currentTabs, + handleClick, + handleClose, + }; +} diff --git a/admin-ui/vue/packages/effects/layouts/src/iframe/iframe-router-view.vue b/admin-ui/vue/packages/effects/layouts/src/iframe/iframe-router-view.vue new file mode 100644 index 0000000..3f1f952 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/iframe/iframe-router-view.vue @@ -0,0 +1,86 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/iframe/iframe-view.vue b/admin-ui/vue/packages/effects/layouts/src/iframe/iframe-view.vue new file mode 100644 index 0000000..7b8b46c --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/iframe/iframe-view.vue @@ -0,0 +1,3 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/iframe/index.ts b/admin-ui/vue/packages/effects/layouts/src/iframe/index.ts new file mode 100644 index 0000000..1b8c131 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/iframe/index.ts @@ -0,0 +1,2 @@ +export { default as IFrameRouterView } from './iframe-router-view.vue'; +export { default as IFrameView } from './iframe-view.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/index.ts b/admin-ui/vue/packages/effects/layouts/src/index.ts new file mode 100644 index 0000000..124a44a --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/index.ts @@ -0,0 +1,4 @@ +export * from './authentication'; +export * from './basic'; +export * from './iframe'; +export * from './widgets'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/breadcrumb.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/breadcrumb.vue new file mode 100644 index 0000000..c041960 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/breadcrumb.vue @@ -0,0 +1,74 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue new file mode 100644 index 0000000..4f3082f --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue @@ -0,0 +1,136 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/check-updates/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/check-updates/index.ts new file mode 100644 index 0000000..fc20c66 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/check-updates/index.ts @@ -0,0 +1 @@ +export { default as CheckUpdates } from './check-updates.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/color-toggle.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/color-toggle.vue new file mode 100644 index 0000000..ae15cb8 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/color-toggle.vue @@ -0,0 +1,64 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/global-search.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/global-search.vue new file mode 100644 index 0000000..bd8b334 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/global-search.vue @@ -0,0 +1,157 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/index.ts new file mode 100644 index 0000000..cd490ae --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/index.ts @@ -0,0 +1 @@ +export { default as GlobalSearch } from './global-search.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue new file mode 100644 index 0000000..6e94049 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue @@ -0,0 +1,288 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/index.ts new file mode 100644 index 0000000..0f9e11a --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/index.ts @@ -0,0 +1,12 @@ +export { default as Breadcrumb } from './breadcrumb.vue'; +export * from './check-updates'; +export { default as AuthenticationColorToggle } from './color-toggle.vue'; +export * from './global-search'; +export { default as LanguageToggle } from './language-toggle.vue'; +export { default as AuthenticationLayoutToggle } from './layout-toggle.vue'; +export * from './lock-screen'; +export * from './notification'; +export * from './preferences'; +export * from './theme-toggle'; +export * from './timezone'; +export * from './user-dropdown'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/language-toggle.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/language-toggle.vue new file mode 100644 index 0000000..f92432f --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/language-toggle.vue @@ -0,0 +1,39 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/layout-toggle.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/layout-toggle.vue new file mode 100644 index 0000000..ae4eecb --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/layout-toggle.vue @@ -0,0 +1,64 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/index.ts new file mode 100644 index 0000000..8ba1f16 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/index.ts @@ -0,0 +1,2 @@ +export { default as LockScreenModal } from './lock-screen-modal.vue'; +export { default as LockScreen } from './lock-screen.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue new file mode 100644 index 0000000..908e670 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue @@ -0,0 +1,110 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue new file mode 100644 index 0000000..3f70033 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue @@ -0,0 +1,167 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/notification/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/notification/index.ts new file mode 100644 index 0000000..e219b71 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/notification/index.ts @@ -0,0 +1,3 @@ +export { default as Notification } from './notification.vue'; + +export type * from './types'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/notification/notification.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/notification/notification.vue new file mode 100644 index 0000000..8089dd7 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/notification/notification.vue @@ -0,0 +1,235 @@ + + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/notification/types.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/notification/types.ts new file mode 100644 index 0000000..4b684f2 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/notification/types.ts @@ -0,0 +1,17 @@ +interface NotificationItem { + id: number | string; + avatar: string; + date: string; + isRead?: boolean; + message: string; + title: string; + /** + * 跳转链接,可以是路由路径或完整 URL + * @example '/dashboard' 或 'https://example.com' + */ + link?: string; + query?: Record; + state?: Record; +} + +export type { NotificationItem }; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue new file mode 100644 index 0000000..c8cc9e6 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue @@ -0,0 +1,22 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue new file mode 100644 index 0000000..99940c6 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue @@ -0,0 +1,63 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue new file mode 100644 index 0000000..b27d074 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue @@ -0,0 +1,51 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue new file mode 100644 index 0000000..c69cd3a --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue @@ -0,0 +1,47 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/index.ts new file mode 100644 index 0000000..cdd6bb1 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/index.ts @@ -0,0 +1,20 @@ +export { default as Block } from './block.vue'; +export { default as Animation } from './general/animation.vue'; +export { default as General } from './general/general.vue'; +export { default as Breadcrumb } from './layout/breadcrumb.vue'; +export { default as Content } from './layout/content.vue'; +export { default as Copyright } from './layout/copyright.vue'; +export { default as Footer } from './layout/footer.vue'; +export { default as Header } from './layout/header.vue'; +export { default as Layout } from './layout/layout.vue'; +export { default as Navigation } from './layout/navigation.vue'; +export { default as Sidebar } from './layout/sidebar.vue'; +export { default as Tabbar } from './layout/tabbar.vue'; +export { default as Widget } from './layout/widget.vue'; +export { default as GlobalShortcutKeys } from './shortcut-keys/global.vue'; +export { default as SwitchItem } from './switch-item.vue'; +export { default as BuiltinTheme } from './theme/builtin.vue'; +export { default as ColorMode } from './theme/color-mode.vue'; +export { default as FontSize } from './theme/font-size.vue'; +export { default as Radius } from './theme/radius.vue'; +export { default as Theme } from './theme/theme.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue new file mode 100644 index 0000000..8e9f09e --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue @@ -0,0 +1,63 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue new file mode 100644 index 0000000..51f1a40 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue @@ -0,0 +1,56 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue new file mode 100644 index 0000000..75af1c3 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue @@ -0,0 +1,53 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue new file mode 100644 index 0000000..9389029 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue @@ -0,0 +1,44 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue new file mode 100644 index 0000000..8a77920 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue @@ -0,0 +1,17 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue new file mode 100644 index 0000000..ee04ee2 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue @@ -0,0 +1,74 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue new file mode 100644 index 0000000..a46650b --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue @@ -0,0 +1,112 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue new file mode 100644 index 0000000..23acb1f --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue @@ -0,0 +1,45 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue new file mode 100644 index 0000000..e8d84af --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue @@ -0,0 +1,100 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue new file mode 100644 index 0000000..ea533da --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue @@ -0,0 +1,94 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue new file mode 100644 index 0000000..82addb3 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue @@ -0,0 +1,71 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue new file mode 100644 index 0000000..3878f81 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue @@ -0,0 +1,74 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue new file mode 100644 index 0000000..fabc371 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue @@ -0,0 +1,68 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue new file mode 100644 index 0000000..f71a1f6 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue @@ -0,0 +1,50 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue new file mode 100644 index 0000000..33d99e9 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue @@ -0,0 +1,55 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue new file mode 100644 index 0000000..d0dba8e --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue @@ -0,0 +1,163 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue new file mode 100644 index 0000000..9a41d4e --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue @@ -0,0 +1,26 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue new file mode 100644 index 0000000..b1aaa2d --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue @@ -0,0 +1,62 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue new file mode 100644 index 0000000..4201ed6 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue @@ -0,0 +1,38 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue new file mode 100644 index 0000000..1a5ca4b --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue @@ -0,0 +1,83 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue new file mode 100644 index 0000000..3f2a4a2 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue @@ -0,0 +1,46 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue new file mode 100644 index 0000000..a1bcefd --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue @@ -0,0 +1,119 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue new file mode 100644 index 0000000..5cbcaca --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue @@ -0,0 +1,50 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue new file mode 100644 index 0000000..d5c9367 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue @@ -0,0 +1,202 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue new file mode 100644 index 0000000..18158b3 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue @@ -0,0 +1,119 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue new file mode 100644 index 0000000..b44e249 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue @@ -0,0 +1,177 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/index.ts new file mode 100644 index 0000000..7eec1b4 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/index.ts @@ -0,0 +1,12 @@ +import HeaderNav from './header-nav.vue'; + +export { default as ContentCompact } from './content-compact.vue'; +export { default as FullContent } from './full-content.vue'; +export { default as HeaderMixedNav } from './header-mixed-nav.vue'; +export { default as HeaderSidebarNav } from './header-sidebar-nav.vue'; +export { default as MixedNav } from './mixed-nav.vue'; +export { default as SidebarMixedNav } from './sidebar-mixed-nav.vue'; +export { default as SidebarNav } from './sidebar-nav.vue'; + +const ContentWide = HeaderNav; +export { ContentWide, HeaderNav }; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue new file mode 100644 index 0000000..d194383 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue @@ -0,0 +1,161 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue new file mode 100644 index 0000000..d824e11 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue @@ -0,0 +1,12 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue new file mode 100644 index 0000000..8fc0ba4 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue @@ -0,0 +1,173 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue new file mode 100644 index 0000000..83ff399 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue @@ -0,0 +1,153 @@ + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/index.ts new file mode 100644 index 0000000..2c737d5 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/index.ts @@ -0,0 +1,3 @@ +export { default as PreferencesButton } from './preferences-button.vue'; +export { default as Preferences } from './preferences.vue'; +export * from './use-open-preferences'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue new file mode 100644 index 0000000..8598bb2 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue @@ -0,0 +1,20 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue new file mode 100644 index 0000000..c88a9bc --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue @@ -0,0 +1,493 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences.vue new file mode 100644 index 0000000..8bf91eb --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/preferences.vue @@ -0,0 +1,72 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts new file mode 100644 index 0000000..eb9d847 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts @@ -0,0 +1,16 @@ +import { ref } from 'vue'; + +const openPreferences = ref(false); + +function useOpenPreferences() { + function handleOpenPreference() { + openPreferences.value = true; + } + + return { + handleOpenPreference, + openPreferences, + }; +} + +export { useOpenPreferences }; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts new file mode 100644 index 0000000..0673d21 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts @@ -0,0 +1 @@ +export { default as ThemeToggle } from './theme-toggle.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue new file mode 100644 index 0000000..8d24b53 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue @@ -0,0 +1,188 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue new file mode 100644 index 0000000..19c132e --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue @@ -0,0 +1,83 @@ + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/timezone/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/timezone/index.ts new file mode 100644 index 0000000..eef486d --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/timezone/index.ts @@ -0,0 +1 @@ +export { default as TimezoneButton } from './timezone-button.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue new file mode 100644 index 0000000..f426b94 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts b/admin-ui/vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts new file mode 100644 index 0000000..86429e9 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts @@ -0,0 +1 @@ +export { default as UserDropdown } from './user-dropdown.vue'; diff --git a/admin-ui/vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue b/admin-ui/vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue new file mode 100644 index 0000000..8156324 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue @@ -0,0 +1,262 @@ + + + diff --git a/admin-ui/vue/packages/effects/layouts/tsconfig.json b/admin-ui/vue/packages/effects/layouts/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/effects/layouts/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/effects/plugins/README.md b/admin-ui/vue/packages/effects/plugins/README.md new file mode 100644 index 0000000..c394c9c --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/README.md @@ -0,0 +1,28 @@ +# @vben/plugins + +该目录用于存放项目中集成的第三方库及其相关插件。每个插件都包含了可重用的逻辑、配置和组件,方便在项目中进行统一管理和调用。 + +## 注意 + +所有的第三方插件都必须以 `subpath` 形式引入,例: + +以 `echarts` 为例,引入方式如下: + +**packages.json** + +```json +"exports": { + "./echarts": { + "types": "./src/echarts/index.ts", + "default": "./src/echarts/index.ts" + } + } +``` + +**使用方式** + +```ts +import { useEcharts } from '@vben/plugins/echarts'; +``` + +这样做的好处是,应用可以自行选择是否使用插件,而不会因为插件的引入及副作用而导致打包体积增大,只引入需要的插件即可。 diff --git a/admin-ui/vue/packages/effects/plugins/package.json b/admin-ui/vue/packages/effects/plugins/package.json new file mode 100644 index 0000000..add6e78 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/package.json @@ -0,0 +1,47 @@ +{ + "name": "@vben/plugins", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/effects/plugins" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + "./echarts": { + "types": "./src/echarts/index.ts", + "default": "./src/echarts/index.ts" + }, + "./vxe-table": { + "types": "./src/vxe-table/index.ts", + "default": "./src/vxe-table/index.ts" + }, + "./motion": { + "types": "./src/motion/index.ts", + "default": "./src/motion/index.ts" + } + }, + "dependencies": { + "@vben-core/form-ui": "workspace:*", + "@vben-core/shadcn-ui": "workspace:*", + "@vben-core/shared": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/locales": "workspace:*", + "@vben/preferences": "workspace:*", + "@vben/types": "workspace:*", + "@vben/utils": "workspace:*", + "@vueuse/core": "catalog:", + "@vueuse/motion": "catalog:", + "echarts": "catalog:", + "vue": "catalog:", + "vxe-pc-ui": "catalog:", + "vxe-table": "catalog:" + } +} diff --git a/admin-ui/vue/packages/effects/plugins/src/echarts/echarts-ui.vue b/admin-ui/vue/packages/effects/plugins/src/echarts/echarts-ui.vue new file mode 100644 index 0000000..70d1f20 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/echarts/echarts-ui.vue @@ -0,0 +1,15 @@ + + + diff --git a/admin-ui/vue/packages/effects/plugins/src/echarts/echarts.ts b/admin-ui/vue/packages/effects/plugins/src/echarts/echarts.ts new file mode 100644 index 0000000..8e1b249 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/echarts/echarts.ts @@ -0,0 +1,61 @@ +import type { + // 系列类型的定义后缀都为 SeriesOption + BarSeriesOption, + LineSeriesOption, +} from 'echarts/charts'; +import type { + DatasetComponentOption, + GridComponentOption, + // 组件类型的定义后缀都为 ComponentOption + TitleComponentOption, + TooltipComponentOption, +} from 'echarts/components'; +import type { ComposeOption } from 'echarts/core'; + +import { BarChart, LineChart, PieChart, RadarChart, MapChart, GaugeChart } from 'echarts/charts'; +import { + // 数据集组件 + DatasetComponent, + GridComponent, + LegendComponent, + TitleComponent, + ToolboxComponent, + TooltipComponent, + // 内置数据转换器组件 (filter, sort) + TransformComponent, +} from 'echarts/components'; +import * as echarts from 'echarts/core'; +import { LabelLayout, UniversalTransition } from 'echarts/features'; +import { CanvasRenderer } from 'echarts/renderers'; + +// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型 +export type ECOption = ComposeOption< + | BarSeriesOption + | DatasetComponentOption + | GridComponentOption + | LineSeriesOption + | TitleComponentOption + | TooltipComponentOption +>; + +// 注册必须的组件 +echarts.use([ + TitleComponent, + PieChart, + RadarChart, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent, + BarChart, + LineChart, + LabelLayout, + UniversalTransition, + CanvasRenderer, + LegendComponent, + ToolboxComponent, + MapChart, + GaugeChart, +]); + +export default echarts; diff --git a/admin-ui/vue/packages/effects/plugins/src/echarts/index.ts b/admin-ui/vue/packages/effects/plugins/src/echarts/index.ts new file mode 100644 index 0000000..80f36a1 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/echarts/index.ts @@ -0,0 +1,3 @@ +export * from './echarts'; +export { default as EchartsUI } from './echarts-ui.vue'; +export * from './use-echarts'; diff --git a/admin-ui/vue/packages/effects/plugins/src/echarts/use-echarts.ts b/admin-ui/vue/packages/effects/plugins/src/echarts/use-echarts.ts new file mode 100644 index 0000000..e7ceed3 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/echarts/use-echarts.ts @@ -0,0 +1,148 @@ +import type { EChartsOption } from 'echarts'; + +import type { Ref } from 'vue'; + +import type { Nullable } from '@vben/types'; + +import type EchartsUI from './echarts-ui.vue'; + +import { computed, nextTick, watch } from 'vue'; + +import { usePreferences } from '@vben/preferences'; + +import { + tryOnUnmounted, + useDebounceFn, + useResizeObserver, + useTimeoutFn, + useWindowSize, +} from '@vueuse/core'; + +import echarts from './echarts'; + +type EchartsUIType = typeof EchartsUI | undefined; + +type EchartsThemeType = 'dark' | 'light' | null; + +function useEcharts(chartRef: Ref) { + let chartInstance: echarts.ECharts | null = null; + let cacheOptions: EChartsOption = {}; + + const { isDark } = usePreferences(); + const { height, width } = useWindowSize(); + const resizeHandler: () => void = useDebounceFn(resize, 200); + + const getChartEl = (): HTMLElement | null => { + const refValue = chartRef?.value as unknown; + if (!refValue) return null; + if (refValue instanceof HTMLElement) { + return refValue; + } + const maybeComponent = refValue as { $el?: HTMLElement }; + return maybeComponent.$el ?? null; + }; + + const isElHidden = (el: HTMLElement | null): boolean => { + if (!el) return true; + return el.offsetHeight === 0 || el.offsetWidth === 0; + }; + + const getOptions = computed((): EChartsOption => { + if (!isDark.value) { + return {}; + } + + return { + backgroundColor: 'transparent', + }; + }); + + const initCharts = (t?: EchartsThemeType) => { + const el = chartRef?.value?.$el; + if (!el) { + return; + } + chartInstance = echarts.init(el, t || isDark.value ? 'dark' : null); + + return chartInstance; + }; + + const renderEcharts = ( + options: EChartsOption, + clear = true, + ): Promise> => { + cacheOptions = options; + const currentOptions = { + ...options, + ...getOptions.value, + }; + return new Promise((resolve) => { + if (chartRef.value?.offsetHeight === 0) { + useTimeoutFn(async () => { + resolve(await renderEcharts(currentOptions)); + }, 30); + return; + } + nextTick(() => { + const el = getChartEl(); + if (isElHidden(el)) { + useTimeoutFn(async () => { + resolve(await renderEcharts(currentOptions)); + }, 30); + return; + } + useTimeoutFn(() => { + if (!chartInstance) { + const instance = initCharts(); + if (!instance) return; + } + clear && chartInstance?.clear(); + chartInstance?.setOption(currentOptions); + resolve(chartInstance); + }, 30); + }); + }); + }; + + function resize() { + const el = getChartEl(); + if (isElHidden(el)) { + return; + } + chartInstance?.resize({ + animation: { + duration: 300, + easing: 'quadraticIn', + }, + }); + } + + watch([width, height], () => { + resizeHandler?.(); + }); + + useResizeObserver(chartRef as never, resizeHandler); + + watch(isDark, () => { + if (chartInstance) { + chartInstance.dispose(); + initCharts(); + renderEcharts(cacheOptions); + resize(); + } + }); + + tryOnUnmounted(() => { + // 销毁实例,释放资源 + chartInstance?.dispose(); + }); + return { + renderEcharts, + resize, + getChartInstance: () => chartInstance, + }; +} + +export { useEcharts, echarts }; + +export type { EchartsUIType }; diff --git a/admin-ui/vue/packages/effects/plugins/src/motion/index.ts b/admin-ui/vue/packages/effects/plugins/src/motion/index.ts new file mode 100644 index 0000000..021465a --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/motion/index.ts @@ -0,0 +1,8 @@ +export * from './types'; + +export { + MotionComponent as Motion, + MotionDirective, + MotionGroupComponent as MotionGroup, + MotionPlugin, +} from '@vueuse/motion'; diff --git a/admin-ui/vue/packages/effects/plugins/src/motion/types.ts b/admin-ui/vue/packages/effects/plugins/src/motion/types.ts new file mode 100644 index 0000000..f08bf21 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/motion/types.ts @@ -0,0 +1,26 @@ +export const MotionPresets = [ + 'fade', + 'fadeVisible', + 'fadeVisibleOnce', + 'rollBottom', + 'rollLeft', + 'rollRight', + 'rollTop', + 'rollVisibleBottom', + 'rollVisibleLeft', + 'rollVisibleRight', + 'rollVisibleTop', + 'pop', + 'popVisible', + 'popVisibleOnce', + 'slideBottom', + 'slideLeft', + 'slideRight', + 'slideTop', + 'slideVisibleBottom', + 'slideVisibleLeft', + 'slideVisibleRight', + 'slideVisibleTop', +] as const; + +export type MotionPreset = (typeof MotionPresets)[number]; diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/api.ts b/admin-ui/vue/packages/effects/plugins/src/vxe-table/api.ts new file mode 100644 index 0000000..2b60d60 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/api.ts @@ -0,0 +1,128 @@ +import type { VxeGridInstance } from 'vxe-table'; + +import type { ExtendedFormApi } from '@vben-core/form-ui'; + +import type { VxeGridProps } from './types'; + +import { toRaw } from 'vue'; + +import { Store } from '@vben-core/shared/store'; +import { + bindMethods, + isBoolean, + isFunction, + mergeWithArrayOverride, + StateHandler, +} from '@vben-core/shared/utils'; + +function getDefaultState(): VxeGridProps { + return { + class: '', + gridClass: '', + gridOptions: {}, + gridEvents: {}, + formOptions: undefined, + showSearchForm: true, + }; +} + +export class VxeGridApi = any> { + public formApi = {} as ExtendedFormApi; + + // private prevState: null | VxeGridProps = null; + public grid = {} as VxeGridInstance; + public state: null | VxeGridProps = null; + + public store: Store>; + + private isMounted = false; + + private stateHandler: StateHandler; + + constructor(options: VxeGridProps = {}) { + const storeState = { ...options }; + + const defaultState = getDefaultState(); + this.store = new Store( + mergeWithArrayOverride(storeState, defaultState), + { + onUpdate: () => { + // this.prevState = this.state; + this.state = this.store.state; + }, + }, + ); + + this.state = this.store.state; + this.stateHandler = new StateHandler(); + bindMethods(this); + } + + mount(instance: null | VxeGridInstance, formApi: ExtendedFormApi) { + if (!this.isMounted && instance) { + this.grid = instance; + this.formApi = formApi; + this.stateHandler.setConditionTrue(); + this.isMounted = true; + } + } + + async query(params: Record = {}) { + try { + await this.grid.commitProxy('query', toRaw(params)); + } catch (error) { + console.error('Error occurred while querying:', error); + } + } + + async reload(params: Record = {}) { + try { + await this.grid.commitProxy('reload', toRaw(params)); + } catch (error) { + console.error('Error occurred while reloading:', error); + } + } + + setGridOptions(options: Partial) { + this.setState({ + gridOptions: options, + }); + } + + setLoading(isLoading: boolean) { + this.setState({ + gridOptions: { + loading: isLoading, + }, + }); + } + + setState( + stateOrFn: + | ((prev: VxeGridProps) => Partial>) + | Partial>, + ) { + if (isFunction(stateOrFn)) { + this.store.setState((prev) => { + return mergeWithArrayOverride(stateOrFn(prev), prev); + }); + } else { + this.store.setState((prev) => mergeWithArrayOverride(stateOrFn, prev)); + } + } + + toggleSearchForm(show?: boolean) { + this.setState({ + showSearchForm: isBoolean(show) ? show : !this.state?.showSearchForm, + }); + // nextTick(() => { + // this.grid.recalculate(); + // }); + return this.state?.showSearchForm; + } + + unmount() { + this.isMounted = false; + this.stateHandler.reset(); + } +} diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/extends.ts b/admin-ui/vue/packages/effects/plugins/src/vxe-table/extends.ts new file mode 100644 index 0000000..a6cf4ca --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/extends.ts @@ -0,0 +1,81 @@ +import type { VxeGridProps, VxeUIExport } from 'vxe-table'; + +import type { Recordable } from '@vben/types'; + +import type { VxeGridApi } from './api'; + +import { formatDate, formatDateTime, isFunction } from '@vben/utils'; + +export function extendProxyOptions( + api: VxeGridApi, + options: VxeGridProps, + getFormValues: () => Recordable, +) { + [ + 'query', + 'querySuccess', + 'queryError', + 'queryAll', + 'queryAllSuccess', + 'queryAllError', + ].forEach((key) => { + extendProxyOption(key, api, options, getFormValues); + }); +} + +function extendProxyOption( + key: string, + api: VxeGridApi, + options: VxeGridProps, + getFormValues: () => Recordable, +) { + const { proxyConfig } = options; + const configFn = (proxyConfig?.ajax as Recordable)?.[key]; + if (!isFunction(configFn)) { + return options; + } + + const wrapperFn = async ( + params: Recordable, + customValues: Recordable, + ...args: Recordable[] + ) => { + const formValues = getFormValues(); + const data = await configFn( + params, + { + /** + * 开启toolbarConfig.refresh功能 + * 点击刷新按钮 这里的值为PointerEvent 会携带错误参数 + */ + ...(customValues instanceof PointerEvent ? {} : customValues), + ...formValues, + }, + ...args, + ); + return data; + }; + api.setState({ + gridOptions: { + proxyConfig: { + ajax: { + [key]: wrapperFn, + }, + }, + }, + }); +} + +export function extendsDefaultFormatter(vxeUI: VxeUIExport) { + vxeUI.formats.add('formatDate', { + tableCellFormatMethod({ cellValue }) { + return formatDate(cellValue); + }, + }); + + vxeUI.formats.add('formatDateTime', { + tableCellFormatMethod({ cellValue }) { + return formatDateTime(cellValue); + }, + }); +} diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/index.ts b/admin-ui/vue/packages/effects/plugins/src/vxe-table/index.ts new file mode 100644 index 0000000..a19f2b8 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/index.ts @@ -0,0 +1,10 @@ +export { setupVbenVxeTable } from './init'; +export type { VxeTableGridOptions } from './types'; +export * from './use-vxe-grid'; + +export { default as VbenVxeGrid } from './use-vxe-grid.vue'; +export type { + VxeGridListeners, + VxeGridProps, + VxeGridPropTypes, +} from 'vxe-table'; diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/init.ts b/admin-ui/vue/packages/effects/plugins/src/vxe-table/init.ts new file mode 100644 index 0000000..00e9d8a --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/init.ts @@ -0,0 +1,131 @@ +import type { SetupVxeTable } from './types'; + +import { defineComponent, watch } from 'vue'; + +import { usePreferences } from '@vben/preferences'; + +import { useVbenForm } from '@vben-core/form-ui'; + +import { + VxeButton, + VxeCheckbox, + + // VxeFormGather, + // VxeForm, + // VxeFormItem, + VxeIcon, + VxeInput, + VxeLoading, + VxeModal, + VxeNumberInput, + VxePager, + // VxeList, + // VxeModal, + // VxeOptgroup, + // VxeOption, + // VxePulldown, + // VxeRadio, + // VxeRadioButton, + VxeRadioGroup, + VxeSelect, + VxeTooltip, + VxeUI, + VxeUpload, + // VxeSwitch, + // VxeTextarea, +} from 'vxe-pc-ui'; +import enUS from 'vxe-pc-ui/lib/language/en-US'; +// 导入默认的语言 +import zhCN from 'vxe-pc-ui/lib/language/zh-CN'; +import { + VxeColgroup, + VxeColumn, + VxeGrid, + VxeTable, + VxeToolbar, +} from 'vxe-table'; + +import { extendsDefaultFormatter } from './extends'; + +// 是否加载过 +let isInit = false; + +// eslint-disable-next-line import/no-mutable-exports +export let useTableForm: typeof useVbenForm; + +// 部分组件,如果没注册,vxe-table 会报错,这里实际没用组件,只是为了不报错,同时可以减少打包体积 +const createVirtualComponent = (name = '') => { + return defineComponent({ + name, + }); +}; + +export function initVxeTable() { + if (isInit) { + return; + } + + VxeUI.component(VxeTable); + VxeUI.component(VxeColumn); + VxeUI.component(VxeColgroup); + VxeUI.component(VxeGrid); + VxeUI.component(VxeToolbar); + + VxeUI.component(VxeButton); + // VxeUI.component(VxeButtonGroup); + VxeUI.component(VxeCheckbox); + // VxeUI.component(VxeCheckboxGroup); + VxeUI.component(createVirtualComponent('VxeForm')); + // VxeUI.component(VxeFormGather); + // VxeUI.component(VxeFormItem); + VxeUI.component(VxeIcon); + VxeUI.component(VxeInput); + // VxeUI.component(VxeList); + VxeUI.component(VxeLoading); + VxeUI.component(VxeModal); + VxeUI.component(VxeNumberInput); + // VxeUI.component(VxeOptgroup); + // VxeUI.component(VxeOption); + VxeUI.component(VxePager); + // VxeUI.component(VxePulldown); + // VxeUI.component(VxeRadio); + // VxeUI.component(VxeRadioButton); + VxeUI.component(VxeRadioGroup); + VxeUI.component(VxeSelect); + // VxeUI.component(VxeSwitch); + // VxeUI.component(VxeTextarea); + VxeUI.component(VxeTooltip); + VxeUI.component(VxeUpload); + + isInit = true; +} + +export function setupVbenVxeTable(setupOptions: SetupVxeTable) { + const { configVxeTable, useVbenForm } = setupOptions; + + initVxeTable(); + useTableForm = useVbenForm; + + const { isDark, locale } = usePreferences(); + + const localMap = { + 'zh-CN': zhCN, + 'en-US': enUS, + }; + + watch( + [() => isDark.value, () => locale.value], + ([isDarkValue, localeValue]) => { + VxeUI.setTheme(isDarkValue ? 'dark' : 'light'); + VxeUI.setI18n(localeValue, localMap[localeValue]); + VxeUI.setLanguage(localeValue); + }, + { + immediate: true, + }, + ); + + extendsDefaultFormatter(VxeUI); + + configVxeTable(VxeUI); +} diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/style.css b/admin-ui/vue/packages/effects/plugins/src/vxe-table/style.css new file mode 100644 index 0000000..5b47fa2 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/style.css @@ -0,0 +1,117 @@ +:root .vxe-grid { + --vxe-ui-font-color: hsl(var(--foreground)); + --vxe-ui-font-primary-color: hsl(var(--primary)); + + /* --vxe-ui-font-lighten-color: #babdc0; + --vxe-ui-font-darken-color: #86898e; */ + --vxe-ui-font-disabled-color: hsl(var(--foreground) / 50%); + + /* base */ + --vxe-ui-base-popup-border-color: hsl(var(--border)); + --vxe-ui-input-disabled-color: hsl(var(--border) / 60%); + + /* --vxe-ui-base-popup-box-shadow: 0px 12px 30px 8px rgb(0 0 0 / 50%); */ + + /* layout */ + --vxe-ui-layout-background-color: hsl(var(--background)); + --vxe-ui-table-resizable-line-color: hsl(var(--heavy)); + + /* --vxe-ui-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px hsl(var(--accent)); + --vxe-ui-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px hsl(var(--accent)); */ + + /* input */ + --vxe-ui-input-border-color: hsl(var(--border)); + + /* --vxe-ui-input-placeholder-color: #8d9095; */ + + /* --vxe-ui-input-disabled-background-color: #262727; */ + + /* loading */ + --vxe-ui-loading-background-color: hsl(var(--overlay-content)); + + /* table */ + --vxe-ui-table-header-background-color: hsl(var(--accent)); + --vxe-ui-table-border-color: hsl(var(--border)); + --vxe-ui-table-row-hover-background-color: hsl(var(--accent-hover)); + --vxe-ui-table-row-striped-background-color: hsl(var(--accent) / 60%); + --vxe-ui-table-row-hover-striped-background-color: hsl(var(--accent)); + --vxe-ui-table-row-radio-checked-background-color: hsl(var(--accent)); + --vxe-ui-table-row-hover-radio-checked-background-color: hsl( + var(--accent-hover) + ); + --vxe-ui-table-row-checkbox-checked-background-color: hsl(var(--accent)); + --vxe-ui-table-row-hover-checkbox-checked-background-color: hsl( + var(--accent-hover) + ); + --vxe-ui-table-row-current-background-color: hsl(var(--accent)); + --vxe-ui-table-row-hover-current-background-color: hsl(var(--accent-hover)); + --vxe-ui-font-primary-tinge-color: hsl(var(--primary)); + --vxe-ui-font-primary-lighten-color: hsl(var(--primary) / 60%); + --vxe-ui-font-primary-darken-color: hsl(var(--primary)); + + height: auto !important; + + /* --vxe-ui-table-fixed-scrolling-box-shadow-color: rgb(0 0 0 / 80%); */ +} + +.vxe-pager { + .vxe-pager--prev-btn:not(.is--disabled):active, + .vxe-pager--next-btn:not(.is--disabled):active, + .vxe-pager--num-btn:not(.is--disabled):active, + .vxe-pager--jump-prev:not(.is--disabled):active, + .vxe-pager--jump-next:not(.is--disabled):active, + .vxe-pager--prev-btn:not(.is--disabled):focus, + .vxe-pager--next-btn:not(.is--disabled):focus, + .vxe-pager--num-btn:not(.is--disabled):focus, + .vxe-pager--jump-prev:not(.is--disabled):focus, + .vxe-pager--jump-next:not(.is--disabled):focus { + color: hsl(var(--accent-foreground)); + background-color: hsl(var(--accent)); + border: 1px solid hsl(var(--border)); + box-shadow: 0 0 0 1px hsl(var(--border)); + } + + .vxe-pager--wrapper { + display: flex; + align-items: center; + } + + .vxe-pager--sizes { + margin-right: auto; + } +} + +.vxe-pager--wrapper { + @apply justify-center md:justify-end; +} + +.vxe-tools--operate { + margin-right: 0.25rem; + margin-left: 0.75rem; +} + +.vxe-table-custom--checkbox-option:hover { + background: none !important; +} + +.vxe-toolbar { + padding: 0; +} + +.vxe-buttons--wrapper:not(:empty), +.vxe-tools--operate:not(:empty), +.vxe-tools--wrapper:not(:empty) { + padding: 0.6em 0; +} + +.vxe-tools--operate:not(:has(button)) { + margin-left: 0; +} + +.vxe-grid--layout-header-wrapper { + overflow: visible; +} + +.vxe-grid--layout-body-content-wrapper { + overflow: hidden; +} diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/types.ts b/admin-ui/vue/packages/effects/plugins/src/vxe-table/types.ts new file mode 100644 index 0000000..8b9aea4 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/types.ts @@ -0,0 +1,93 @@ +import type { + VxeGridListeners, + VxeGridPropTypes, + VxeGridProps as VxeTableGridProps, + VxeUIExport, +} from 'vxe-table'; + +import type { Ref } from 'vue'; + +import type { ClassType, DeepPartial } from '@vben/types'; + +import type { BaseFormComponentType, VbenFormProps } from '@vben-core/form-ui'; + +import type { VxeGridApi } from './api'; + +import { useVbenForm } from '@vben-core/form-ui'; + +export interface VxePaginationInfo { + currentPage: number; + pageSize: number; + total: number; +} + +interface ToolbarConfigOptions extends VxeGridPropTypes.ToolbarConfig { + /** 是否显示切换搜索表单的按钮 */ + search?: boolean; +} + +export interface VxeTableGridOptions extends VxeTableGridProps { + /** 工具栏配置 */ + toolbarConfig?: ToolbarConfigOptions; +} + +export interface SeparatorOptions { + show?: boolean; + backgroundColor?: string; +} + +export interface VxeGridProps< + T extends Record = any, + D extends BaseFormComponentType = BaseFormComponentType, +> { + /** + * 标题 + */ + tableTitle?: string; + /** + * 标题帮助 + */ + tableTitleHelp?: string; + /** + * 组件class + */ + class?: ClassType; + /** + * vxe-grid class + */ + gridClass?: ClassType; + /** + * vxe-grid 配置 + */ + gridOptions?: DeepPartial>; + /** + * vxe-grid 事件 + */ + gridEvents?: DeepPartial>; + /** + * 表单配置 + */ + formOptions?: VbenFormProps; + /** + * 显示搜索表单 + */ + showSearchForm?: boolean; + /** + * 搜索表单与表格主体之间的分隔条 + */ + separator?: boolean | SeparatorOptions; +} + +export type ExtendedVxeGridApi< + D extends Record = any, + F extends BaseFormComponentType = BaseFormComponentType, +> = VxeGridApi & { + useStore: >>( + selector?: (state: NoInfer>) => T, + ) => Readonly>; +}; + +export interface SetupVxeTable { + configVxeTable: (ui: VxeUIExport) => void; + useVbenForm: typeof useVbenForm; +} diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts b/admin-ui/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts new file mode 100644 index 0000000..6ab8769 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts @@ -0,0 +1,70 @@ +import type { VxeGridSlots, VxeGridSlotTypes } from 'vxe-table'; + +import type { SlotsType } from 'vue'; + +import type { BaseFormComponentType } from '@vben-core/form-ui'; + +import type { ExtendedVxeGridApi, VxeGridProps } from './types'; + +import { defineComponent, h, onBeforeUnmount } from 'vue'; + +import { useStore } from '@vben-core/shared/store'; + +import { VxeGridApi } from './api'; +import VxeGrid from './use-vxe-grid.vue'; + +type FilteredSlots = { + [K in keyof VxeGridSlots as K extends 'form' + ? never + : K]: VxeGridSlots[K]; +}; + +export function useVbenVxeGrid< + T extends Record = any, + D extends BaseFormComponentType = BaseFormComponentType, +>(options: VxeGridProps) { + // const IS_REACTIVE = isReactive(options); + const api = new VxeGridApi(options); + const extendedApi: ExtendedVxeGridApi = api as ExtendedVxeGridApi; + extendedApi.useStore = (selector) => { + return useStore(api.store, selector); + }; + + const Grid = defineComponent( + (props: VxeGridProps, { attrs, slots }) => { + onBeforeUnmount(() => { + api.unmount(); + }); + api.setState({ ...props, ...attrs }); + return () => h(VxeGrid, { ...props, ...attrs, api: extendedApi }, slots); + }, + { + name: 'VbenVxeGrid', + inheritAttrs: false, + slots: Object as SlotsType< + { + // 表格标题 + 'table-title': undefined; + // 工具栏左侧部分 + 'toolbar-actions': VxeGridSlotTypes.DefaultSlotParams; + // 工具栏右侧部分 + 'toolbar-tools': VxeGridSlotTypes.DefaultSlotParams; + } & FilteredSlots + >, + }, + ); + // Add reactivity support + // if (IS_REACTIVE) { + // watch( + // () => options, + // () => { + // api.setState(options); + // }, + // { immediate: true }, + // ); + // } + + return [Grid, extendedApi] as const; +} + +export type UseVbenVxeGrid = typeof useVbenVxeGrid; diff --git a/admin-ui/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue b/admin-ui/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue new file mode 100644 index 0000000..7b002a2 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue @@ -0,0 +1,479 @@ + + + diff --git a/admin-ui/vue/packages/effects/plugins/tsconfig.json b/admin-ui/vue/packages/effects/plugins/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/effects/plugins/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/effects/request/package.json b/admin-ui/vue/packages/effects/request/package.json new file mode 100644 index 0000000..0b557d3 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/package.json @@ -0,0 +1,32 @@ +{ + "name": "@vben/request", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/effects/request" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben/locales": "workspace:*", + "@vben/utils": "workspace:*", + "axios": "catalog:", + "qs": "catalog:" + }, + "devDependencies": { + "@types/qs": "catalog:", + "axios-mock-adapter": "catalog:" + } +} diff --git a/admin-ui/vue/packages/effects/request/src/index.ts b/admin-ui/vue/packages/effects/request/src/index.ts new file mode 100644 index 0000000..fae1b05 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/index.ts @@ -0,0 +1,2 @@ +export * from './request-client'; +export * from 'axios'; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/index.ts b/admin-ui/vue/packages/effects/request/src/request-client/index.ts new file mode 100644 index 0000000..a44cd15 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/index.ts @@ -0,0 +1,3 @@ +export * from './preset-interceptors'; +export * from './request-client'; +export type * from './types'; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/downloader.test.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/downloader.test.ts new file mode 100644 index 0000000..27e8a30 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/downloader.test.ts @@ -0,0 +1,157 @@ +import type { AxiosRequestConfig } from 'axios'; + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { FileDownloader } from './downloader'; + +describe('fileDownloader', () => { + let fileDownloader: FileDownloader; + const mockAxiosInstance = { + get: vi.fn(), + } as any; + + beforeEach(() => { + fileDownloader = new FileDownloader(mockAxiosInstance); + }); + + it('should create an instance of FileDownloader', () => { + expect(fileDownloader).toBeInstanceOf(FileDownloader); + }); + + it('should download a file and return a Blob', async () => { + const url = 'https://example.com/file'; + const mockBlob = new Blob(['file content'], { type: 'text/plain' }); + const mockResponse: Blob = mockBlob; + + mockAxiosInstance.get.mockResolvedValueOnce(mockResponse); + + const result = await fileDownloader.download(url); + + expect(result).toBeInstanceOf(Blob); + expect(result).toEqual(mockBlob); + expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, { + method: 'GET', + responseType: 'blob', + responseReturn: 'body', + }); + }); + + it('should merge provided config with default config', async () => { + const url = 'https://example.com/file'; + const mockBlob = new Blob(['file content'], { type: 'text/plain' }); + const mockResponse: Blob = mockBlob; + + mockAxiosInstance.get.mockResolvedValueOnce(mockResponse); + + const customConfig: AxiosRequestConfig = { + headers: { 'Custom-Header': 'value' }, + }; + + const result = await fileDownloader.download(url, customConfig); + expect(result).toBeInstanceOf(Blob); + expect(result).toEqual(mockBlob); + expect(mockAxiosInstance.get).toHaveBeenCalledWith(url, { + ...customConfig, + method: 'GET', + responseType: 'blob', + responseReturn: 'body', + }); + }); + + it('should handle errors gracefully', async () => { + const url = 'https://example.com/file'; + mockAxiosInstance.get.mockRejectedValueOnce(new Error('Network Error')); + await expect(fileDownloader.download(url)).rejects.toThrow('Network Error'); + }); + + it('should handle empty URL gracefully', async () => { + const url = ''; + mockAxiosInstance.get.mockRejectedValueOnce( + new Error('Request failed with status code 404'), + ); + + await expect(fileDownloader.download(url)).rejects.toThrow( + 'Request failed with status code 404', + ); + }); + + it('should handle null URL gracefully', async () => { + const url = null as unknown as string; + mockAxiosInstance.get.mockRejectedValueOnce( + new Error('Request failed with status code 404'), + ); + + await expect(fileDownloader.download(url)).rejects.toThrow( + 'Request failed with status code 404', + ); + }); +}); + +describe('fileDownloader use other method', () => { + let fileDownloader: FileDownloader; + + it('should call request using get', async () => { + const url = 'https://example.com/file'; + const mockBlob = new Blob(['file content'], { type: 'text/plain' }); + const mockResponse: Blob = mockBlob; + + const mockAxiosInstance = { + request: vi.fn(), + } as any; + + fileDownloader = new FileDownloader(mockAxiosInstance); + + mockAxiosInstance.request.mockResolvedValueOnce(mockResponse); + + const result = await fileDownloader.download(url); + + expect(result).toBeInstanceOf(Blob); + expect(result).toEqual(mockBlob); + expect(mockAxiosInstance.request).toHaveBeenCalledWith(url, { + method: 'GET', + responseType: 'blob', + responseReturn: 'body', + }); + }); + + it('should call post', async () => { + const url = 'https://example.com/file'; + + const mockAxiosInstance = { + post: vi.fn(), + } as any; + + fileDownloader = new FileDownloader(mockAxiosInstance); + + const customConfig: AxiosRequestConfig = { + method: 'POST', + data: { name: 'aa' }, + }; + + await fileDownloader.download(url, customConfig); + + expect(mockAxiosInstance.post).toHaveBeenCalledWith( + url, + { name: 'aa' }, + { + method: 'POST', + responseType: 'blob', + responseReturn: 'body', + }, + ); + }); + + it('should handle errors gracefully', async () => { + const url = 'https://example.com/file'; + const mockAxiosInstance = { + post: vi.fn(), + } as any; + + fileDownloader = new FileDownloader(mockAxiosInstance); + await expect(() => + fileDownloader.download(url, { method: 'postt' }), + ).rejects.toThrow( + 'RequestClient does not support method "POSTT". Please ensure the method is properly implemented in your RequestClient instance.', + ); + }); +}); diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/downloader.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/downloader.ts new file mode 100644 index 0000000..6c30005 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/downloader.ts @@ -0,0 +1,60 @@ +import type { RequestClient } from '../request-client'; +import type { RequestClientConfig } from '../types'; + +type DownloadRequestConfig = { + /** + * 定义期望获得的数据类型。 + * raw: 原始的AxiosResponse,包括headers、status等。 + * body: 只返回响应数据的BODY部分(Blob) + */ + responseReturn?: 'body' | 'raw'; +} & Omit; + +class FileDownloader { + private client: RequestClient; + + constructor(client: RequestClient) { + this.client = client; + } + /** + * 下载文件 + * @param url 文件的完整链接 + * @param config 配置信息,可选。 + * @returns 如果config.responseReturn为'body',则返回Blob(默认),否则返回RequestResponse + */ + public async download( + url: string, + config?: DownloadRequestConfig, + ): Promise { + const finalConfig: DownloadRequestConfig = { + responseReturn: 'body', + method: 'GET', + ...config, + responseType: 'blob', + }; + + // Prefer a generic request if available; otherwise, dispatch to method-specific calls. + const method = (finalConfig.method || 'GET').toUpperCase(); + const clientAny = this.client as any; + + if (typeof clientAny.request === 'function') { + return await clientAny.request(url, finalConfig); + } + const lower = method.toLowerCase(); + + if (typeof clientAny[lower] === 'function') { + if (['POST', 'PUT'].includes(method)) { + const { data, ...rest } = finalConfig as Record; + return await clientAny[lower](url, data, rest); + } + + return await clientAny[lower](url, finalConfig); + } + + throw new Error( + `RequestClient does not support method "${method}". Please ensure the method is properly implemented in your RequestClient instance.`, + ); + } +} + +export { FileDownloader }; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/interceptor.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/interceptor.ts new file mode 100644 index 0000000..f6d2ad8 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/interceptor.ts @@ -0,0 +1,40 @@ +import type { AxiosInstance, AxiosResponse } from 'axios'; + +import type { + RequestInterceptorConfig, + ResponseInterceptorConfig, +} from '../types'; + +const defaultRequestInterceptorConfig: RequestInterceptorConfig = { + fulfilled: (response) => response, + rejected: (error) => Promise.reject(error), +}; + +const defaultResponseInterceptorConfig: ResponseInterceptorConfig = { + fulfilled: (response: AxiosResponse) => response, + rejected: (error) => Promise.reject(error), +}; + +class InterceptorManager { + private axiosInstance: AxiosInstance; + + constructor(instance: AxiosInstance) { + this.axiosInstance = instance; + } + + addRequestInterceptor({ + fulfilled, + rejected, + }: RequestInterceptorConfig = defaultRequestInterceptorConfig) { + this.axiosInstance.interceptors.request.use(fulfilled, rejected); + } + + addResponseInterceptor({ + fulfilled, + rejected, + }: ResponseInterceptorConfig = defaultResponseInterceptorConfig) { + this.axiosInstance.interceptors.response.use(fulfilled, rejected); + } +} + +export { InterceptorManager }; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/sse.test.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/sse.test.ts new file mode 100644 index 0000000..4e8c6a9 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/sse.test.ts @@ -0,0 +1,142 @@ +import type { RequestClient } from '../request-client'; + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { SSE } from './sse'; + +// 模拟 TextDecoder +const OriginalTextDecoder = globalThis.TextDecoder; + +beforeEach(() => { + vi.stubGlobal( + 'TextDecoder', + class { + private decoder = new OriginalTextDecoder(); + decode(value: Uint8Array, opts?: any) { + return this.decoder.decode(value, opts); + } + }, + ); +}); + +// 创建 fetch mock +const createFetchMock = (chunks: string[], ok = true) => { + const encoder = new TextEncoder(); + let index = 0; + return vi.fn().mockResolvedValue({ + ok, + status: ok ? 200 : 500, + body: { + getReader: () => ({ + read: async () => { + if (index < chunks.length) { + return { done: false, value: encoder.encode(chunks[index++]) }; + } + return { done: true, value: undefined }; + }, + }), + }, + }); +}; + +describe('sSE', () => { + let client: RequestClient; + let sse: SSE; + + beforeEach(() => { + vi.restoreAllMocks(); + client = { + getBaseUrl: () => 'http://localhost', + instance: { + interceptors: { + request: { + handlers: [], + }, + }, + }, + } as unknown as RequestClient; + sse = new SSE(client); + }); + + it('should call requestSSE when postSSE is used', async () => { + const spy = vi.spyOn(sse, 'requestSSE').mockResolvedValue(undefined); + await sse.postSSE('/test', { foo: 'bar' }, { headers: { a: '1' } }); + expect(spy).toHaveBeenCalledWith( + '/test', + { foo: 'bar' }, + { + headers: { a: '1' }, + method: 'POST', + }, + ); + }); + + it('should throw error if fetch response not ok', async () => { + vi.stubGlobal('fetch', createFetchMock([], false)); + await expect(sse.requestSSE('/bad')).rejects.toThrow( + 'HTTP error! status: 500', + ); + }); + + it('should trigger onMessage and onEnd callbacks', async () => { + const messages: string[] = []; + const onMessage = vi.fn((msg: string) => messages.push(msg)); + const onEnd = vi.fn(); + + vi.stubGlobal('fetch', createFetchMock(['hello', ' world'])); + + await sse.requestSSE('/sse', undefined, { onMessage, onEnd }); + + expect(onMessage).toHaveBeenCalledTimes(2); + expect(messages.join('')).toBe('hello world'); + // onEnd 不再带参数 + expect(onEnd).toHaveBeenCalled(); + }); + + it('should apply request interceptors', async () => { + const interceptor = vi.fn(async (config) => { + config.headers['x-test'] = 'intercepted'; + return config; + }); + (client.instance.interceptors.request as any).handlers.push({ + fulfilled: interceptor, + }); + + // 创建 fetch mock,并挂到全局 + const fetchMock = createFetchMock(['data']); + vi.stubGlobal('fetch', fetchMock); + + await sse.requestSSE('/sse', undefined, {}); + + expect(interceptor).toHaveBeenCalled(); + expect(fetchMock).toHaveBeenCalledWith( + 'http://localhost/sse', + expect.objectContaining({ + headers: expect.any(Headers), + }), + ); + + const calls = fetchMock.mock?.calls; + expect(calls).toBeDefined(); + expect(calls?.length).toBeGreaterThan(0); + + const init = calls?.[0]?.[1] as RequestInit; + expect(init).toBeDefined(); + + const headers = init?.headers as Headers; + expect(headers?.get('x-test')).toBe('intercepted'); + expect(headers?.get('accept')).toBe('text/event-stream'); + }); + + it('should throw error when no reader', async () => { + vi.stubGlobal( + 'fetch', + vi.fn().mockResolvedValue({ + ok: true, + status: 200, + body: null, + }), + ); + await expect(sse.requestSSE('/sse')).rejects.toThrow('No reader'); + }); +}); diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/sse.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/sse.ts new file mode 100644 index 0000000..09d1301 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/sse.ts @@ -0,0 +1,136 @@ +import type { AxiosRequestHeaders, InternalAxiosRequestConfig } from 'axios'; + +import type { RequestClient } from '../request-client'; +import type { SseRequestOptions } from '../types'; + +/** + * SSE模块 + */ +class SSE { + private client: RequestClient; + + constructor(client: RequestClient) { + this.client = client; + } + + public async postSSE( + url: string, + data?: any, + requestOptions?: SseRequestOptions, + ) { + return this.requestSSE(url, data, { + ...requestOptions, + method: 'POST', + }); + } + + /** + * SSE请求方法 + * @param url - 请求URL + * @param data - 请求数据 + * @param requestOptions - SSE请求选项 + */ + public async requestSSE( + url: string, + data?: any, + requestOptions?: SseRequestOptions, + ) { + const baseUrl = this.client.getBaseUrl() || ''; + + let axiosConfig: InternalAxiosRequestConfig = { + url, + method: (requestOptions?.method as any) ?? 'GET', + headers: {} as AxiosRequestHeaders, + }; + const requestInterceptors = this.client.instance.interceptors + .request as any; + if ( + requestInterceptors.handlers && + requestInterceptors.handlers.length > 0 + ) { + for (const handler of requestInterceptors.handlers) { + if (typeof handler?.fulfilled === 'function') { + const next = await handler.fulfilled(axiosConfig as any); + if (next) axiosConfig = next as InternalAxiosRequestConfig; + } + } + } + + const merged = new Headers(); + Object.entries( + (axiosConfig.headers ?? {}) as Record, + ).forEach(([k, v]) => merged.set(k, String(v))); + if (requestOptions?.headers) { + new Headers(requestOptions.headers).forEach((v, k) => merged.set(k, v)); + } + if (!merged.has('accept')) { + merged.set('accept', 'text/event-stream'); + } + + let bodyInit = requestOptions?.body ?? data; + const ct = (merged.get('content-type') || '').toLowerCase(); + if ( + bodyInit && + typeof bodyInit === 'object' && + !ArrayBuffer.isView(bodyInit as any) && + !(bodyInit instanceof ArrayBuffer) && + !(bodyInit instanceof Blob) && + !(bodyInit instanceof FormData) && + ct.includes('application/json') + ) { + bodyInit = JSON.stringify(bodyInit); + } + const requestInit: RequestInit = { + ...requestOptions, + method: axiosConfig.method, + headers: merged, + body: bodyInit, + }; + + const response = await fetch(safeJoinUrl(baseUrl, url), requestInit); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const reader = response.body?.getReader(); + const decoder = new TextDecoder(); + + if (!reader) { + throw new Error('No reader'); + } + let isEnd = false; + while (!isEnd) { + const { done, value } = await reader.read(); + if (done) { + isEnd = true; + decoder.decode(new Uint8Array(0), { stream: false }); + requestOptions?.onEnd?.(); + reader.releaseLock?.(); + break; + } + const content = decoder.decode(value, { stream: true }); + requestOptions?.onMessage?.(content); + } + } +} + +function safeJoinUrl(baseUrl: string | undefined, url: string): string { + if (!baseUrl) { + return url; // 没有 baseUrl,直接返回 url + } + + // 如果 url 本身就是绝对地址,直接返回 + if (/^https?:\/\//i.test(url)) { + return url; + } + + // 如果 baseUrl 是完整 URL,就用 new URL + if (/^https?:\/\//i.test(baseUrl)) { + return new URL(url, baseUrl).toString(); + } + + // 否则,当作路径拼接 + return `${baseUrl.replace(/\/+$/, '')}/${url.replace(/^\/+/, '')}`; +} + +export { SSE }; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/uploader.test.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/uploader.test.ts new file mode 100644 index 0000000..8306656 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/uploader.test.ts @@ -0,0 +1,118 @@ +import type { AxiosRequestConfig, AxiosResponse } from 'axios'; + +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { FileUploader } from './uploader'; + +describe('fileUploader', () => { + let fileUploader: FileUploader; + // Mock the AxiosInstance + const mockAxiosInstance = { + post: vi.fn(), + } as any; + + beforeEach(() => { + fileUploader = new FileUploader(mockAxiosInstance); + }); + + it('should create an instance of FileUploader', () => { + expect(fileUploader).toBeInstanceOf(FileUploader); + }); + + it('should upload a file and return the response', async () => { + const url = 'https://example.com/upload'; + const file = new File(['file content'], 'test.txt', { type: 'text/plain' }); + const mockResponse: AxiosResponse = { + config: {} as any, + data: { success: true }, + headers: {}, + status: 200, + statusText: 'OK', + }; + + ( + mockAxiosInstance.post as unknown as ReturnType + ).mockResolvedValueOnce(mockResponse); + + const result = await fileUploader.upload(url, { file }); + expect(result).toEqual(mockResponse); + expect(mockAxiosInstance.post).toHaveBeenCalledWith( + url, + expect.any(FormData), + { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }, + ); + }); + + it('should merge provided config with default config', async () => { + const url = 'https://example.com/upload'; + const file = new File(['file content'], 'test.txt', { type: 'text/plain' }); + const mockResponse: AxiosResponse = { + config: {} as any, + data: { success: true }, + headers: {}, + status: 200, + statusText: 'OK', + }; + + ( + mockAxiosInstance.post as unknown as ReturnType + ).mockResolvedValueOnce(mockResponse); + + const customConfig: AxiosRequestConfig = { + headers: { 'Custom-Header': 'value' }, + }; + + const result = await fileUploader.upload(url, { file }, customConfig); + expect(result).toEqual(mockResponse); + expect(mockAxiosInstance.post).toHaveBeenCalledWith( + url, + expect.any(FormData), + { + headers: { + 'Content-Type': 'multipart/form-data', + 'Custom-Header': 'value', + }, + }, + ); + }); + + it('should handle errors gracefully', async () => { + const url = 'https://example.com/upload'; + const file = new File(['file content'], 'test.txt', { type: 'text/plain' }); + ( + mockAxiosInstance.post as unknown as ReturnType + ).mockRejectedValueOnce(new Error('Network Error')); + + await expect(fileUploader.upload(url, { file })).rejects.toThrow( + 'Network Error', + ); + }); + + it('should handle empty URL gracefully', async () => { + const url = ''; + const file = new File(['file content'], 'test.txt', { type: 'text/plain' }); + ( + mockAxiosInstance.post as unknown as ReturnType + ).mockRejectedValueOnce(new Error('Request failed with status code 404')); + + await expect(fileUploader.upload(url, { file })).rejects.toThrow( + 'Request failed with status code 404', + ); + }); + + it('should handle null URL gracefully', async () => { + const url = null as unknown as string; + const file = new File(['file content'], 'test.txt', { type: 'text/plain' }); + ( + mockAxiosInstance.post as unknown as ReturnType + ).mockRejectedValueOnce(new Error('Request failed with status code 404')); + + await expect(fileUploader.upload(url, { file })).rejects.toThrow( + 'Request failed with status code 404', + ); + }); +}); diff --git a/admin-ui/vue/packages/effects/request/src/request-client/modules/uploader.ts b/admin-ui/vue/packages/effects/request/src/request-client/modules/uploader.ts new file mode 100644 index 0000000..1353222 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/modules/uploader.ts @@ -0,0 +1,42 @@ +import type { RequestClient } from '../request-client'; +import type { RequestClientConfig } from '../types'; + +import { isUndefined } from '@vben/utils'; + +class FileUploader { + private client: RequestClient; + + constructor(client: RequestClient) { + this.client = client; + } + + public async upload( + url: string, + data: Record & { file: Blob | File }, + config?: RequestClientConfig, + ): Promise { + const formData = new FormData(); + + Object.entries(data).forEach(([key, value]) => { + if (Array.isArray(value)) { + value.forEach((item, index) => { + !isUndefined(item) && formData.append(`${key}[${index}]`, item); + }); + } else { + !isUndefined(value) && formData.append(key, value); + } + }); + + const finalConfig: RequestClientConfig = { + ...config, + headers: { + 'Content-Type': 'multipart/form-data', + ...config?.headers, + }, + }; + + return this.client.post(url, formData, finalConfig); + } +} + +export { FileUploader }; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/preset-interceptors.ts b/admin-ui/vue/packages/effects/request/src/request-client/preset-interceptors.ts new file mode 100644 index 0000000..f8bfd43 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/preset-interceptors.ts @@ -0,0 +1,169 @@ +import type { RequestClient } from './request-client'; +import type { MakeErrorMessageFn, ResponseInterceptorConfig } from './types'; + +import { $t } from '@vben/locales'; +import { isFunction } from '@vben/utils'; + +import axios from 'axios'; + +export const defaultResponseInterceptor = ({ + codeField = 'code', + dataField = 'data', + successCode = 0, +}: { + /** 响应数据中代表访问结果的字段名 */ + codeField: string; + /** 响应数据中装载实际数据的字段名,或者提供一个函数从响应数据中解析需要返回的数据 */ + dataField: ((response: any) => any) | string; + /** 当codeField所指定的字段值与successCode相同时,代表接口访问成功。如果提供一个函数,则返回true代表接口访问成功 */ + successCode: ((code: any) => boolean) | number | string; +}): ResponseInterceptorConfig => { + return { + fulfilled: (response) => { + const { config, data: responseData, status } = response; + + if (config.responseReturn === 'raw') { + return response; + } + + if (status >= 200 && status < 400) { + if (config.responseReturn === 'body') { + return responseData; + } else if ( + isFunction(successCode) + ? successCode(responseData[codeField]) + : responseData[codeField] === successCode + ) { + return isFunction(dataField) + ? dataField(responseData) + : responseData[dataField]; + } + } + throw Object.assign({}, response, { response }); + }, + }; +}; + +export const authenticateResponseInterceptor = ({ + client, + doReAuthenticate, + doRefreshToken, + enableRefreshToken, + formatToken, +}: { + client: RequestClient; + doReAuthenticate: () => Promise; + doRefreshToken: () => Promise; + enableRefreshToken: boolean; + formatToken: (token: string) => null | string; +}): ResponseInterceptorConfig => { + return { + rejected: async (error) => { + const { config, response } = error; + // 如果不是 401 错误,直接抛出异常 + if (response?.status !== 401) { + throw error; + } + // 判断是否启用了 refreshToken 功能 + // 如果没有启用或者已经是重试请求了,直接跳转到重新登录 + if (!enableRefreshToken || config.__isRetryRequest) { + await doReAuthenticate(); + throw error; + } + // 如果正在刷新 token,则将请求加入队列,等待刷新完成 + if (client.isRefreshing) { + return new Promise((resolve) => { + client.refreshTokenQueue.push((newToken: string) => { + config.headers.Authorization = formatToken(newToken); + resolve(client.request(config.url, { ...config })); + }); + }); + } + + // 标记开始刷新 token + client.isRefreshing = true; + // 标记当前请求为重试请求,避免无限循环 + config.__isRetryRequest = true; + + try { + const newToken = await doRefreshToken(); + + // 处理队列中的请求 + client.refreshTokenQueue.forEach((callback) => callback(newToken)); + // 清空队列 + client.refreshTokenQueue = []; + + return client.request(error.config.url, { ...error.config }); + } catch (refreshError) { + // 如果刷新 token 失败,处理错误(如强制登出或跳转登录页面) + client.refreshTokenQueue.forEach((callback) => callback('')); + client.refreshTokenQueue = []; + console.error('Refresh token failed, please login again.'); + await doReAuthenticate(); + + throw refreshError; + } finally { + client.isRefreshing = false; + } + }, + }; +}; + +export const errorMessageResponseInterceptor = ( + makeErrorMessage?: MakeErrorMessageFn, +): ResponseInterceptorConfig => { + return { + rejected: (error: any) => { + if (axios.isCancel(error)) { + return Promise.reject(error); + } + + const err: string = error?.toString?.() ?? ''; + let errMsg = ''; + if (err?.includes('Network Error')) { + errMsg = $t('ui.fallback.http.networkError'); + } else if (error?.message?.includes?.('timeout')) { + errMsg = $t('ui.fallback.http.requestTimeout'); + } + if (errMsg) { + makeErrorMessage?.(errMsg, error); + return Promise.reject(error); + } + + let errorMessage = ''; + const status = error?.response?.status; + + switch (status) { + case 400: { + errorMessage = $t('ui.fallback.http.badRequest'); + break; + } + case 401: { + errorMessage = $t('ui.fallback.http.unauthorized'); + break; + } + case 403: { + errorMessage = $t('ui.fallback.http.forbidden'); + break; + } + case 404: { + errorMessage = $t('ui.fallback.http.notFound'); + break; + } + case 408: { + errorMessage = $t('ui.fallback.http.requestTimeout'); + break; + } + case 413: { + errorMessage = $t('ui.fallback.http.payloadTooLarge'); + break; + } + default: { + errorMessage = $t('ui.fallback.http.internalServerError'); + } + } + makeErrorMessage?.(errorMessage, error); + return Promise.reject(error); + }, + }; +}; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/request-client.test.ts b/admin-ui/vue/packages/effects/request/src/request-client/request-client.test.ts new file mode 100644 index 0000000..2d94525 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/request-client.test.ts @@ -0,0 +1,99 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; + +import { RequestClient } from './request-client'; + +describe('requestClient', () => { + let mock: MockAdapter; + let requestClient: RequestClient; + + beforeEach(() => { + mock = new MockAdapter(axios); + requestClient = new RequestClient(); + }); + + afterEach(() => { + mock.reset(); + }); + + it('should successfully make a GET request', async () => { + mock.onGet('test/url').reply(200, { data: 'response' }); + + const response = await requestClient.get('test/url'); + + expect(response.data).toEqual({ data: 'response' }); + }); + + it('should successfully make a POST request', async () => { + const postData = { key: 'value' }; + const mockData = { data: 'response' }; + mock.onPost('/test/post', postData).reply(200, mockData); + const response = await requestClient.post('/test/post', postData); + expect(response.data).toEqual(mockData); + }); + + it('should successfully make a PUT request', async () => { + const putData = { key: 'updatedValue' }; + const mockData = { data: 'updated response' }; + mock.onPut('/test/put', putData).reply(200, mockData); + const response = await requestClient.put('/test/put', putData); + expect(response.data).toEqual(mockData); + }); + + it('should successfully make a DELETE request', async () => { + const mockData = { data: 'delete response' }; + mock.onDelete('/test/delete').reply(200, mockData); + const response = await requestClient.delete('/test/delete'); + expect(response.data).toEqual(mockData); + }); + + it('should handle network errors', async () => { + mock.onGet('/test/error').networkError(); + try { + await requestClient.get('/test/error'); + expect(true).toBe(false); + } catch (error: any) { + expect(error.isAxiosError).toBe(true); + expect(error.message).toBe('Network Error'); + } + }); + + it('should handle timeout', async () => { + mock.onGet('/test/timeout').timeout(); + try { + await requestClient.get('/test/timeout'); + expect(true).toBe(false); + } catch (error: any) { + expect(error.isAxiosError).toBe(true); + expect(error.code).toBe('ECONNABORTED'); + } + }); + + it('should successfully upload a file', async () => { + const fileData = new Blob(['file contents'], { type: 'text/plain' }); + + mock.onPost('/test/upload').reply((config) => { + return config.data instanceof FormData && config.data.has('file') + ? [200, { data: 'file uploaded' }] + : [400, { error: 'Bad Request' }]; + }); + + const response = await requestClient.upload('/test/upload', { + file: fileData, + }); + expect(response.data).toEqual({ data: 'file uploaded' }); + }); + + it('should successfully download a file as a blob', async () => { + const mockFileContent = new Blob(['mock file content'], { + type: 'text/plain', + }); + + mock.onGet('/test/download').reply(200, mockFileContent); + + const res = await requestClient.download('/test/download'); + + expect(res.data).toBeInstanceOf(Blob); + }); +}); diff --git a/admin-ui/vue/packages/effects/request/src/request-client/request-client.ts b/admin-ui/vue/packages/effects/request/src/request-client/request-client.ts new file mode 100644 index 0000000..453913b --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/request-client.ts @@ -0,0 +1,164 @@ +import type { AxiosInstance, AxiosResponse } from 'axios'; + +import type { RequestClientConfig, RequestClientOptions } from './types'; + +import { bindMethods, isString, merge } from '@vben/utils'; + +import axios from 'axios'; +import qs from 'qs'; + +import { FileDownloader } from './modules/downloader'; +import { InterceptorManager } from './modules/interceptor'; +import { SSE } from './modules/sse'; +import { FileUploader } from './modules/uploader'; + +function getParamsSerializer( + paramsSerializer: RequestClientOptions['paramsSerializer'], +) { + if (isString(paramsSerializer)) { + switch (paramsSerializer) { + case 'brackets': { + return (params: any) => + qs.stringify(params, { arrayFormat: 'brackets' }); + } + case 'comma': { + return (params: any) => qs.stringify(params, { arrayFormat: 'comma' }); + } + case 'indices': { + return (params: any) => + qs.stringify(params, { arrayFormat: 'indices' }); + } + case 'repeat': { + return (params: any) => qs.stringify(params, { arrayFormat: 'repeat' }); + } + } + } + return paramsSerializer; +} + +class RequestClient { + public addRequestInterceptor: InterceptorManager['addRequestInterceptor']; + + public addResponseInterceptor: InterceptorManager['addResponseInterceptor']; + public download: FileDownloader['download']; + + public readonly instance: AxiosInstance; + // 是否正在刷新token + public isRefreshing = false; + public postSSE: SSE['postSSE']; + // 刷新token队列 + public refreshTokenQueue: ((token: string) => void)[] = []; + public requestSSE: SSE['requestSSE']; + public upload: FileUploader['upload']; + + /** + * 构造函数,用于创建Axios实例 + * @param options - Axios请求配置,可选 + */ + constructor(options: RequestClientOptions = {}) { + // 合并默认配置和传入的配置 + const defaultConfig: RequestClientOptions = { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + responseReturn: 'raw', + // 默认超时时间 + timeout: 10_000, + }; + const { ...axiosConfig } = options; + const requestConfig = merge(axiosConfig, defaultConfig); + requestConfig.paramsSerializer = getParamsSerializer( + requestConfig.paramsSerializer, + ); + this.instance = axios.create(requestConfig); + + bindMethods(this); + + // 实例化拦截器管理器 + const interceptorManager = new InterceptorManager(this.instance); + this.addRequestInterceptor = + interceptorManager.addRequestInterceptor.bind(interceptorManager); + this.addResponseInterceptor = + interceptorManager.addResponseInterceptor.bind(interceptorManager); + + // 实例化文件上传器 + const fileUploader = new FileUploader(this); + this.upload = fileUploader.upload.bind(fileUploader); + // 实例化文件下载器 + const fileDownloader = new FileDownloader(this); + this.download = fileDownloader.download.bind(fileDownloader); + // 实例化SSE模块 + const sse = new SSE(this); + this.postSSE = sse.postSSE.bind(sse); + this.requestSSE = sse.requestSSE.bind(sse); + } + + /** + * DELETE请求方法 + */ + public delete( + url: string, + config?: RequestClientConfig, + ): Promise { + return this.request(url, { ...config, method: 'DELETE' }); + } + + /** + * GET请求方法 + */ + public get(url: string, config?: RequestClientConfig): Promise { + return this.request(url, { ...config, method: 'GET' }); + } + + /** + * 获取基础URL + */ + public getBaseUrl() { + return this.instance.defaults.baseURL; + } + + /** + * POST请求方法 + */ + public post( + url: string, + data?: any, + config?: RequestClientConfig, + ): Promise { + return this.request(url, { ...config, data, method: 'POST' }); + } + + /** + * PUT请求方法 + */ + public put( + url: string, + data?: any, + config?: RequestClientConfig, + ): Promise { + return this.request(url, { ...config, data, method: 'PUT' }); + } + + /** + * 通用的请求方法 + */ + public async request( + url: string, + config: RequestClientConfig, + ): Promise { + try { + const response: AxiosResponse = await this.instance({ + url, + ...config, + ...(config.paramsSerializer + ? { paramsSerializer: getParamsSerializer(config.paramsSerializer) } + : {}), + }); + return response as T; + } catch (error: any) { + throw error.response ? error.response.data : error; + } + } +} + +export { RequestClient }; diff --git a/admin-ui/vue/packages/effects/request/src/request-client/types.ts b/admin-ui/vue/packages/effects/request/src/request-client/types.ts new file mode 100644 index 0000000..080468b --- /dev/null +++ b/admin-ui/vue/packages/effects/request/src/request-client/types.ts @@ -0,0 +1,106 @@ +import type { + AxiosRequestConfig, + AxiosResponse, + CreateAxiosDefaults, + InternalAxiosRequestConfig, +} from 'axios'; + +type ExtendOptions = { + /** + * 错误提示方式。none 表示只抛出错误,由调用方自行处理。 + */ + errorMessageMode?: 'message' | 'none'; + /** + * 成功提示方式。none 表示不展示成功提示。 + */ + successMessageMode?: 'message' | 'modal' | 'none'; + /** + * 是否返回原始响应。 + */ + isReturnNativeResponse?: boolean; + /** + * 是否转换响应数据。 + */ + isTransformResponse?: boolean; + /** + * 参数序列化方式。预置的有 + * - brackets: ids[]=1&ids[]=2&ids[]=3 + * - comma: ids=1,2,3 + * - indices: ids[0]=1&ids[1]=2&ids[2]=3 + * - repeat: ids=1&ids=2&ids=3 + */ + paramsSerializer?: + | 'brackets' + | 'comma' + | 'indices' + | 'repeat' + | AxiosRequestConfig['paramsSerializer']; + /** + * 响应数据的返回方式。 + * - raw: 原始的AxiosResponse,包括headers、status等,不做是否成功请求的检查。 + * - body: 返回响应数据的BODY部分(只会根据status检查请求是否成功,忽略对code的判断,这种情况下应由调用方检查请求是否成功)。 + * - data: 解构响应的BODY数据,只返回其中的data节点数据(会检查status和code是否为成功状态)。 + */ + responseReturn?: 'body' | 'data' | 'raw'; +}; +type RequestClientConfig = AxiosRequestConfig & ExtendOptions; + +type RequestResponse = AxiosResponse & { + config: RequestClientConfig; +}; + +type RequestContentType = + | 'application/json;charset=utf-8' + | 'application/octet-stream;charset=utf-8' + | 'application/x-www-form-urlencoded;charset=utf-8' + | 'multipart/form-data;charset=utf-8'; + +type RequestClientOptions = CreateAxiosDefaults & ExtendOptions; + +/** + * SSE 请求选项 + */ +interface SseRequestOptions extends RequestInit { + onMessage?: (message: string) => void; + onEnd?: () => void; +} + +interface RequestInterceptorConfig { + fulfilled?: ( + config: ExtendOptions & InternalAxiosRequestConfig, + ) => + | (ExtendOptions & InternalAxiosRequestConfig) + | Promise>; + rejected?: (error: any) => any; +} + +interface ResponseInterceptorConfig { + fulfilled?: ( + response: RequestResponse, + ) => Promise | RequestResponse; + rejected?: (error: any) => any; +} + +type MakeErrorMessageFn = (message: string, error: any) => void; + +interface HttpResponse { + /** + * 0 表示成功 其他表示失败 + * 0 means success, others means fail + */ + code: number; + data: T; + message: string; +} + +export type { + HttpResponse, + MakeErrorMessageFn, + RequestClientConfig, + RequestClientOptions, + RequestContentType, + RequestInterceptorConfig, + RequestResponse, + ResponseInterceptorConfig, + SseRequestOptions, +}; diff --git a/admin-ui/vue/packages/effects/request/tsconfig.json b/admin-ui/vue/packages/effects/request/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/effects/request/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/icons/README.md b/admin-ui/vue/packages/icons/README.md new file mode 100644 index 0000000..bc50d25 --- /dev/null +++ b/admin-ui/vue/packages/icons/README.md @@ -0,0 +1,19 @@ +# @vben/icons + +用于多个 `app` 公用的图标文件,继承了 `@vben-core/icons` 的所有能力。业务上有通用图标可以放在这里。 + +## 用法 + +### 添加依赖 + +```bash +# 进入目标应用目录,例如 apps/xxxx-app +# cd apps/xxxx-app +pnpm add @vben/icons +``` + +### 使用 + +```ts +import { X } from '@vben/icons'; +``` diff --git a/admin-ui/vue/packages/icons/package.json b/admin-ui/vue/packages/icons/package.json new file mode 100644 index 0000000..24680ea --- /dev/null +++ b/admin-ui/vue/packages/icons/package.json @@ -0,0 +1,33 @@ +{ + "name": "@vben/icons", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/icons" + }, + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/icons": "workspace:*" + }, + "devDependencies": { + "@iconify/icons-ant-design": "^1.2.7", + "@iconify/icons-flat-color-icons": "^1.2.5", + "@iconify/icons-la": "^1.2.3", + "@iconify/icons-ri": "^1.2.10", + "@iconify/icons-simple-icons": "^1.2.74", + "@iconify/icons-fa-brands": "^1.2.4", + "@iconify/icons-uiw": "^1.2.6", + "@iconify/icons-logos": "^1.2.36", + "@iconify/icons-arcticons": "^1.2.1" + } +} diff --git a/admin-ui/vue/packages/icons/src/iconify-offline/index.ts b/admin-ui/vue/packages/icons/src/iconify-offline/index.ts new file mode 100644 index 0000000..8c331ae --- /dev/null +++ b/admin-ui/vue/packages/icons/src/iconify-offline/index.ts @@ -0,0 +1,151 @@ +import { createIconifyOfflineIcon } from '@vben-core/icons'; +import userOutlined from '@iconify/icons-ant-design/user-outlined'; +import androidOutlined from '@iconify/icons-ant-design/android-outlined'; +import baiduOutlined from '@iconify/icons-ant-design/ie-outlined'; +import ieOutlined from '@iconify/icons-ant-design/ie-outlined'; +import windowsOutlined from '@iconify/icons-ant-design/windows-outlined'; +import chromeOutlined from '@iconify/icons-ant-design/chrome-outlined'; +import dingtalkOutlined from '@iconify/icons-ant-design/dingtalk-outlined'; +import uploadOutlined from '@iconify/icons-ant-design/upload-outlined'; +import plusOutlined from '@iconify/icons-ant-design/plus-outlined'; +import deleteOutlined from '@iconify/icons-ant-design/delete-outlined'; +import downloadOutlined from '@iconify/icons-ant-design/download-outlined'; +import comandLine from '@iconify/icons-flat-color-icons/command-line'; +import redisIcon from '@iconify/icons-logos/redis'; +import memoryIcon from '@iconify/icons-la/memory'; +import taobaoIconFill from '@iconify/icons-ri/taobao-fill'; +import alipayIcon from '@iconify/icons-fa-brands/alipay'; +import dingdingFill from '@iconify/icons-ri/dingding-fill'; +import giteeIcon from '@iconify/icons-simple-icons/gitee'; +import macosIcon from '@iconify/icons-simple-icons/macos'; +import githubOAuthIcon from '@iconify/icons-uiw/github'; +import appleIcon from '@iconify/icons-uiw/apple'; +import linuxIcon from '@iconify/icons-uiw/linux'; +import wechatIcon from '@iconify/icons-uiw/linux'; +import firefoxbrowserIcon from '@iconify/icons-simple-icons/firefoxbrowser'; +import operaIcon from '@iconify/icons-uiw/opera'; +import qqIcon from '@iconify/icons-uiw/qq'; +import safariIcon from '@iconify/icons-uiw/safari'; +import ucIcon from '@iconify/icons-arcticons/uc-browser'; +import windowsIcon from '@iconify/icons-uiw/windows'; + +// 顶部菜单 +export const UserOutlined = createIconifyOfflineIcon( + 'ant-design:user-outlined', + userOutlined, +); +// 缓存监控使用 +export const RedisIcon = createIconifyOfflineIcon('logos:redis', redisIcon); +export const CommandLineIcon = createIconifyOfflineIcon( + 'flat-color-icons:command-line', + comandLine, +); +export const MemoryIcon = createIconifyOfflineIcon('la:memory', memoryIcon); + +// 第三方登录相关图标 +export const TaobaoIcon = createIconifyOfflineIcon( + 'ri:taobao-fill', + taobaoIconFill, +); +export const AlipayIcon = createIconifyOfflineIcon( + 'fa-brands:alipay', + alipayIcon, +); +export const DingdingIcon = createIconifyOfflineIcon( + 'ri:dingding-fill', + dingdingFill, +); +export const GiteeIcon = createIconifyOfflineIcon( + 'simple-icons:gitee', + giteeIcon, +); +export const GithubOAuthIcon = createIconifyOfflineIcon( + 'uiw:github', + githubOAuthIcon, +); +// 系统相关 +export const AndroidIcon = createIconifyOfflineIcon( + 'ant-design:android-outlined', + androidOutlined, +); +export const BaiduIcon = createIconifyOfflineIcon( + 'ant-design:baidu-outlined', + baiduOutlined, +); +export const ChromeIcon = createIconifyOfflineIcon( + 'ant-design:chrome-outlined', + chromeOutlined, +); +export const DefaultBrowserIcon = createIconifyOfflineIcon( + 'ant-design:ie-outlined', + ieOutlined, + ); +export const DefaultOsIcon = createIconifyOfflineIcon( + 'ant-design:windows-outlined', + windowsOutlined, +); +export const DingtalkIcon = createIconifyOfflineIcon( + 'ant-design:dingtalk-outlined', + dingtalkOutlined, +); +export const EdgeIcon = createIconifyOfflineIcon( + 'ant-design:ie-outlined', + ieOutlined, +); +export const FirefoxIcon = createIconifyOfflineIcon( + 'simple-icons:firefoxbrowser', + firefoxbrowserIcon, +); +export const IPhoneIcon = createIconifyOfflineIcon( + 'uiw:apple', + appleIcon, +); +export const LinuxIcon = createIconifyOfflineIcon( + 'uiw:linux', + linuxIcon, +); +export const MicromessengerIcon = createIconifyOfflineIcon( + 'uiw:weixin', + wechatIcon, + ); +export const OperaIcon = createIconifyOfflineIcon( + 'uiw:opera', + operaIcon, +); +export const OSXIcon = createIconifyOfflineIcon( + 'simple-icons:macos', + macosIcon, +); +export const QQIcon = createIconifyOfflineIcon( + 'uiw:qq', + qqIcon, +); + +export const SafariIcon = createIconifyOfflineIcon( + 'uiw:safari', + safariIcon, +); +export const UcIcon = createIconifyOfflineIcon( + 'arcticons:uc-browser', + ucIcon, +); +export const WindowsIcon = createIconifyOfflineIcon( + 'uiw:windows', + windowsIcon, +); +export const UploadOutlined = createIconifyOfflineIcon( + 'ant-design:upload-outlined', + uploadOutlined, +); +export const PlusOutlined = createIconifyOfflineIcon( + 'ant-design:plus-outlined', + plusOutlined, +); +export const DeleteOutlined = createIconifyOfflineIcon( + 'ant-design:delete-outlined', + deleteOutlined, +); +export const DownloadOutlined = createIconifyOfflineIcon( + 'ant-design:download-outlined', + downloadOutlined, +); diff --git a/admin-ui/vue/packages/icons/src/iconify/index.ts b/admin-ui/vue/packages/icons/src/iconify/index.ts new file mode 100644 index 0000000..e5aa9b0 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/iconify/index.ts @@ -0,0 +1,26 @@ +import { createIconifyIcon } from '@vben-core/icons'; + +export * from '@vben-core/icons'; + +export const MdiKeyboardEsc = createIconifyIcon('mdi:keyboard-esc'); + +export const MdiWechat = createIconifyIcon('mdi:wechat'); + +export const MdiGithub = createIconifyIcon('mdi:github'); + +export const MdiGoogle = createIconifyIcon('mdi:google'); + +export const MdiQqchat = createIconifyIcon('mdi:qqchat'); + +// 系统管理使用 +export const MdiPlus = createIconifyIcon('mdi:plus'); + +export const MdiEdit = createIconifyIcon('mdi:pencil'); + +export const MdiExport = createIconifyIcon('mdi:export'); + +export const MdiImport = createIconifyIcon('mdi:import'); + +export const MdiDelete = createIconifyIcon('mdi:delete'); + +export const SyncOutlined = createIconifyIcon('ant-design:sync-outlined'); diff --git a/admin-ui/vue/packages/icons/src/icons/empty-icon.vue b/admin-ui/vue/packages/icons/src/icons/empty-icon.vue new file mode 100644 index 0000000..444a765 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/icons/empty-icon.vue @@ -0,0 +1,27 @@ + diff --git a/admin-ui/vue/packages/icons/src/index.ts b/admin-ui/vue/packages/icons/src/index.ts new file mode 100644 index 0000000..b224144 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/index.ts @@ -0,0 +1,4 @@ +export * from './iconify'; +export { default as EmptyIcon } from './icons/empty-icon.vue'; +export * from './svg'; +export * from './iconify-offline/index.js'; \ No newline at end of file diff --git a/admin-ui/vue/packages/icons/src/svg/icons/antdv-logo.svg b/admin-ui/vue/packages/icons/src/svg/icons/antdv-logo.svg new file mode 100644 index 0000000..dbfcee7 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/antdv-logo.svg @@ -0,0 +1,29 @@ + + + + Vue + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/admin-ui/vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg b/admin-ui/vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg new file mode 100644 index 0000000..80fd6d3 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/admin-ui/vue/packages/icons/src/svg/icons/avatar-1.svg b/admin-ui/vue/packages/icons/src/svg/icons/avatar-1.svg new file mode 100644 index 0000000..b05970d --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/avatar-1.svg @@ -0,0 +1 @@ +Asset 15 diff --git a/admin-ui/vue/packages/icons/src/svg/icons/avatar-2.svg b/admin-ui/vue/packages/icons/src/svg/icons/avatar-2.svg new file mode 100644 index 0000000..8e17b0b --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/avatar-2.svg @@ -0,0 +1 @@ +Asset 16 diff --git a/admin-ui/vue/packages/icons/src/svg/icons/avatar-3.svg b/admin-ui/vue/packages/icons/src/svg/icons/avatar-3.svg new file mode 100644 index 0000000..ca79178 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/avatar-3.svg @@ -0,0 +1 @@ +Asset 17 diff --git a/admin-ui/vue/packages/icons/src/svg/icons/avatar-4.svg b/admin-ui/vue/packages/icons/src/svg/icons/avatar-4.svg new file mode 100644 index 0000000..d9138df --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/avatar-4.svg @@ -0,0 +1 @@ +Asset 120 diff --git a/admin-ui/vue/packages/icons/src/svg/icons/bell.svg b/admin-ui/vue/packages/icons/src/svg/icons/bell.svg new file mode 100644 index 0000000..90c34e1 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/bell.svg @@ -0,0 +1 @@ +Asset 510 diff --git a/admin-ui/vue/packages/icons/src/svg/icons/cake.svg b/admin-ui/vue/packages/icons/src/svg/icons/cake.svg new file mode 100644 index 0000000..43901fb --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/cake.svg @@ -0,0 +1 @@ +Asset 480% diff --git a/admin-ui/vue/packages/icons/src/svg/icons/card.svg b/admin-ui/vue/packages/icons/src/svg/icons/card.svg new file mode 100644 index 0000000..40ff3e3 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/card.svg @@ -0,0 +1 @@ + diff --git a/admin-ui/vue/packages/icons/src/svg/icons/download.svg b/admin-ui/vue/packages/icons/src/svg/icons/download.svg new file mode 100644 index 0000000..af9ff15 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/icons/download.svg @@ -0,0 +1 @@ + diff --git a/admin-ui/vue/packages/icons/src/svg/index.ts b/admin-ui/vue/packages/icons/src/svg/index.ts new file mode 100644 index 0000000..9573ef7 --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/index.ts @@ -0,0 +1,27 @@ +import { createIconifyIcon } from '@vben-core/icons'; + +import './load.js'; + +const SvgAvatar1Icon = createIconifyIcon('svg:avatar-1'); +const SvgAvatar2Icon = createIconifyIcon('svg:avatar-2'); +const SvgAvatar3Icon = createIconifyIcon('svg:avatar-3'); +const SvgAvatar4Icon = createIconifyIcon('svg:avatar-4'); +const SvgDownloadIcon = createIconifyIcon('svg:download'); +const SvgCardIcon = createIconifyIcon('svg:card'); +const SvgBellIcon = createIconifyIcon('svg:bell'); +const SvgCakeIcon = createIconifyIcon('svg:cake'); +const SvgAntdvLogoIcon = createIconifyIcon('svg:antdv-logo'); +const SvgQuarkBrowserIcon = createIconifyIcon('svg:arcticons--quark-browser'); + +export { + SvgAntdvLogoIcon, + SvgAvatar1Icon, + SvgAvatar2Icon, + SvgAvatar3Icon, + SvgAvatar4Icon, + SvgBellIcon, + SvgCakeIcon, + SvgCardIcon, + SvgDownloadIcon, + SvgQuarkBrowserIcon, +}; diff --git a/admin-ui/vue/packages/icons/src/svg/load.ts b/admin-ui/vue/packages/icons/src/svg/load.ts new file mode 100644 index 0000000..59098bd --- /dev/null +++ b/admin-ui/vue/packages/icons/src/svg/load.ts @@ -0,0 +1,79 @@ +import type { IconifyIconStructure } from '@vben-core/icons'; + +import { addIcon } from '@vben-core/icons'; + +let loaded = false; +if (!loaded) { + loadSvgIcons(); + loaded = true; +} + +function parseSvg(svgData: string): IconifyIconStructure { + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(svgData, 'image/svg+xml'); + const svgElement = xmlDoc.documentElement; + + // 提取 SVG 根元素的关键样式属性 + const getAttrs = (el: Element, attrs: string[]) => + attrs + .map((attr) => + el.hasAttribute(attr) ? `${attr}="${el.getAttribute(attr)}"` : '', + ) + .filter(Boolean) + .join(' '); + + const rootAttrs = getAttrs(svgElement, [ + 'fill', + 'stroke', + 'fill-rule', + 'stroke-width', + ]); + + const svgContent = [...svgElement.childNodes] + .filter((node) => node.nodeType === Node.ELEMENT_NODE) + .map((node) => new XMLSerializer().serializeToString(node)) + .join(''); + // 若根有属性,用一个 g 标签包裹内容并继承属性 + const body = rootAttrs ? `${svgContent}` : svgContent; + + const viewBoxValue = svgElement.getAttribute('viewBox') || ''; + const [left, top, width, height] = viewBoxValue.split(' ').map((val) => { + const num = Number(val); + return Number.isNaN(num) ? undefined : num; + }); + + return { + body, + height, + left, + top, + width, + }; +} + +/** + * 自定义的svg图片转化为组件 + * @example ./svg/avatar.svg + * + */ +async function loadSvgIcons() { + const svgEagers = import.meta.glob('./icons/**', { + eager: true, + query: '?raw', + }); + + await Promise.all( + Object.entries(svgEagers).map((svg) => { + const [key, body] = svg as [string, string | { default: string }]; + + // ./icons/xxxx.svg => xxxxxx + const start = key.lastIndexOf('/') + 1; + const end = key.lastIndexOf('.'); + const iconName = key.slice(start, end); + + return addIcon(`svg:${iconName}`, { + ...parseSvg(typeof body === 'object' ? body.default : body), + }); + }), + ); +} diff --git a/admin-ui/vue/packages/icons/tsconfig.json b/admin-ui/vue/packages/icons/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/icons/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/locales/package.json b/admin-ui/vue/packages/locales/package.json new file mode 100644 index 0000000..7d47915 --- /dev/null +++ b/admin-ui/vue/packages/locales/package.json @@ -0,0 +1,28 @@ +{ + "name": "@vben/locales", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/locales" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@intlify/core-base": "catalog:", + "@vben-core/composables": "workspace:*", + "vue": "catalog:", + "vue-i18n": "catalog:" + } +} diff --git a/admin-ui/vue/packages/locales/src/i18n.ts b/admin-ui/vue/packages/locales/src/i18n.ts new file mode 100644 index 0000000..e3c75bd --- /dev/null +++ b/admin-ui/vue/packages/locales/src/i18n.ts @@ -0,0 +1,147 @@ +import type { App } from 'vue'; +import type { Locale } from 'vue-i18n'; + +import type { + ImportLocaleFn, + LoadMessageFn, + LocaleSetupOptions, + SupportedLanguagesType, +} from './typing'; + +import { unref } from 'vue'; +import { createI18n } from 'vue-i18n'; + +import { useSimpleLocale } from '@vben-core/composables'; + +const i18n = createI18n({ + globalInjection: true, + legacy: false, + locale: '', + messages: {}, +}); + +const modules = import.meta.glob('./langs/**/*.json'); + +const { setSimpleLocale } = useSimpleLocale(); + +const localesMap = loadLocalesMapFromDir( + /\.\/langs\/([^/]+)\/(.*)\.json$/, + modules, +); +let loadMessages: LoadMessageFn; + +/** + * Load locale modules + * @param modules + */ +function loadLocalesMap(modules: Record Promise>) { + const localesMap: Record = {}; + + for (const [path, loadLocale] of Object.entries(modules)) { + const key = path.match(/([\w-]*)\.(json)/)?.[1]; + if (key) { + localesMap[key] = loadLocale as ImportLocaleFn; + } + } + return localesMap; +} + +/** + * Load locale modules with directory structure + * @param regexp - Regular expression to match language and file names + * @param modules - The modules object containing paths and import functions + * @returns A map of locales to their corresponding import functions + */ +function loadLocalesMapFromDir( + regexp: RegExp, + modules: Record Promise>, +): Record { + const localesRaw: Record Promise>> = {}; + const localesMap: Record = {}; + + // Iterate over the modules to extract language and file names + for (const path in modules) { + const match = path.match(regexp); + if (match) { + const [_, locale, fileName] = match; + if (locale && fileName) { + if (!localesRaw[locale]) { + localesRaw[locale] = {}; + } + if (modules[path]) { + localesRaw[locale][fileName] = modules[path]; + } + } + } + } + + // Convert raw locale data into async import functions + for (const [locale, files] of Object.entries(localesRaw)) { + localesMap[locale] = async () => { + const messages: Record = {}; + for (const [fileName, importFn] of Object.entries(files)) { + messages[fileName] = ((await importFn()) as any)?.default; + } + return { default: messages }; + }; + } + + return localesMap; +} + +/** + * Set i18n language + * @param locale + */ +function setI18nLanguage(locale: Locale) { + i18n.global.locale.value = locale; + + document?.querySelector('html')?.setAttribute('lang', locale); +} + +async function setupI18n(app: App, options: LocaleSetupOptions = {}) { + const { defaultLocale = 'zh-CN' } = options; + // app可以自行扩展一些第三方库和组件库的国际化 + loadMessages = options.loadMessages || (async () => ({})); + app.use(i18n); + await loadLocaleMessages(defaultLocale); + + // 在控制台打印警告 + i18n.global.setMissingHandler((locale, key) => { + if (options.missingWarn && key.includes('.')) { + console.warn( + `[intlify] Not found '${key}' key in '${locale}' locale messages.`, + ); + } + }); +} + +/** + * Load locale messages + * @param lang + */ +async function loadLocaleMessages(lang: SupportedLanguagesType) { + if (unref(i18n.global.locale) === lang) { + return setI18nLanguage(lang); + } + setSimpleLocale(lang); + + const message = await localesMap[lang]?.(); + + if (message?.default) { + i18n.global.setLocaleMessage(lang, message.default); + } + + const mergeMessage = await loadMessages(lang); + i18n.global.mergeLocaleMessage(lang, mergeMessage); + + return setI18nLanguage(lang); +} + +export { + i18n, + loadLocaleMessages, + loadLocalesMap, + loadLocalesMapFromDir, + setupI18n, +}; diff --git a/admin-ui/vue/packages/locales/src/index.ts b/admin-ui/vue/packages/locales/src/index.ts new file mode 100644 index 0000000..d4bfd81 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/index.ts @@ -0,0 +1,30 @@ +import { + i18n, + loadLocaleMessages, + loadLocalesMap, + loadLocalesMapFromDir, + setupI18n, +} from './i18n'; + +const $t = i18n.global.t; +const $te = i18n.global.te; + +export { + $t, + $te, + i18n, + loadLocaleMessages, + loadLocalesMap, + loadLocalesMapFromDir, + setupI18n, +}; +export { + type ImportLocaleFn, + type LocaleSetupOptions, + type SupportedLanguagesType, +} from './typing'; +export type { CompileError } from '@intlify/core-base'; + +export { useI18n } from 'vue-i18n'; + +export type { Locale } from 'vue-i18n'; diff --git a/admin-ui/vue/packages/locales/src/langs/en-US/authentication.json b/admin-ui/vue/packages/locales/src/langs/en-US/authentication.json new file mode 100644 index 0000000..7dd3462 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/en-US/authentication.json @@ -0,0 +1,65 @@ +{ + "welcomeBack": "Welcome Back", + "pageTitle": "Plug-and-play Admin system", + "pageDesc": "Efficient, versatile frontend template", + "loginSuccess": "Login Successful", + "loginSuccessDesc": "Welcome Back", + "loginSubtitle": "Enter your account details to manage your projects", + "selectAccount": "Quick Select Account", + "username": "Username", + "password": "Password", + "usernameTip": "Please enter username", + "passwordErrorTip": "Password is incorrect", + "passwordTip": "Please enter password", + "verifyRequiredTip": "Please complete the verification first", + "rememberMe": "Remember Me", + "createAnAccount": "Create an Account", + "createAccount": "Create Account", + "alreadyHaveAccount": "Already have an account?", + "accountTip": "Don't have an account?", + "signUp": "Sign Up", + "signUpSubtitle": "Make managing your applications simple and fun", + "confirmPassword": "Confirm Password", + "confirmPasswordTip": "The passwords do not match", + "agree": "I agree to", + "privacyPolicy": "Privacy-policy", + "terms": "Terms", + "agreeTip": "Please agree to the Privacy Policy and Terms", + "goToLogin": "Login instead", + "passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols", + "forgetPassword": "Forget Password?", + "forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password", + "emailTip": "Please enter email", + "emailValidErrorTip": "The email format you entered is incorrect", + "sendResetLink": "Send Reset Link", + "email": "Email", + "qrcodeSubtitle": "Scan the QR code with your phone to login", + "qrcodePrompt": "Click 'Confirm' after scanning to complete login", + "qrcodeLogin": "QR Code Login", + "wechatLogin": "Wechat Login", + "qqLogin": "QQ Login", + "githubLogin": "Github Login", + "googleLogin": "Google Login", + "dingdingLogin": "Dingding Login", + "codeSubtitle": "Enter your phone number to start managing your project", + "code": "Security code", + "codeTip": "Security code required {0} characters", + "mobile": "Mobile", + "mobileLogin": "Mobile Login", + "mobileTip": "Please enter mobile number", + "mobileErrortip": "The phone number format is incorrect", + "sendCode": "Get Security code", + "sendText": "Resend in {0}s", + "thirdPartyLogin": "Or continue with", + "weChat": "WeChat", + "qq": "QQ", + "gitHub": "GitHub", + "google": "Google", + "loginAgainTitle": "Please Log In Again", + "loginAgainSubTitle": "Your login session has expired. Please log in again to continue.", + "layout": { + "center": "Align Center", + "alignLeft": "Align Left", + "alignRight": "Align Right" + } +} diff --git a/admin-ui/vue/packages/locales/src/langs/en-US/common.json b/admin-ui/vue/packages/locales/src/langs/en-US/common.json new file mode 100644 index 0000000..08c20f7 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/en-US/common.json @@ -0,0 +1,24 @@ +{ + "back": "Back", + "backToHome": "Back To Home", + "login": "Login", + "logout": "Logout", + "prompt": "Prompt", + "cancel": "Cancel", + "confirm": "Confirm", + "reset": "Reset", + "noData": "No Data", + "refresh": "Refresh", + "loadingMenu": "Loading Menu", + "query": "Search", + "search": "Search", + "enabled": "Enabled", + "disabled": "Disabled", + "edit": "Edit", + "delete": "Delete", + "create": "Create", + "yes": "Yes", + "no": "No", + "showSearchPanel": "Show search panel", + "hideSearchPanel": "Hide search panel" +} diff --git a/admin-ui/vue/packages/locales/src/langs/en-US/preferences.json b/admin-ui/vue/packages/locales/src/langs/en-US/preferences.json new file mode 100644 index 0000000..977632a --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/en-US/preferences.json @@ -0,0 +1,194 @@ +{ + "title": "Preferences", + "subtitle": "Customize Preferences & Preview in Real Time", + "enableStickyPreferencesNavigationBar": "Enable sticky preferences navigation bar", + "disableStickyPreferencesNavigationBar": "Disable sticky preferences navigation bar", + "resetTip": "Data has changed, click to reset", + "resetTitle": "Reset Preferences", + "resetSuccess": "Preferences reset successfully", + "appearance": "Appearance", + "layout": "Layout", + "content": "Content", + "other": "Other", + "wide": "Wide", + "compact": "Fixed", + "followSystem": "Follow System", + "vertical": "Vertical", + "verticalTip": "Side vertical menu mode", + "horizontal": "Horizontal", + "horizontalTip": "Horizontal menu mode, all menus displayed at the top", + "twoColumn": "Two Column", + "twoColumnTip": "Vertical Two Column Menu Mode", + "headerSidebarNav": "Header Vertical", + "headerSidebarNavTip": "Header Full Width, Sidebar Navigation Mode", + "headerTwoColumn": "Header Two Column", + "headerTwoColumnTip": "Header Navigation & Sidebar Two Column co-exists", + "mixedMenu": "Mixed Menu", + "mixedMenuTip": "Vertical & Horizontal Menu Co-exists", + "fullContent": "Full Content", + "fullContentTip": "Only display content body, hide all menus", + "normal": "Normal", + "plain": "Plain", + "rounded": "Rounded", + "copyPreferences": "Copy Preferences", + "copyPreferencesSuccessTitle": "Copy successful", + "copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app", + "clearAndLogout": "Clear Cache & Logout", + "mode": "Mode", + "general": "General", + "language": "Language", + "dynamicTitle": "Dynamic Title", + "watermark": "Watermark", + "watermarkContent": "Please input Watermark content", + "checkUpdates": "Periodic update check", + "position": { + "title": "Preferences Postion", + "header": "Header", + "auto": "Auto", + "fixed": "Fixed" + }, + "sidebar": { + "buttons": "Show Buttons", + "buttonFixed": "Fixed", + "buttonCollapsed": "Collapsed", + "title": "Sidebar", + "width": "Width", + "visible": "Show Sidebar", + "collapsed": "Collpase Menu", + "collapsedShowTitle": "Show Menu Title", + "autoActivateChild": "Auto Activate SubMenu", + "autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.", + "expandOnHover": "Expand On Hover", + "expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar." + }, + "tabbar": { + "title": "Tabbar", + "enable": "Enable Tab Bar", + "icon": "Show Tabbar Icon", + "showMore": "Show More Button", + "showMaximize": "Show Maximize Button", + "persist": "Persist Tabs", + "maxCount": "Max Count of Tabs", + "maxCountTip": "When the number of tabs exceeds the maximum,\nthe oldest tab will be closed.\n Set to 0 to disable count checking.", + "draggable": "Enable Draggable Sort", + "wheelable": "Support Mouse Wheel", + "middleClickClose": "Close Tab when Mouse Middle Button Click", + "wheelableTip": "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.", + "styleType": { + "title": "Tabs Style", + "chrome": "Chrome", + "card": "Card", + "plain": "Plain", + "brisk": "Brisk" + }, + "contextMenu": { + "reload": "Reload", + "close": "Close", + "pin": "Pin", + "unpin": "Unpin", + "closeLeft": "Close Left Tabs", + "closeRight": "Close Right Tabs", + "closeOther": "Close Other Tabs", + "closeAll": "Close All Tabs", + "openInNewWindow": "Open in New Window", + "maximize": "Maximize", + "restoreMaximize": "Restore" + } + }, + "navigationMenu": { + "title": "Navigation Menu", + "style": "Navigation Menu Style", + "accordion": "Sidebar Accordion Menu", + "split": "Navigation Menu Separation", + "splitTip": "When enabled, the sidebar displays the top bar's submenu" + }, + "breadcrumb": { + "title": "Breadcrumb", + "home": "Show Home Button", + "enable": "Enable Breadcrumb", + "icon": "Show Breadcrumb Icon", + "background": "background", + "style": "Breadcrumb Style", + "hideOnlyOne": "Hidden when only one" + }, + "animation": { + "title": "Animation", + "loading": "Page Loading", + "transition": "Page Transition", + "progress": "Page Progress" + }, + "theme": { + "title": "Theme", + "radius": "Radius", + "fontSize": "Font Size", + "fontSizeTip": "Adjust global font size with real-time preview", + "light": "Light", + "dark": "Dark", + "darkSidebar": "Semi Dark Sidebar", + "darkHeader": "Semi Dark Header", + "weakMode": "Weak Mode", + "grayMode": "Gray Mode", + "builtin": { + "title": "Built-in", + "default": "Default", + "violet": "Violet", + "pink": "Pink", + "rose": "Rose", + "skyBlue": "Sky Blue", + "deepBlue": "Deep Blue", + "green": "Green", + "deepGreen": "Deep Green", + "orange": "Orange", + "yellow": "Yellow", + "zinc": "Zinc", + "neutral": "Neutral", + "slate": "Slate", + "gray": "Gray", + "custom": "Custom" + } + }, + "header": { + "title": "Header", + "visible": "Show Header", + "modeStatic": "Static", + "modeFixed": "Fixed", + "modeAuto": "Auto hide & Show", + "modeAutoScroll": "Scroll to Hide & Show", + "menuAlign": "Menu Align", + "menuAlignStart": "Start", + "menuAlignEnd": "End", + "menuAlignCenter": "Center" + }, + "footer": { + "title": "Footer", + "visible": "Show Footer", + "fixed": "Fixed at Bottom" + }, + "copyright": { + "title": "Copyright", + "enable": "Enable Copyright", + "companyName": "Company Name", + "companySiteLink": "Company Site Link", + "date": "Date", + "icp": "ICP License Number", + "icpLink": "ICP Site Link" + }, + "shortcutKeys": { + "title": "Shortcut Keys", + "global": "Global", + "search": "Global Search", + "logout": "Logout", + "preferences": "Preferences" + }, + "widget": { + "title": "Widget", + "globalSearch": "Enable Global Search", + "fullscreen": "Enable Fullscreen", + "themeToggle": "Enable Theme Toggle", + "languageToggle": "Enable Language Toggle", + "notification": "Enable Notification", + "sidebarToggle": "Enable Sidebar Toggle", + "lockScreen": "Enable Lock Screen", + "refresh": "Enable Refresh" + } +} diff --git a/admin-ui/vue/packages/locales/src/langs/en-US/ui.json b/admin-ui/vue/packages/locales/src/langs/en-US/ui.json new file mode 100644 index 0000000..d6a6337 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/en-US/ui.json @@ -0,0 +1,112 @@ +{ + "formRules": { + "required": "Please enter {0}", + "selectRequired": "Please select {0}", + "minLength": "{0} must be at least {1} characters", + "maxLength": "{0} can be at most {1} characters", + "length": "{0} must be {1} characters long", + "alreadyExists": "{0} `{1}` already exists", + "startWith": "{0} must start with `{1}`", + "invalidURL": "Please input a valid URL" + }, + "actionTitle": { + "edit": "Modify {0}", + "create": "Create {0}", + "delete": "Delete {0}", + "view": "View {0}" + }, + "actionMessage": { + "deleteConfirm": "Are you sure to delete {0}?", + "deleting": "Deleting {0} ...", + "deleteSuccess": "{0} deleted successfully", + "operationSuccess": "Operation succeeded", + "operationFailed": "Operation failed" + }, + "placeholder": { + "input": "Please enter", + "select": "Please select" + }, + "captcha": { + "title": "Please complete the security verification", + "sliderSuccessText": "Passed", + "sliderDefaultText": "Slider and drag", + "alt": "Supports img tag src attribute value", + "sliderRotateDefaultTip": "Click picture to refresh", + "sliderTranslateDefaultTip": "Click picture to refresh", + "sliderRotateFailTip": "Validation failed", + "sliderRotateSuccessTip": "Validation successful, time {0} seconds", + "sliderTranslateFailTip": "Validation failed", + "sliderTranslateSuccessTip": "Validation successful, time {0} seconds", + "refreshAriaLabel": "Refresh captcha", + "confirmAriaLabel": "Confirm selection", + "confirm": "Confirm", + "pointAriaLabel": "Click point", + "clickInOrder": "Please click in order" + }, + "iconPicker": { + "placeholder": "Select an icon", + "search": "Search icon..." + }, + "jsonViewer": { + "copy": "Copy", + "copied": "Copied" + }, + "fallback": { + "pageNotFound": "Oops! Page Not Found", + "pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.", + "forbidden": "Oops! Access Denied", + "forbiddenDesc": "Sorry, but you don't have permission to access this page.", + "internalError": "Oops! Something Went Wrong", + "internalErrorDesc": "Sorry, but the server encountered an error.", + "offline": "Offline Page", + "offlineError": "Oops! Network Error", + "offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.", + "comingSoon": "Coming Soon", + "http": { + "requestTimeout": "The request timed out. Please try again later.", + "networkError": "A network error occurred. Please check your internet connection and try again.", + "badRequest": "Bad Request. Please check your input and try again.", + "unauthorized": "Unauthorized. Please log in to continue.", + "forbidden": "Forbidden. You do not have permission to access this resource.", + "notFound": "Not Found. The requested resource could not be found.", + "payloadTooLarge": "The uploaded file is too large. Please reduce the file size or adjust the upload limit.", + "internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later." + } + }, + "widgets": { + "document": "Document", + "qa": "Q&A", + "setting": "Settings", + "logoutTip": "Do you want to logout?", + "viewAll": "View All Messages", + "notifications": "Notifications", + "markAllAsRead": "Make All as Read", + "clearNotifications": "Clear", + "checkUpdatesTitle": "New Version Available", + "checkUpdatesDescription": "Click to refresh and get the latest version", + "search": { + "title": "Search", + "searchNavigate": "Search Navigation", + "select": "Select", + "navigate": "Navigate", + "close": "Close", + "noResults": "No Search Results Found", + "noRecent": "No Search History", + "recent": "Search History" + }, + "lockScreen": { + "title": "Lock Screen", + "screenButton": "Locking", + "password": "Password", + "placeholder": "Please enter password", + "unlock": "Click to unlock", + "errorPasswordTip": "Password error, please re-enter", + "backToLogin": "Back to login", + "entry": "Enter the system" + }, + "timezone": { + "setTimezone": "Set Timezone", + "setSuccess": "Timezone set successfully" + } + } +} diff --git a/admin-ui/vue/packages/locales/src/langs/zh-CN/authentication.json b/admin-ui/vue/packages/locales/src/langs/zh-CN/authentication.json new file mode 100644 index 0000000..ade52ac --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/zh-CN/authentication.json @@ -0,0 +1,65 @@ +{ + "welcomeBack": "欢迎回来", + "pageTitle": "开箱即用的大型中后台管理系统", + "pageDesc": "工程化、高性能、跨组件库的前端模版", + "loginSuccess": "登录成功", + "loginSuccessDesc": "欢迎回来", + "loginSubtitle": "请输入您的帐户信息以开始管理您的项目", + "selectAccount": "快速选择账号", + "username": "账号", + "password": "密码", + "usernameTip": "请输入用户名", + "passwordTip": "请输入密码", + "verifyRequiredTip": "请先完成验证", + "passwordErrorTip": "密码错误", + "rememberMe": "记住账号", + "createAnAccount": "创建一个账号", + "createAccount": "创建账号", + "alreadyHaveAccount": "已经有账号了?", + "accountTip": "还没有账号?", + "signUp": "注册", + "signUpSubtitle": "让您的应用程序管理变得简单而有趣", + "confirmPassword": "确认密码", + "confirmPasswordTip": "两次输入的密码不一致", + "agree": "我同意", + "privacyPolicy": "隐私政策", + "terms": "条款", + "agreeTip": "请同意隐私政策和条款", + "goToLogin": "去登录", + "passwordStrength": "使用 8 个或更多字符,混合字母、数字和符号", + "forgetPassword": "忘记密码?", + "forgetPasswordSubtitle": "输入您的电子邮件,我们将向您发送重置密码的连接", + "emailTip": "请输入邮箱", + "emailValidErrorTip": "你输入的邮箱格式不正确", + "sendResetLink": "发送重置链接", + "email": "邮箱", + "qrcodeSubtitle": "请用手机扫描二维码登录", + "qrcodePrompt": "扫码后点击 '确认',即可完成登录", + "qrcodeLogin": "扫码登录", + "wechatLogin": "微信登录", + "qqLogin": "QQ登录", + "githubLogin": "Github登录", + "googleLogin": "Google登录", + "dingdingLogin": "钉钉登录", + "codeSubtitle": "请输入您的手机号码以开始管理您的项目", + "code": "验证码", + "codeTip": "请输入{0}位验证码", + "mobile": "手机号码", + "mobileTip": "请输入手机号", + "mobileErrortip": "手机号码格式错误", + "mobileLogin": "手机号登录", + "sendCode": "获取验证码", + "sendText": "{0}秒后重新获取", + "thirdPartyLogin": "其他登录方式", + "weChat": "微信", + "qq": "QQ", + "gitHub": "GitHub", + "google": "Google", + "loginAgainTitle": "重新登录", + "loginAgainSubTitle": "您的登录状态已过期,请重新登录以继续。", + "layout": { + "center": "居中", + "alignLeft": "居左", + "alignRight": "居右" + } +} diff --git a/admin-ui/vue/packages/locales/src/langs/zh-CN/common.json b/admin-ui/vue/packages/locales/src/langs/zh-CN/common.json new file mode 100644 index 0000000..6b3cad5 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/zh-CN/common.json @@ -0,0 +1,24 @@ +{ + "back": "返回", + "backToHome": "返回首页", + "login": "登录", + "logout": "退出登录", + "prompt": "提示", + "cancel": "取消", + "confirm": "确认", + "reset": "重置", + "noData": "暂无数据", + "refresh": "刷新", + "loadingMenu": "加载菜单中", + "query": "查询", + "search": "搜索", + "enabled": "已启用", + "disabled": "已禁用", + "edit": "修改", + "delete": "删除", + "create": "新增", + "yes": "是", + "no": "否", + "showSearchPanel": "显示搜索面板", + "hideSearchPanel": "隐藏搜索面板" +} diff --git a/admin-ui/vue/packages/locales/src/langs/zh-CN/preferences.json b/admin-ui/vue/packages/locales/src/langs/zh-CN/preferences.json new file mode 100644 index 0000000..f8e390f --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/zh-CN/preferences.json @@ -0,0 +1,194 @@ +{ + "title": "偏好设置", + "subtitle": "自定义偏好设置 & 实时预览", + "enableStickyPreferencesNavigationBar": "开启首选项导航栏吸顶效果", + "disableStickyPreferencesNavigationBar": "关闭首选项导航栏吸顶效果", + "resetTitle": "重置偏好设置", + "resetTip": "数据有变化,点击可进行重置", + "resetSuccess": "重置偏好设置成功", + "appearance": "外观", + "layout": "布局", + "content": "内容", + "other": "其它", + "wide": "流式", + "compact": "定宽", + "followSystem": "跟随系统", + "vertical": "垂直", + "verticalTip": "侧边垂直菜单模式", + "horizontal": "水平", + "horizontalTip": "水平菜单模式,菜单全部显示在顶部", + "twoColumn": "双列菜单", + "twoColumnTip": "垂直双列菜单模式", + "headerSidebarNav": "侧边导航", + "headerSidebarNavTip": "顶部通栏,侧边导航模式", + "headerTwoColumn": "混合双列", + "headerTwoColumnTip": "双列、水平菜单共存模式", + "mixedMenu": "混合垂直", + "mixedMenuTip": "垂直水平菜单共存", + "fullContent": "内容全屏", + "fullContentTip": "不显示任何菜单,只显示内容主体", + "normal": "常规", + "plain": "朴素", + "rounded": "圆润", + "copyPreferences": "复制偏好设置", + "copyPreferencesSuccessTitle": "复制成功", + "copyPreferencesSuccess": "复制成功,请在 app 下的 `src/preferences.ts`内进行覆盖", + "clearAndLogout": "清空缓存 & 退出登录", + "mode": "模式", + "general": "通用", + "language": "语言", + "dynamicTitle": "动态标题", + "watermark": "水印", + "watermarkContent": "请输入水印文案", + "checkUpdates": "定时检查更新", + "position": { + "title": "偏好设置位置", + "header": "顶栏", + "auto": "自动", + "fixed": "固定" + }, + "sidebar": { + "buttons": "显示按钮", + "buttonFixed": "固定按钮", + "buttonCollapsed": "折叠按钮", + "title": "侧边栏", + "width": "宽度", + "visible": "显示侧边栏", + "collapsed": "折叠菜单", + "collapsedShowTitle": "折叠显示菜单名", + "autoActivateChild": "自动激活子菜单", + "autoActivateChildTip": "点击顶层菜单时,自动激活第一个子菜单或者上一次激活的子菜单", + "expandOnHover": "鼠标悬停展开", + "expandOnHoverTip": "鼠标在折叠区域悬浮时,`启用`则展开当前子菜单,`禁用`则展开整个侧边栏" + }, + "tabbar": { + "title": "标签栏", + "enable": "启用标签栏", + "icon": "显示标签栏图标", + "showMore": "显示更多按钮", + "showMaximize": "显示最大化按钮", + "persist": "持久化标签页", + "maxCount": "最大标签数", + "maxCountTip": "每次打开新的标签时如果超过最大标签数,\n会自动关闭一个最先打开的标签\n设置为 0 则不限制", + "draggable": "启动拖拽排序", + "wheelable": "启用纵向滚轮响应", + "middleClickClose": "点击鼠标中键关闭标签页", + "wheelableTip": "开启后,标签栏区域可以响应滚轮的纵向滚动事件。\n关闭时,只能响应系统的横向滚动事件(需要按下Shift再滚动滚轮)", + "styleType": { + "title": "标签页风格", + "chrome": "谷歌", + "card": "卡片", + "plain": "朴素", + "brisk": "轻快" + }, + "contextMenu": { + "reload": "重新加载", + "close": "关闭", + "pin": "固定", + "unpin": "取消固定", + "closeLeft": "关闭左侧标签页", + "closeRight": "关闭右侧标签页", + "closeOther": "关闭其它标签页", + "closeAll": "关闭全部标签页", + "openInNewWindow": "在新窗口打开", + "maximize": "最大化", + "restoreMaximize": "还原" + } + }, + "navigationMenu": { + "title": "导航菜单", + "style": "导航菜单风格", + "accordion": "侧边导航菜单手风琴模式", + "split": "导航菜单分离", + "splitTip": "开启时,侧边栏显示顶栏对应菜单的子菜单" + }, + "breadcrumb": { + "title": "面包屑导航", + "enable": "开启面包屑导航", + "icon": "显示面包屑图标", + "home": "显示首页按钮", + "style": "面包屑风格", + "hideOnlyOne": "仅有一个时隐藏", + "background": "背景" + }, + "animation": { + "title": "动画", + "loading": "页面切换 Loading", + "transition": "页面切换动画", + "progress": "页面切换进度条" + }, + "theme": { + "title": "主题", + "radius": "圆角", + "fontSize": "字体大小", + "fontSizeTip": "调整全局字体大小,实时预览效果", + "light": "浅色", + "dark": "深色", + "darkSidebar": "深色侧边栏", + "darkHeader": "深色顶栏", + "weakMode": "色弱模式", + "grayMode": "灰色模式", + "builtin": { + "title": "内置主题", + "default": "默认", + "violet": "紫罗兰", + "pink": "樱花粉", + "rose": "玫瑰红", + "skyBlue": "天蓝色", + "deepBlue": "深蓝色", + "green": "浅绿色", + "deepGreen": "深绿色", + "orange": "橙黄色", + "yellow": "柠檬黄", + "zinc": "锌色灰", + "neutral": "中性色", + "slate": "石板灰", + "gray": "中灰色", + "custom": "自定义" + } + }, + "header": { + "title": "顶栏", + "modeStatic": "静止", + "modeFixed": "固定", + "modeAuto": "自动隐藏和显示", + "modeAutoScroll": "滚动隐藏和显示", + "visible": "显示顶栏", + "menuAlign": "菜单位置", + "menuAlignStart": "左侧", + "menuAlignEnd": "右侧", + "menuAlignCenter": "居中" + }, + "footer": { + "title": "底栏", + "visible": "显示底栏", + "fixed": "固定在底部" + }, + "copyright": { + "title": "版权", + "enable": "启用版权", + "companyName": "公司名", + "companySiteLink": "公司主页", + "date": "日期", + "icp": "ICP 备案号", + "icpLink": "ICP 网站链接" + }, + "shortcutKeys": { + "title": "快捷键", + "global": "全局", + "search": "全局搜索", + "logout": "退出登录", + "preferences": "偏好设置" + }, + "widget": { + "title": "小部件", + "globalSearch": "启用全局搜索", + "fullscreen": "启用全屏", + "themeToggle": "启用主题切换", + "languageToggle": "启用语言切换", + "notification": "启用通知", + "sidebarToggle": "启用侧边栏切换", + "lockScreen": "启用锁屏", + "refresh": "启用刷新" + } +} diff --git a/admin-ui/vue/packages/locales/src/langs/zh-CN/ui.json b/admin-ui/vue/packages/locales/src/langs/zh-CN/ui.json new file mode 100644 index 0000000..ef9d101 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/langs/zh-CN/ui.json @@ -0,0 +1,112 @@ +{ + "formRules": { + "required": "请输入{0}", + "selectRequired": "请选择{0}", + "minLength": "{0}至少{1}个字符", + "maxLength": "{0}最多{1}个字符", + "length": "{0}长度必须为{1}个字符", + "alreadyExists": "{0} `{1}` 已存在", + "startWith": "{0}必须以 {1} 开头", + "invalidURL": "请输入有效的链接" + }, + "actionTitle": { + "edit": "修改{0}", + "create": "新增{0}", + "delete": "删除{0}", + "view": "查看{0}" + }, + "actionMessage": { + "deleteConfirm": "确定删除 {0} 吗?", + "deleting": "正在删除 {0} ...", + "deleteSuccess": "{0} 删除成功", + "operationSuccess": "操作成功", + "operationFailed": "操作失败" + }, + "placeholder": { + "input": "请输入", + "select": "请选择" + }, + "captcha": { + "title": "请完成安全验证", + "sliderSuccessText": "验证通过", + "sliderDefaultText": "请按住滑块拖动", + "sliderRotateDefaultTip": "点击图片可刷新", + "sliderTranslateDefaultTip": "点击图片可刷新", + "sliderRotateFailTip": "验证失败", + "sliderRotateSuccessTip": "验证成功,耗时{0}秒", + "sliderTranslateFailTip": "验证失败", + "sliderTranslateSuccessTip": "验证成功,耗时{0}秒", + "alt": "支持img标签src属性值", + "refreshAriaLabel": "刷新验证码", + "confirmAriaLabel": "确认选择", + "confirm": "确认", + "pointAriaLabel": "点击点", + "clickInOrder": "请依次点击" + }, + "iconPicker": { + "placeholder": "选择一个图标", + "search": "搜索图标..." + }, + "jsonViewer": { + "copy": "复制", + "copied": "已复制" + }, + "fallback": { + "pageNotFound": "哎呀!未找到页面", + "pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。", + "forbidden": "哎呀!访问被拒绝", + "forbiddenDesc": "抱歉,您没有权限访问此页面。", + "internalError": "哎呀!出错了", + "internalErrorDesc": "抱歉,服务器遇到错误。", + "offline": "离线页面", + "offlineError": "哎呀!网络错误", + "offlineErrorDesc": "抱歉,无法连接到互联网,请检查您的网络连接并重试。", + "comingSoon": "即将推出", + "http": { + "requestTimeout": "请求超时,请稍后再试。", + "networkError": "网络异常,请检查您的网络连接后重试。", + "badRequest": "请求错误。请检查您的输入并重试。", + "unauthorized": "登录认证过期,请重新登录后继续。", + "forbidden": "禁止访问, 您没有权限访问此资源。", + "notFound": "未找到, 请求的资源不存在。", + "payloadTooLarge": "上传文件过大,请减小文件或调整上传限制。", + "internalServerError": "内部服务器错误,请稍后再试。" + } + }, + "widgets": { + "document": "文档", + "qa": "问题 & 帮助", + "setting": "设置", + "logoutTip": "是否退出登录?", + "viewAll": "查看所有消息", + "notifications": "通知", + "markAllAsRead": "全部标记为已读", + "clearNotifications": "清空", + "checkUpdatesTitle": "新版本可用", + "checkUpdatesDescription": "点击刷新以获取最新版本", + "search": { + "title": "搜索", + "searchNavigate": "搜索导航菜单", + "select": "选择", + "navigate": "导航", + "close": "关闭", + "noResults": "未找到搜索结果", + "noRecent": "没有搜索历史", + "recent": "搜索历史" + }, + "lockScreen": { + "title": "锁定屏幕", + "screenButton": "锁定", + "password": "密码", + "placeholder": "请输入锁屏密码", + "unlock": "点击解锁", + "errorPasswordTip": "密码错误,请重新输入", + "backToLogin": "返回登录", + "entry": "进入系统" + }, + "timezone": { + "setTimezone": "设置时区", + "setSuccess": "时区设置成功" + } + } +} diff --git a/admin-ui/vue/packages/locales/src/typing.ts b/admin-ui/vue/packages/locales/src/typing.ts new file mode 100644 index 0000000..fdebac2 --- /dev/null +++ b/admin-ui/vue/packages/locales/src/typing.ts @@ -0,0 +1,25 @@ +export type SupportedLanguagesType = 'en-US' | 'zh-CN'; + +export type ImportLocaleFn = () => Promise<{ default: Record }>; + +export type LoadMessageFn = ( + lang: SupportedLanguagesType, +) => Promise | undefined>; + +export interface LocaleSetupOptions { + /** + * Default language + * @default zh-CN + */ + defaultLocale?: SupportedLanguagesType; + /** + * Load message function + * @param lang + * @returns + */ + loadMessages?: LoadMessageFn; + /** + * Whether to warn when the key is not found + */ + missingWarn?: boolean; +} diff --git a/admin-ui/vue/packages/locales/tsconfig.json b/admin-ui/vue/packages/locales/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/locales/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/preferences/package.json b/admin-ui/vue/packages/preferences/package.json new file mode 100644 index 0000000..e6e52e2 --- /dev/null +++ b/admin-ui/vue/packages/preferences/package.json @@ -0,0 +1,26 @@ +{ + "name": "@vben/preferences", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/preferences" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/preferences": "workspace:*", + "@vben-core/typings": "workspace:*" + } +} diff --git a/admin-ui/vue/packages/preferences/src/index.ts b/admin-ui/vue/packages/preferences/src/index.ts new file mode 100644 index 0000000..75fab43 --- /dev/null +++ b/admin-ui/vue/packages/preferences/src/index.ts @@ -0,0 +1,17 @@ +import type { Preferences } from '@vben-core/preferences'; +import type { DeepPartial } from '@vben-core/typings'; + +/** + * 如果你想所有的app都使用相同的默认偏好设置,你可以在这里定义 + * 而不是去修改 @vben-core/preferences 中的默认偏好设置 + * @param preferences + * @returns + */ + +function defineOverridesPreferences(preferences: DeepPartial) { + return preferences; +} + +export { defineOverridesPreferences }; + +export * from '@vben-core/preferences'; diff --git a/admin-ui/vue/packages/preferences/tsconfig.json b/admin-ui/vue/packages/preferences/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/preferences/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/stores/package.json b/admin-ui/vue/packages/stores/package.json new file mode 100644 index 0000000..72bcf49 --- /dev/null +++ b/admin-ui/vue/packages/stores/package.json @@ -0,0 +1,32 @@ +{ + "name": "@vben/stores", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/stores" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/preferences": "workspace:*", + "@vben-core/shared": "workspace:*", + "@vben-core/typings": "workspace:*", + "pinia": "catalog:", + "pinia-plugin-persistedstate": "catalog:", + "secure-ls": "catalog:", + "vue": "catalog:", + "vue-router": "catalog:" + } +} diff --git a/admin-ui/vue/packages/stores/shim-pinia.d.ts b/admin-ui/vue/packages/stores/shim-pinia.d.ts new file mode 100644 index 0000000..558d0ba --- /dev/null +++ b/admin-ui/vue/packages/stores/shim-pinia.d.ts @@ -0,0 +1,9 @@ +// https://github.com/vuejs/pinia/issues/2098 +declare module 'pinia' { + export function acceptHMRUpdate( + initialUseStore: any | StoreDefinition, + hot: any, + ): (newModule: any) => any; +} + +export { acceptHMRUpdate }; diff --git a/admin-ui/vue/packages/stores/src/index.ts b/admin-ui/vue/packages/stores/src/index.ts new file mode 100644 index 0000000..41b3662 --- /dev/null +++ b/admin-ui/vue/packages/stores/src/index.ts @@ -0,0 +1,3 @@ +export * from './modules'; +export * from './setup'; +export { defineStore, storeToRefs } from 'pinia'; diff --git a/admin-ui/vue/packages/stores/src/modules/access.test.ts b/admin-ui/vue/packages/stores/src/modules/access.test.ts new file mode 100644 index 0000000..211e256 --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/access.test.ts @@ -0,0 +1,46 @@ +import { createPinia, setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; + +import { useAccessStore } from './access'; + +describe('useAccessStore', () => { + beforeEach(() => { + setActivePinia(createPinia()); + }); + + it('updates accessMenus state', () => { + const store = useAccessStore(); + expect(store.accessMenus).toEqual([]); + store.setAccessMenus([{ name: 'Dashboard', path: '/dashboard' }]); + expect(store.accessMenus).toEqual([ + { name: 'Dashboard', path: '/dashboard' }, + ]); + }); + + it('updates accessToken state correctly', () => { + const store = useAccessStore(); + expect(store.accessToken).toBeNull(); // 初始状态 + store.setAccessToken('abc123'); + expect(store.accessToken).toBe('abc123'); + }); + + it('returns the correct accessToken', () => { + const store = useAccessStore(); + store.setAccessToken('xyz789'); + expect(store.accessToken).toBe('xyz789'); + }); + + // 测试设置空的访问菜单列表 + it('handles empty accessMenus correctly', () => { + const store = useAccessStore(); + store.setAccessMenus([]); + expect(store.accessMenus).toEqual([]); + }); + + // 测试设置空的访问路由列表 + it('handles empty accessRoutes correctly', () => { + const store = useAccessStore(); + store.setAccessRoutes([]); + expect(store.accessRoutes).toEqual([]); + }); +}); diff --git a/admin-ui/vue/packages/stores/src/modules/access.ts b/admin-ui/vue/packages/stores/src/modules/access.ts new file mode 100644 index 0000000..b88242e --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/access.ts @@ -0,0 +1,129 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import type { MenuRecordRaw } from '@vben-core/typings'; + +import { acceptHMRUpdate, defineStore } from 'pinia'; + +type AccessToken = null | string; + +interface AccessState { + /** + * 权限码 + */ + accessCodes: string[]; + /** + * 可访问的菜单列表 + */ + accessMenus: MenuRecordRaw[]; + /** + * 可访问的路由列表 + */ + accessRoutes: RouteRecordRaw[]; + /** + * 登录 accessToken + */ + accessToken: AccessToken; + /** + * 是否已经检查过权限 + */ + isAccessChecked: boolean; + /** + * 是否锁屏状态 + */ + isLockScreen: boolean; + /** + * 锁屏密码 + */ + lockScreenPassword?: string; + /** + * 登录是否过期 + */ + loginExpired: boolean; + /** + * 登录 accessToken + */ + refreshToken: AccessToken; +} + +/** + * @zh_CN 访问权限相关 + */ +export const useAccessStore = defineStore('core-access', { + actions: { + getMenuByPath(path: string) { + function findMenu( + menus: MenuRecordRaw[], + path: string, + ): MenuRecordRaw | undefined { + for (const menu of menus) { + if (menu.path === path) { + return menu; + } + if (menu.children) { + const matched = findMenu(menu.children, path); + if (matched) { + return matched; + } + } + } + } + return findMenu(this.accessMenus, path); + }, + lockScreen(password: string) { + this.isLockScreen = true; + this.lockScreenPassword = password; + }, + setAccessCodes(codes: string[]) { + this.accessCodes = codes; + }, + setAccessMenus(menus: MenuRecordRaw[]) { + this.accessMenus = menus; + }, + setAccessRoutes(routes: RouteRecordRaw[]) { + this.accessRoutes = routes; + }, + setAccessToken(token: AccessToken) { + this.accessToken = token; + }, + setIsAccessChecked(isAccessChecked: boolean) { + this.isAccessChecked = isAccessChecked; + }, + setLoginExpired(loginExpired: boolean) { + this.loginExpired = loginExpired; + }, + setRefreshToken(token: AccessToken) { + this.refreshToken = token; + }, + unlockScreen() { + this.isLockScreen = false; + this.lockScreenPassword = undefined; + }, + }, + persist: { + // 持久化 + pick: [ + 'accessToken', + 'refreshToken', + 'accessCodes', + 'isLockScreen', + 'lockScreenPassword', + ], + }, + state: (): AccessState => ({ + accessCodes: [], + accessMenus: [], + accessRoutes: [], + accessToken: null, + isAccessChecked: false, + isLockScreen: false, + lockScreenPassword: undefined, + loginExpired: false, + refreshToken: null, + }), +}); + +// 解决热更新问题 +const hot = import.meta.hot; +if (hot) { + hot.accept(acceptHMRUpdate(useAccessStore, hot)); +} diff --git a/admin-ui/vue/packages/stores/src/modules/index.ts b/admin-ui/vue/packages/stores/src/modules/index.ts new file mode 100644 index 0000000..bb9a66f --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/index.ts @@ -0,0 +1,4 @@ +export * from './access'; +export * from './tabbar'; +export * from './timezone'; +export * from './user'; diff --git a/admin-ui/vue/packages/stores/src/modules/tabbar.test.ts b/admin-ui/vue/packages/stores/src/modules/tabbar.test.ts new file mode 100644 index 0000000..2dd6a6f --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/tabbar.test.ts @@ -0,0 +1,335 @@ +import { createRouter, createWebHistory } from 'vue-router'; + +import { startProgress, stopProgress } from '@vben-core/shared/utils'; + +import { createPinia, setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +vi.mock('@vben-core/shared/utils', async (importOriginal) => { + const actual = + await importOriginal(); + return { ...actual, startProgress: vi.fn(), stopProgress: vi.fn() }; +}); + +import { useTabbarStore } from './tabbar'; + +describe('useAccessStore', () => { + const router = createRouter({ + history: createWebHistory(), + routes: [], + }); + router.push = vi.fn(); + router.replace = vi.fn(); + beforeEach(() => { + setActivePinia(createPinia()); + vi.clearAllMocks(); + }); + + it('adds a new tab', () => { + const store = useTabbarStore(); + const tab: any = { + fullPath: '/home', + meta: {}, + key: '/home', + name: 'Home', + path: '/home', + }; + const addNewTab = store.addTab(tab); + expect(store.tabs.length).toBe(1); + expect(store.tabs[0]).toEqual(addNewTab); + }); + + it('adds a new tab if it does not exist', () => { + const store = useTabbarStore(); + const newTab: any = { + fullPath: '/new', + meta: {}, + name: 'New', + path: '/new', + }; + const addNewTab = store.addTab(newTab); + expect(store.tabs).toContainEqual(addNewTab); + }); + + it('updates an existing tab instead of adding a new one', () => { + const store = useTabbarStore(); + const initialTab: any = { + fullPath: '/existing', + meta: { + fullPathKey: false, + }, + name: 'Existing', + path: '/existing', + query: {}, + }; + store.addTab(initialTab); + const updatedTab = { ...initialTab, query: { id: '1' } }; + store.addTab(updatedTab); + expect(store.tabs.length).toBe(1); + expect(store.tabs[0]?.query).toEqual({ id: '1' }); + }); + + it('reuses a tab when pageKey is stable and other query values change', () => { + const store = useTabbarStore(); + const firstTab: any = { + fullPath: '/diagnosis?pageKey=/diagnosis&queryCode=card-1', + meta: {}, + name: 'Diagnosis', + path: '/diagnosis', + query: { pageKey: '/diagnosis', queryCode: 'card-1' }, + }; + const secondTab: any = { + ...firstTab, + fullPath: '/diagnosis?pageKey=/diagnosis&queryCode=card-2', + query: { pageKey: '/diagnosis', queryCode: 'card-2' }, + }; + + store.addTab(firstTab); + store.addTab(secondTab); + + expect(store.tabs).toHaveLength(1); + expect(store.tabs[0]?.query).toEqual({ + pageKey: '/diagnosis', + queryCode: 'card-2', + }); + }); + + it('closes all tabs', async () => { + const store = useTabbarStore(); + store.addTab({ + fullPath: '/home', + meta: {}, + name: 'Home', + path: '/home', + } as any); + router.replace = vi.fn(); + + await store.closeAllTabs(router); + + expect(store.tabs.length).toBe(1); + }); + + it('closes a non-affix tab', () => { + const store = useTabbarStore(); + const tab: any = { + fullPath: '/closable', + meta: {}, + name: 'Closable', + path: '/closable', + }; + store.tabs.push(tab); + store._close(tab); + expect(store.tabs.length).toBe(0); + }); + + it('does not close an affix tab', () => { + const store = useTabbarStore(); + const affixTab: any = { + fullPath: '/affix', + meta: { affixTab: true }, + name: 'Affix', + path: '/affix', + }; + store.tabs.push(affixTab); + store._close(affixTab); + expect(store.tabs.length).toBe(1); // Affix tab should not be closed + }); + + it('returns all cache tabs', () => { + const store = useTabbarStore(); + store.cachedTabs.add('Home'); + store.cachedTabs.add('About'); + expect(store.getCachedTabs).toEqual(['Home', 'About']); + }); + + it('returns all tabs, including affix tabs', () => { + const store = useTabbarStore(); + const normalTab: any = { + fullPath: '/normal', + meta: {}, + name: 'Normal', + path: '/normal', + }; + const affixTab: any = { + fullPath: '/affix', + meta: { affixTab: true }, + name: 'Affix', + path: '/affix', + }; + store.tabs.push(normalTab); + store.affixTabs.push(affixTab); + expect(store.getTabs).toContainEqual(normalTab); + expect(store.affixTabs).toContainEqual(affixTab); + }); + + it('navigates to a specific tab', async () => { + const store = useTabbarStore(); + const tab: any = { meta: {}, name: 'Dashboard', path: '/dashboard' }; + + await store._goToTab(tab, router); + + expect(router.replace).toHaveBeenCalledWith({ + params: {}, + path: '/dashboard', + query: {}, + }); + }); + + it('closes multiple tabs by paths', async () => { + const store = useTabbarStore(); + store.addTab({ + fullPath: '/home', + meta: {}, + name: 'Home', + path: '/home', + } as any); + store.addTab({ + fullPath: '/about', + meta: {}, + name: 'About', + path: '/about', + } as any); + store.addTab({ + fullPath: '/contact', + meta: {}, + name: 'Contact', + path: '/contact', + } as any); + + await store._bulkCloseByKeys(['/home', '/contact']); + + expect(store.tabs).toHaveLength(1); + expect(store.tabs[0]?.name).toBe('About'); + }); + + it('closes all tabs to the left of the specified tab', async () => { + const store = useTabbarStore(); + store.addTab({ + fullPath: '/home', + meta: {}, + name: 'Home', + path: '/home', + } as any); + store.addTab({ + fullPath: '/about', + meta: {}, + name: 'About', + path: '/about', + } as any); + const targetTab: any = { + fullPath: '/contact', + meta: {}, + name: 'Contact', + path: '/contact', + }; + const addTargetTab = store.addTab(targetTab); + await store.closeLeftTabs(addTargetTab); + + expect(store.tabs).toHaveLength(1); + expect(store.tabs[0]?.name).toBe('Contact'); + }); + + it('closes all tabs except the specified tab', async () => { + const store = useTabbarStore(); + store.addTab({ + fullPath: '/home', + meta: {}, + name: 'Home', + path: '/home', + } as any); + const targetTab: any = { + fullPath: '/about', + meta: {}, + name: 'About', + path: '/about', + }; + const addTargetTab = store.addTab(targetTab); + store.addTab({ + fullPath: '/contact', + meta: {}, + name: 'Contact', + path: '/contact', + } as any); + + await store.closeOtherTabs(addTargetTab); + + expect(store.tabs).toHaveLength(1); + expect(store.tabs[0]?.name).toBe('About'); + }); + + it('closes all tabs to the right of the specified tab', async () => { + const store = useTabbarStore(); + const targetTab: any = { + fullPath: '/home', + meta: {}, + name: 'Home', + path: '/home', + }; + const addTargetTab = store.addTab(targetTab); + store.addTab({ + fullPath: '/about', + meta: {}, + name: 'About', + path: '/about', + } as any); + store.addTab({ + fullPath: '/contact', + meta: {}, + name: 'Contact', + path: '/contact', + } as any); + + await store.closeRightTabs(addTargetTab); + + expect(store.tabs).toHaveLength(1); + expect(store.tabs[0]?.name).toBe('Home'); + }); + + it('closes the tab with the specified key', async () => { + const store = useTabbarStore(); + const keyToClose = '/about'; + store.addTab({ + fullPath: '/home', + meta: {}, + name: 'Home', + path: '/home', + } as any); + store.addTab({ + fullPath: keyToClose, + meta: {}, + name: 'About', + path: '/about', + } as any); + store.addTab({ + fullPath: '/contact', + meta: {}, + name: 'Contact', + path: '/contact', + } as any); + + await store.closeTabByKey(keyToClose, router); + + expect(store.tabs).toHaveLength(2); + expect( + store.tabs.find((tab) => tab.fullPath === keyToClose), + ).toBeUndefined(); + }); + + it('refreshes the current tab', async () => { + const store = useTabbarStore(); + const currentTab: any = { + fullPath: '/dashboard', + meta: { name: 'Dashboard' }, + name: 'Dashboard', + path: '/dashboard', + }; + router.currentRoute.value = currentTab; + + await store.refresh(router); + + expect(store.excludeCachedTabs.has('Dashboard')).toBe(false); + expect(store.renderRouteView).toBe(true); + expect(startProgress).toHaveBeenCalledTimes(1); + expect(stopProgress).toHaveBeenCalledTimes(1); + }); +}); diff --git a/admin-ui/vue/packages/stores/src/modules/tabbar.ts b/admin-ui/vue/packages/stores/src/modules/tabbar.ts new file mode 100644 index 0000000..b1b4060 --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/tabbar.ts @@ -0,0 +1,658 @@ +import type { ComputedRef } from 'vue'; +import type { + RouteLocationNormalized, + Router, + RouteRecordNormalized, +} from 'vue-router'; + +import type { TabDefinition } from '@vben-core/typings'; + +import { toRaw } from 'vue'; + +import { preferences } from '@vben-core/preferences'; +import { + openRouteInNewWindow, + startProgress, + stopProgress, +} from '@vben-core/shared/utils'; + +import { acceptHMRUpdate, defineStore } from 'pinia'; + +interface TabbarState { + /** + * @zh_CN 当前打开的标签页列表缓存 + */ + cachedTabs: Set; + /** + * @zh_CN 拖拽结束的索引 + */ + dragEndIndex: number; + /** + * @zh_CN 需要排除缓存的标签页 + */ + excludeCachedTabs: Set; + /** + * @zh_CN 标签右键菜单列表 + */ + menuList: string[]; + /** + * @zh_CN 是否刷新 + */ + renderRouteView?: boolean; + /** + * @zh_CN 当前打开的标签页列表 + */ + tabs: TabDefinition[]; + /** + * @zh_CN 更新时间,用于一些更新场景,使用watch深度监听的话,会损耗性能 + */ + updateTime?: number; +} + +/** + * @zh_CN 访问权限相关 + */ +export const useTabbarStore = defineStore('core-tabbar', { + actions: { + /** + * Close tabs in bulk + */ + async _bulkCloseByKeys(keys: string[]) { + const keySet = new Set(keys); + this.tabs = this.tabs.filter( + (item) => !keySet.has(getTabKeyFromTab(item)), + ); + + await this.updateCacheTabs(); + }, + /** + * @zh_CN 关闭标签页 + * @param tab + */ + _close(tab: TabDefinition) { + if (isAffixTab(tab)) { + return; + } + const index = this.tabs.findIndex((item) => equalTab(item, tab)); + index !== -1 && this.tabs.splice(index, 1); + }, + /** + * @zh_CN 跳转到默认标签页 + */ + async _goToDefaultTab(router: Router) { + if (this.getTabs.length <= 0) { + return; + } + const firstTab = this.getTabs[0]; + if (firstTab) { + await this._goToTab(firstTab, router); + } + }, + /** + * @zh_CN 跳转到标签页 + * @param tab + * @param router + */ + async _goToTab(tab: TabDefinition, router: Router) { + const { params, path, query } = tab; + const toParams = { + params: params || {}, + path, + query: query || {}, + }; + await router.replace(toParams); + }, + /** + * @zh_CN 添加标签页 + * @param routeTab + */ + addTab(routeTab: TabDefinition): TabDefinition { + let tab = cloneTab(routeTab); + if (!tab.key) { + tab.key = getTabKey(routeTab); + } + if (!isTabShown(tab)) { + return tab; + } + + const tabIndex = this.tabs.findIndex((item) => { + return equalTab(item, tab); + }); + + if (tabIndex === -1) { + const maxCount = preferences.tabbar.maxCount; + // 获取动态路由打开数,超过 0 即代表需要控制打开数 + const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ?? + -1) as number; + // 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了 + // 获取到已经打开的动态路由数, 判断是否大于某一个值 + if ( + maxNumOfOpenTab > 0 && + this.tabs.filter((tab) => tab.name === routeTab.name).length >= + maxNumOfOpenTab + ) { + // 关闭第一个 + const index = this.tabs.findIndex( + (item) => item.name === routeTab.name, + ); + index !== -1 && this.tabs.splice(index, 1); + } else if (maxCount > 0 && this.tabs.length >= maxCount) { + // 关闭第一个 + const index = this.tabs.findIndex( + (item) => + !Reflect.has(item.meta, 'affixTab') || !item.meta.affixTab, + ); + index !== -1 && this.tabs.splice(index, 1); + } + this.tabs.push(tab); + } else { + // 页面已经存在,不重复添加选项卡,只更新选项卡参数 + const currentTab = toRaw(this.tabs)[tabIndex]; + const mergedTab = { + ...currentTab, + ...tab, + meta: { ...currentTab?.meta, ...tab.meta }, + }; + if (currentTab) { + const curMeta = currentTab.meta; + if (Reflect.has(curMeta, 'affixTab')) { + mergedTab.meta.affixTab = curMeta.affixTab; + } + if (Reflect.has(curMeta, 'newTabTitle')) { + mergedTab.meta.newTabTitle = curMeta.newTabTitle; + } + } + tab = mergedTab; + this.tabs.splice(tabIndex, 1, mergedTab); + } + this.updateCacheTabs(); + return tab; + }, + /** + * @zh_CN 关闭所有标签页 + */ + async closeAllTabs(router: Router) { + const newTabs = this.tabs.filter((tab) => isAffixTab(tab)); + this.tabs = newTabs.length > 0 ? newTabs : [...this.tabs].splice(0, 1); + await this._goToDefaultTab(router); + this.updateCacheTabs(); + }, + /** + * @zh_CN 关闭左侧标签页 + * @param tab + */ + async closeLeftTabs(tab: TabDefinition) { + const index = this.tabs.findIndex((item) => equalTab(item, tab)); + + if (index < 1) { + return; + } + + const leftTabs = this.tabs.slice(0, index); + const keys: string[] = []; + + for (const item of leftTabs) { + if (!isAffixTab(item)) { + keys.push(item.key as string); + } + } + await this._bulkCloseByKeys(keys); + }, + /** + * @zh_CN 关闭其他标签页 + * @param tab + */ + async closeOtherTabs(tab: TabDefinition) { + const closeKeys = this.tabs.map((item) => getTabKeyFromTab(item)); + + const keys: string[] = []; + + for (const key of closeKeys) { + if (key !== getTabKeyFromTab(tab)) { + const closeTab = this.tabs.find( + (item) => getTabKeyFromTab(item) === key, + ); + if (!closeTab) { + continue; + } + if (!isAffixTab(closeTab)) { + keys.push(closeTab.key as string); + } + } + } + await this._bulkCloseByKeys(keys); + }, + /** + * @zh_CN 关闭右侧标签页 + * @param tab + */ + async closeRightTabs(tab: TabDefinition) { + const index = this.tabs.findIndex((item) => equalTab(item, tab)); + + if (index !== -1 && index < this.tabs.length - 1) { + const rightTabs = this.tabs.slice(index + 1); + + const keys: string[] = []; + for (const item of rightTabs) { + if (!isAffixTab(item)) { + keys.push(item.key as string); + } + } + await this._bulkCloseByKeys(keys); + } + }, + + /** + * @zh_CN 关闭标签页 + * @param tab + * @param router + */ + async closeTab(tab: TabDefinition, router: Router) { + const { currentRoute } = router; + // 关闭不是激活选项卡 + if (getTabKey(currentRoute.value) !== getTabKeyFromTab(tab)) { + this._close(tab); + this.updateCacheTabs(); + return; + } + const index = this.getTabs.findIndex( + (item) => getTabKeyFromTab(item) === getTabKey(currentRoute.value), + ); + + const before = this.getTabs[index - 1]; + const after = this.getTabs[index + 1]; + + // 下一个tab存在,跳转到下一个 + if (after) { + this._close(tab); + await this._goToTab(after, router); + // 上一个tab存在,跳转到上一个 + } else if (before) { + this._close(tab); + await this._goToTab(before, router); + } else { + console.error('Failed to close the tab; only one tab remains open.'); + } + }, + + /** + * @zh_CN 通过key关闭标签页 + * @param key + * @param router + */ + async closeTabByKey(key: string, router: Router) { + const originKey = decodeURIComponent(key); + const index = this.tabs.findIndex( + (item) => getTabKeyFromTab(item) === originKey, + ); + if (index === -1) { + return; + } + + const tab = this.tabs[index]; + if (tab) { + await this.closeTab(tab, router); + } + }, + + /** + * 根据tab的key获取tab + * @param key + */ + getTabByKey(key: string) { + return this.getTabs.find( + (item) => getTabKeyFromTab(item) === key, + ) as TabDefinition; + }, + /** + * @zh_CN 新窗口打开标签页 + * @param tab + */ + async openTabInNewWindow(tab: TabDefinition) { + openRouteInNewWindow(tab.fullPath || tab.path); + }, + + /** + * @zh_CN 固定标签页 + * @param tab + */ + async pinTab(tab: TabDefinition) { + const index = this.tabs.findIndex((item) => equalTab(item, tab)); + if (index === -1) { + return; + } + const oldTab = this.tabs[index]; + tab.meta.affixTab = true; + tab.meta.title = oldTab?.meta?.title as string; + // this.addTab(tab); + this.tabs.splice(index, 1, tab); + // 过滤固定tabs,后面更改affixTabOrder的值的话可能会有问题,目前行464排序affixTabs没有设置值 + const affixTabs = this.tabs.filter((tab) => isAffixTab(tab)); + // 获得固定tabs的index + const newIndex = affixTabs.findIndex((item) => equalTab(item, tab)); + // 交换位置重新排序 + await this.sortTabs(index, newIndex); + }, + + /** + * 刷新标签页 + */ + async refresh(router: Router | string) { + // 如果是Router路由,那么就根据当前路由刷新 + // 如果是string字符串,为路由名称,则定向刷新指定标签页,不能是当前路由名称,否则不会刷新 + if (typeof router === 'string') { + return await this.refreshByName(router); + } + + const { currentRoute } = router; + const { name } = currentRoute.value; + + this.excludeCachedTabs.add(name as string); + this.renderRouteView = false; + startProgress(); + + await new Promise((resolve) => setTimeout(resolve, 200)); + + this.excludeCachedTabs.delete(name as string); + this.renderRouteView = true; + stopProgress(); + }, + + /** + * 根据路由名称刷新指定标签页 + */ + async refreshByName(name: string) { + this.excludeCachedTabs.add(name); + await new Promise((resolve) => setTimeout(resolve, 200)); + this.excludeCachedTabs.delete(name); + }, + + /** + * @zh_CN 重置标签页标题 + */ + async resetTabTitle(tab: TabDefinition) { + if (tab?.meta?.newTabTitle) { + return; + } + const findTab = this.tabs.find((item) => equalTab(item, tab)); + if (findTab) { + findTab.meta.newTabTitle = undefined; + await this.updateCacheTabs(); + } + }, + + /** + * 设置固定标签页 + * @param tabs + */ + setAffixTabs(tabs: RouteRecordNormalized[]) { + for (const tab of tabs) { + tab.meta.affixTab = true; + this.addTab(routeToTab(tab)); + } + }, + + /** + * @zh_CN 更新菜单列表 + * @param list + */ + setMenuList(list: string[]) { + this.menuList = list; + }, + + /** + * @zh_CN 设置标签页标题 + * + * @zh_CN 支持设置静态标题字符串或计算属性作为动态标题 + * @zh_CN 当标题为计算属性时,标题会随计算属性值变化而自动更新 + * @zh_CN 适用于需要根据状态或多语言动态更新标题的场景 + * + * @param {TabDefinition} tab - 标签页对象 + * @param {ComputedRef | string} title - 标题内容,支持静态字符串或计算属性 + * + * @example + * // 设置静态标题 + * setTabTitle(tab, '新标签页'); + * + * @example + * // 设置动态标题 + * setTabTitle(tab, computed(() => t('common.dashboard'))); + */ + async setTabTitle(tab: TabDefinition, title: ComputedRef | string) { + const findTab = this.tabs.find((item) => equalTab(item, tab)); + + if (findTab) { + findTab.meta.newTabTitle = title; + + await this.updateCacheTabs(); + } + }, + setUpdateTime() { + this.updateTime = Date.now(); + }, + /** + * @zh_CN 设置标签页顺序 + * @param oldIndex + * @param newIndex + */ + async sortTabs(oldIndex: number, newIndex: number) { + const currentTab = this.tabs[oldIndex]; + if (!currentTab) { + return; + } + this.tabs.splice(oldIndex, 1); + this.tabs.splice(newIndex, 0, currentTab); + this.dragEndIndex = this.dragEndIndex + 1; + }, + + /** + * @zh_CN 切换固定标签页 + * @param tab + */ + async toggleTabPin(tab: TabDefinition) { + const affixTab = tab?.meta?.affixTab ?? false; + + await (affixTab ? this.unpinTab(tab) : this.pinTab(tab)); + }, + + /** + * @zh_CN 取消固定标签页 + * @param tab + */ + async unpinTab(tab: TabDefinition) { + const index = this.tabs.findIndex((item) => equalTab(item, tab)); + if (index === -1) { + return; + } + const oldTab = this.tabs[index]; + tab.meta.affixTab = false; + tab.meta.title = oldTab?.meta?.title as string; + // this.addTab(tab); + this.tabs.splice(index, 1, tab); + // 过滤固定tabs,后面更改affixTabOrder的值的话可能会有问题,目前行464排序affixTabs没有设置值 + const affixTabs = this.tabs.filter((tab) => isAffixTab(tab)); + // 获得固定tabs的index,使用固定tabs的下一个位置也就是活动tabs的第一个位置 + const newIndex = affixTabs.length; + // 交换位置重新排序 + await this.sortTabs(index, newIndex); + }, + /** + * 根据当前打开的选项卡更新缓存 + */ + async updateCacheTabs() { + const cacheMap = new Set(); + + for (const tab of this.tabs) { + // 跳过不需要持久化的标签页 + const keepAlive = tab.meta?.keepAlive; + if (!keepAlive) { + continue; + } + (tab.matched || []).forEach((t, i) => { + if (i > 0) { + cacheMap.add(t.name as string); + } + }); + + const name = tab.name as string; + cacheMap.add(name); + } + this.cachedTabs = cacheMap; + }, + }, + getters: { + affixTabs(): TabDefinition[] { + const affixTabs = this.tabs.filter((tab) => isAffixTab(tab)); + + return affixTabs.toSorted((a, b) => { + const orderA = (a.meta?.affixTabOrder ?? 0) as number; + const orderB = (b.meta?.affixTabOrder ?? 0) as number; + return orderA - orderB; + }); + }, + getCachedTabs(): string[] { + return [...this.cachedTabs]; + }, + getExcludeCachedTabs(): string[] { + return [...this.excludeCachedTabs]; + }, + getMenuList(): string[] { + return this.menuList; + }, + getTabs(): TabDefinition[] { + const normalTabs = this.tabs.filter((tab) => !isAffixTab(tab)); + return [...this.affixTabs, ...normalTabs].filter(Boolean); + }, + }, + persist: [ + // tabs不需要保存在localStorage + { + pick: ['tabs'], + storage: sessionStorage, + }, + ], + state: (): TabbarState => ({ + cachedTabs: new Set(), + dragEndIndex: 0, + excludeCachedTabs: new Set(), + menuList: [ + 'close', + 'affix', + 'maximize', + 'reload', + 'open-in-new-window', + 'close-left', + 'close-right', + 'close-other', + 'close-all', + ], + renderRouteView: true, + tabs: [], + updateTime: Date.now(), + }), +}); + +// 解决热更新问题 +const hot = import.meta.hot; +if (hot) { + hot.accept(acceptHMRUpdate(useTabbarStore, hot)); +} + +/** + * @zh_CN 克隆路由,防止路由被修改 + * @param route + */ +function cloneTab(route: TabDefinition): TabDefinition { + if (!route) { + return route; + } + const { matched, meta, ...opt } = route; + return { + ...opt, + matched: (matched + ? matched.map((item) => ({ + meta: item.meta, + name: item.name, + path: item.path, + })) + : undefined) as RouteRecordNormalized[], + meta: { + ...meta, + newTabTitle: meta.newTabTitle, + }, + }; +} + +/** + * @zh_CN 是否是固定标签页 + * @param tab + */ +function isAffixTab(tab: TabDefinition) { + return tab?.meta?.affixTab ?? false; +} + +/** + * @zh_CN 是否显示标签 + * @param tab + */ +function isTabShown(tab: TabDefinition) { + const matched = tab?.matched ?? []; + return !tab.meta.hideInTab && matched.every((item) => !item.meta.hideInTab); +} + +/** + * 从route获取tab页的key + * @param tab + */ +function getTabKey(tab: RouteLocationNormalized | RouteRecordNormalized) { + const { + fullPath, + path, + meta: { fullPathKey } = {}, + query = {}, + } = tab as RouteLocationNormalized; + // pageKey可能是数组(查询参数重复时可能出现) + const pageKey = Array.isArray(query.pageKey) + ? query.pageKey[0] + : query.pageKey; + let rawKey; + if (pageKey) { + rawKey = pageKey; + } else { + rawKey = fullPathKey === false ? path : (fullPath ?? path); + } + try { + return decodeURIComponent(rawKey); + } catch { + return rawKey; + } +} + +/** + * 从tab获取tab页的key + * 如果tab没有key,那么就从route获取key + * @param tab + */ +function getTabKeyFromTab(tab: TabDefinition): string { + return tab.key ?? getTabKey(tab); +} + +/** + * 比较两个tab是否相等 + * @param a + * @param b + */ +function equalTab(a: TabDefinition, b: TabDefinition) { + return getTabKeyFromTab(a) === getTabKeyFromTab(b); +} + +function routeToTab(route: RouteRecordNormalized) { + return { + meta: route.meta, + name: route.name, + path: route.path, + key: getTabKey(route), + } as TabDefinition; +} + +export { getTabKey }; diff --git a/admin-ui/vue/packages/stores/src/modules/timezone.ts b/admin-ui/vue/packages/stores/src/modules/timezone.ts new file mode 100644 index 0000000..24180c6 --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/timezone.ts @@ -0,0 +1,132 @@ +import { ref, unref } from 'vue'; + +import { DEFAULT_TIME_ZONE_OPTIONS } from '@vben-core/preferences'; +import { + getCurrentTimezone, + setCurrentTimezone, +} from '@vben-core/shared/utils'; + +import { acceptHMRUpdate, defineStore } from 'pinia'; + +interface TimezoneHandler { + getTimezone?: () => Promise; + getTimezoneOptions?: () => Promise< + { + label: string; + value: string; + }[] + >; + setTimezone?: (timezone: string) => Promise; +} + +/** + * 默认时区处理模块 + * 时区存储基于pinia存储插件 + */ +const getDefaultTimezoneHandler = (): TimezoneHandler => { + return { + getTimezoneOptions: () => { + return Promise.resolve( + DEFAULT_TIME_ZONE_OPTIONS.map((item) => { + return { + label: item.label, + value: item.timezone, + }; + }), + ); + }, + }; +}; + +/** + * 自定义时区处理模块 + */ +let customTimezoneHandler: null | Partial = null; +const setTimezoneHandler = (handler: Partial) => { + customTimezoneHandler = handler; +}; + +/** + * 获取时区处理模块 + */ +const getTimezoneHandler = () => { + return { + ...getDefaultTimezoneHandler(), + ...customTimezoneHandler, + }; +}; + +/** + * timezone支持模块 + */ +const useTimezoneStore = defineStore( + 'core-timezone', + () => { + const timezoneRef = ref(getCurrentTimezone()); + + /** + * 初始化时区 + * Initialize the timezone + */ + async function initTimezone() { + const timezoneHandler = getTimezoneHandler(); + const timezone = await timezoneHandler.getTimezone?.(); + if (timezone) { + timezoneRef.value = timezone; + } + // 设置dayjs默认时区 + setCurrentTimezone(unref(timezoneRef)); + } + + /** + * 设置时区 + * Set the timezone + * @param timezone 时区字符串 + */ + async function setTimezone(timezone: string) { + const timezoneHandler = getTimezoneHandler(); + await timezoneHandler.setTimezone?.(timezone); + timezoneRef.value = timezone; + // 设置dayjs默认时区 + setCurrentTimezone(timezone); + } + + /** + * 获取时区选项 + * Get the timezone options + */ + async function getTimezoneOptions() { + const timezoneHandler = getTimezoneHandler(); + return (await timezoneHandler.getTimezoneOptions?.()) || []; + } + + initTimezone().catch((error) => { + console.error('Failed to initialize timezone during store setup:', error); + }); + + function $reset() { + timezoneRef.value = getCurrentTimezone(); + } + + return { + timezone: timezoneRef, + setTimezone, + getTimezoneOptions, + $reset, + }; + }, + { + persist: { + // 持久化 + pick: ['timezone'], + }, + }, +); + +export { setTimezoneHandler, useTimezoneStore }; + +// 解决热更新问题 +const hot = import.meta.hot; +if (hot) { + hot.accept(acceptHMRUpdate(useTimezoneStore, hot)); +} diff --git a/admin-ui/vue/packages/stores/src/modules/user.test.ts b/admin-ui/vue/packages/stores/src/modules/user.test.ts new file mode 100644 index 0000000..3d8a22c --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/user.test.ts @@ -0,0 +1,37 @@ +import { createPinia, setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; + +import { useUserStore } from './user'; + +describe('useUserStore', () => { + beforeEach(() => { + setActivePinia(createPinia()); + }); + + it('returns correct userInfo', () => { + const store = useUserStore(); + const userInfo: any = { name: 'Jane Doe', roles: [{ value: 'user' }] }; + store.setUserInfo(userInfo); + expect(store.userInfo).toEqual(userInfo); + }); + + // 测试重置用户信息时的行为 + it('clears userInfo and userRoles when setting null userInfo', () => { + const store = useUserStore(); + store.setUserInfo({ + roles: [{ roleName: 'User', value: 'user' }], + } as any); + expect(store.userInfo).not.toBeNull(); + expect(store.userRoles.length).toBeGreaterThan(0); + + store.setUserInfo(null as any); + expect(store.userInfo).toBeNull(); + expect(store.userRoles).toEqual([]); + }); + + // 测试在没有用户角色时返回空数组 + it('returns an empty array for userRoles if not set', () => { + const store = useUserStore(); + expect(store.userRoles).toEqual([]); + }); +}); diff --git a/admin-ui/vue/packages/stores/src/modules/user.ts b/admin-ui/vue/packages/stores/src/modules/user.ts new file mode 100644 index 0000000..9d37433 --- /dev/null +++ b/admin-ui/vue/packages/stores/src/modules/user.ts @@ -0,0 +1,64 @@ +import { acceptHMRUpdate, defineStore } from 'pinia'; + +interface BasicUserInfo { + [key: string]: any; + /** + * 头像 + */ + avatar: string; + /** + * 用户昵称 + */ + realName: string; + /** + * 用户角色 + */ + roles?: string[]; + /** + * 用户id + */ + userId: string; + /** + * 用户名 + */ + username: string; +} + +interface AccessState { + /** + * 用户信息 + */ + userInfo: BasicUserInfo | null; + /** + * 用户角色 + */ + userRoles: string[]; +} + +/** + * @zh_CN 用户信息相关 + */ +export const useUserStore = defineStore('core-user', { + actions: { + setUserInfo(userInfo: BasicUserInfo | null) { + // 设置用户信息 + this.userInfo = userInfo; + // 设置角色信息 + const roles = userInfo?.roles ?? []; + this.setUserRoles(roles); + }, + setUserRoles(roles: string[]) { + this.userRoles = roles; + }, + }, + state: (): AccessState => ({ + userInfo: null, + userRoles: [], + }), +}); + +// 解决热更新问题 +const hot = import.meta.hot; +if (hot) { + hot.accept(acceptHMRUpdate(useUserStore, hot)); +} diff --git a/admin-ui/vue/packages/stores/src/setup.ts b/admin-ui/vue/packages/stores/src/setup.ts new file mode 100644 index 0000000..b18c27e --- /dev/null +++ b/admin-ui/vue/packages/stores/src/setup.ts @@ -0,0 +1,60 @@ +import type { Pinia } from 'pinia'; + +import type { App } from 'vue'; + +import { createPinia } from 'pinia'; +import SecureLS from 'secure-ls'; + +let pinia: Pinia; + +export interface InitStoreOptions { + /** + * @zh_CN 应用名,由于 @vben/stores 是公用的,后续可能有多个app,为了防止多个app缓存冲突,可在这里配置应用名,应用名将被用于持久化的前缀 + */ + namespace: string; +} + +/** + * @zh_CN 初始化pinia + */ +export async function initStores(app: App, options: InitStoreOptions) { + const { createPersistedState } = await import('pinia-plugin-persistedstate'); + pinia = createPinia(); + const { namespace } = options; + const ls = new SecureLS({ + encodingType: 'aes', + encryptionSecret: import.meta.env.VITE_APP_STORE_SECURE_KEY, + isCompression: true, + // @ts-ignore secure-ls does not have a type definition for this + metaKey: `${namespace}-secure-meta`, + }); + pinia.use( + createPersistedState({ + // key $appName-$store.id + key: (storeKey) => `${namespace}-${storeKey}`, + storage: import.meta.env.DEV + ? localStorage + : { + getItem(key) { + return ls.get(key); + }, + setItem(key, value) { + ls.set(key, value); + }, + }, + }), + ); + app.use(pinia); + return pinia; +} + +export function resetAllStores() { + if (!pinia) { + console.error('Pinia is not installed'); + return; + } + const allStores = (pinia as any)._s; + for (const [_key, store] of allStores) { + store.$reset(); + } +} diff --git a/admin-ui/vue/packages/stores/tsconfig.json b/admin-ui/vue/packages/stores/tsconfig.json new file mode 100644 index 0000000..3057820 --- /dev/null +++ b/admin-ui/vue/packages/stores/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src", "shim-pinia.d.ts"] +} diff --git a/admin-ui/vue/packages/styles/README.md b/admin-ui/vue/packages/styles/README.md new file mode 100644 index 0000000..4826446 --- /dev/null +++ b/admin-ui/vue/packages/styles/README.md @@ -0,0 +1,19 @@ +# @vben/styles + +用于多个 `app` 公用的样式文件,继承了 `@vben-core/design` 的所有能力。业务上有通用的样式文件可以放在这里。 + +## 用法 + +### 添加依赖 + +```bash +# 进入目标应用目录,例如 apps/xxxx-app +# cd apps/xxxx-app +pnpm add @vben/styles +``` + +### 使用 + +```ts +import '@vben/styles'; +``` diff --git a/admin-ui/vue/packages/styles/package.json b/admin-ui/vue/packages/styles/package.json new file mode 100644 index 0000000..0716a5e --- /dev/null +++ b/admin-ui/vue/packages/styles/package.json @@ -0,0 +1,34 @@ +{ + "name": "@vben/styles", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/styles" + }, + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./antd": { + "default": "./src/antd/index.css" + }, + "./ele": { + "default": "./src/ele/index.css" + }, + "./naive": { + "default": "./src/naive/index.css" + }, + "./global": { + "default": "./src/global/index.scss" + } + }, + "dependencies": { + "@vben-core/design": "workspace:*" + } +} diff --git a/admin-ui/vue/packages/styles/src/antd/index.css b/admin-ui/vue/packages/styles/src/antd/index.css new file mode 100644 index 0000000..4dec637 --- /dev/null +++ b/admin-ui/vue/packages/styles/src/antd/index.css @@ -0,0 +1,75 @@ +/* ant-design-vue 组件库的一些样式重置 */ + +.ant-app { + width: 100%; + height: 100%; + overscroll-behavior: none; + color: inherit; +} + +.ant-btn { + .anticon { + display: inline-flex; + } + + /* * 修复按钮添加图标时的位置问题 */ + > svg { + display: inline-block; + } + + > svg + span { + margin-inline-start: 6px; + } +} + +.ant-tag { + > svg { + display: inline-block; + } + + > svg + span { + margin-inline-start: 4px; + } +} + +.ant-message-notice-content, +.ant-notification-notice { + @apply dark:border-border/60 dark:border; +} + +.form-valid-error { + /** select 选择器的样式 */ + + .ant-select:not(.valid-success) .ant-select-selector:not(.valid-success) { + border-color: hsl(var(--destructive)) !important; + } + + .ant-select-focused .ant-select-selector { + box-shadow: 0 0 0 2px rgb(255 38 5 / 6%) !important; + } + + /** 数字输入框样式 */ + .ant-input-number-focused { + box-shadow: 0 0 0 2px rgb(255 38 5 / 6%); + } + + /** 密码输入框样式 */ + .ant-input-affix-wrapper:hover { + border-color: hsl(var(--destructive)); + box-shadow: 0 0 0 2px rgb(255 38 5 / 6%); + } + + .ant-input:not(.valid-success) { + border-color: hsl(var(--destructive)) !important; + } +} + +/** 区间选择器下面来回切换时的样式 */ +.ant-app .form-valid-error .ant-picker-active-bar { + background-color: hsl(var(--destructive)); +} + +/** 时间选择器的样式 */ +.ant-app .form-valid-error .ant-picker-focused { + box-shadow: 0 0 0 2px rgb(255 38 5 / 6%); +} diff --git a/admin-ui/vue/packages/styles/src/ele/index.css b/admin-ui/vue/packages/styles/src/ele/index.css new file mode 100644 index 0000000..4ee8f7b --- /dev/null +++ b/admin-ui/vue/packages/styles/src/ele/index.css @@ -0,0 +1,44 @@ +.el-card { + --el-card-border-radius: var(--radius) !important; +} + +.form-valid-error { + /** select 选择器的样式 */ + .el-select .el-select__wrapper { + box-shadow: 0 0 0 1px var(--el-color-danger) inset; + } + + /** input 选择器的样式 */ + .el-input .el-input__wrapper { + box-shadow: 0 0 0 1px var(--el-color-danger) inset; + } + + /** radio和checkbox 选择器的样式 */ + .el-radio .el-radio__inner, + .el-checkbox .el-checkbox__inner { + border: 1px solid var(--el-color-danger); + } + + .el-checkbox-button .el-checkbox-button__inner, + .el-radio-button .el-radio-button__inner { + border: 1px solid var(--el-color-danger); + } + + .el-checkbox-button:first-child .el-checkbox-button__inner, + .el-radio-button:first-child .el-radio-button__inner { + border-left: 1px solid var(--el-color-danger); + } + + .el-checkbox-button:not(:first-child) .el-checkbox-button__inner, + .el-radio-button:not(:first-child) .el-radio-button__inner { + border-left: none; + } + + .el-textarea .el-textarea__inner { + border: 1px solid var(--el-color-danger); + } +} + +html .el-loading-mask { + z-index: 1000; +} diff --git a/admin-ui/vue/packages/styles/src/global/index.scss b/admin-ui/vue/packages/styles/src/global/index.scss new file mode 100644 index 0000000..c7af9bb --- /dev/null +++ b/admin-ui/vue/packages/styles/src/global/index.scss @@ -0,0 +1 @@ +@use '@vben-core/design/bem' as *; diff --git a/admin-ui/vue/packages/styles/src/index.ts b/admin-ui/vue/packages/styles/src/index.ts new file mode 100644 index 0000000..b375456 --- /dev/null +++ b/admin-ui/vue/packages/styles/src/index.ts @@ -0,0 +1 @@ +import '@vben-core/design'; diff --git a/admin-ui/vue/packages/styles/src/naive/index.css b/admin-ui/vue/packages/styles/src/naive/index.css new file mode 100644 index 0000000..a775116 --- /dev/null +++ b/admin-ui/vue/packages/styles/src/naive/index.css @@ -0,0 +1,20 @@ +.form-valid-error { + .n-base-selection__state-border, + .n-input__state-border, + .n-radio-group__splitor { + border: var(--n-border-error); + } + + .n-radio-group .n-radio-button, + .n-radio-group .n-radio-group__splitor { + --n-button-border-color: rgb(255 56 96); + } + + .n-radio__dot { + --n-box-shadow: inset 0 0 0 1px rgb(255 56 96); + } + + .n-checkbox-box__border { + --n-border: 1px solid rgb(255 56 96); + } +} diff --git a/admin-ui/vue/packages/styles/tsconfig.json b/admin-ui/vue/packages/styles/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/styles/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/types/README.md b/admin-ui/vue/packages/types/README.md new file mode 100644 index 0000000..f796f31 --- /dev/null +++ b/admin-ui/vue/packages/types/README.md @@ -0,0 +1,20 @@ +# @vben/types + +用于多个 `app` 公用的工具类型,继承了 `@vben-core/typings` 的所有能力。业务上有通用的类型定义可以放在这里。 + +## 用法 + +### 添加依赖 + +```bash +# 进入目标应用目录,例如 apps/xxxx-app +# cd apps/xxxx-app +pnpm add @vben/types +``` + +### 使用 + +```ts +// 推荐加上 type +import type { SelectOption } from '@vben/types'; +``` diff --git a/admin-ui/vue/packages/types/global.d.ts b/admin-ui/vue/packages/types/global.d.ts new file mode 100644 index 0000000..d615b4c --- /dev/null +++ b/admin-ui/vue/packages/types/global.d.ts @@ -0,0 +1,32 @@ +import type { RouteMeta as IRouteMeta } from '@vben-core/typings'; + +import 'vue-router'; + +declare module 'vue-router' { + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + interface RouteMeta extends IRouteMeta {} +} + +export interface VbenAdminProAppConfigRaw { + VITE_GLOB_API_URL: string; + VITE_GLOB_CLIENT_ID: string; // 客户端ID +} + +interface AuthConfig { + dingding?: { + clientId: string; + corpId: string; + }; +} + +export interface ApplicationConfig { + apiURL: string; + auth: AuthConfig; + clientId: string; // 客户端ID +} + +declare global { + interface Window { + _VBEN_ADMIN_PRO_APP_CONF_: VbenAdminProAppConfigRaw; + } +} diff --git a/admin-ui/vue/packages/types/package.json b/admin-ui/vue/packages/types/package.json new file mode 100644 index 0000000..07dbca0 --- /dev/null +++ b/admin-ui/vue/packages/types/package.json @@ -0,0 +1,27 @@ +{ + "name": "@vben/types", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/types" + }, + "license": "MIT", + "type": "module", + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + }, + "./global": { + "types": "./global.d.ts" + } + }, + "dependencies": { + "@vben-core/typings": "workspace:*", + "vue": "catalog:", + "vue-router": "catalog:" + } +} diff --git a/admin-ui/vue/packages/types/src/index.ts b/admin-ui/vue/packages/types/src/index.ts new file mode 100644 index 0000000..1e266c4 --- /dev/null +++ b/admin-ui/vue/packages/types/src/index.ts @@ -0,0 +1,2 @@ +export type * from './user'; +export type * from '@vben-core/typings'; diff --git a/admin-ui/vue/packages/types/src/user.ts b/admin-ui/vue/packages/types/src/user.ts new file mode 100644 index 0000000..c5167c0 --- /dev/null +++ b/admin-ui/vue/packages/types/src/user.ts @@ -0,0 +1,30 @@ +import type { BasicUserInfo } from '@vben-core/typings'; + +/** 用户信息 */ +interface UserInfo extends BasicUserInfo { + /** + * 用户描述 + */ + desc: string; + /** + * 首页地址 + */ + homePath: string; + + /** + * accessToken + */ + token: string; + + /** + * 手机号(为空表示未绑定,登录后引导绑定) + */ + phonenumber?: string; + + /** + * 当前密码是否仍为系统初始密码(true 时引导首次登录修改密码) + */ + isInitPassword?: boolean; +} + +export type { UserInfo }; diff --git a/admin-ui/vue/packages/types/tsconfig.json b/admin-ui/vue/packages/types/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/admin-ui/vue/packages/types/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/packages/utils/README.md b/admin-ui/vue/packages/utils/README.md new file mode 100644 index 0000000..f06068a --- /dev/null +++ b/admin-ui/vue/packages/utils/README.md @@ -0,0 +1,19 @@ +# @vben/utils + +用于多个 `app` 公用的工具包,继承了 `@vben-core/shared/utils` 的所有能力。业务上有通用的工具函数可以放在这里。 + +## 用法 + +### 添加依赖 + +```bash +# 进入目标应用目录,例如 apps/xxxx-app +# cd apps/xxxx-app +pnpm add @vben/utils +``` + +### 使用 + +```ts +import { isString } from '@vben/utils'; +``` diff --git a/admin-ui/vue/packages/utils/package.json b/admin-ui/vue/packages/utils/package.json new file mode 100644 index 0000000..811f64c --- /dev/null +++ b/admin-ui/vue/packages/utils/package.json @@ -0,0 +1,28 @@ +{ + "name": "@vben/utils", + "version": "5.5.9", + "homepage": "https://github.com/vbenjs/vue-vben-admin", + "bugs": "https://github.com/vbenjs/vue-vben-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/vbenjs/vue-vben-admin.git", + "directory": "packages/utils" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@vben-core/shared": "workspace:*", + "@vben-core/typings": "workspace:*", + "file-type": "^19.5.0", + "vue-router": "catalog:" + } +} diff --git a/admin-ui/vue/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts b/admin-ui/vue/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts new file mode 100644 index 0000000..fc0d76b --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, it } from 'vitest'; + +import { findMenuByPath, findRootMenuByPath } from '../find-menu-by-path'; + +// 示例菜单数据 +const menus: any[] = [ + { path: '/', children: [] }, + { path: '/about', children: [] }, + { + path: '/contact', + children: [ + { path: '/contact/email', children: [] }, + { path: '/contact/phone', children: [] }, + ], + }, + { + path: '/services', + children: [ + { path: '/services/design', children: [] }, + { + path: '/services/development', + children: [{ path: '/services/development/web', children: [] }], + }, + ], + }, +]; + +describe('menu Finder Tests', () => { + it('finds a top-level menu', () => { + const menu = findMenuByPath(menus, '/about'); + expect(menu).toBeDefined(); + expect(menu?.path).toBe('/about'); + }); + + it('finds a nested menu', () => { + const menu = findMenuByPath(menus, '/services/development/web'); + expect(menu).toBeDefined(); + expect(menu?.path).toBe('/services/development/web'); + }); + + it('returns null for a non-existent path', () => { + const menu = findMenuByPath(menus, '/non-existent'); + expect(menu).toBeNull(); + }); + + it('handles empty menus list', () => { + const menu = findMenuByPath([], '/about'); + expect(menu).toBeNull(); + }); + + it('handles menu items without children', () => { + const menu = findMenuByPath( + [{ path: '/only', children: undefined }] as any[], + '/only', + ); + expect(menu).toBeDefined(); + expect(menu?.path).toBe('/only'); + }); + + it('finds root menu by path', () => { + const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath( + menus, + '/services/development/web', + ); + + expect(findMenu).toBeDefined(); + expect(rootMenu).toBeUndefined(); + expect(rootMenuPath).toBeUndefined(); + expect(findMenu?.path).toBe('/services/development/web'); + }); + + it('returns null for undefined or empty path', () => { + const menuUndefinedPath = findMenuByPath(menus); + const menuEmptyPath = findMenuByPath(menus, ''); + expect(menuUndefinedPath).toBeNull(); + expect(menuEmptyPath).toBeNull(); + }); + + it('checks for root menu when path does not exist', () => { + const { findMenu, rootMenu, rootMenuPath } = findRootMenuByPath( + menus, + '/non-existent', + ); + expect(findMenu).toBeNull(); + expect(rootMenu).toBeUndefined(); + expect(rootMenuPath).toBeUndefined(); + }); +}); diff --git a/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-menus.test.ts b/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-menus.test.ts new file mode 100644 index 0000000..9d98b5a --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-menus.test.ts @@ -0,0 +1,236 @@ +import type { Router, RouteRecordRaw } from 'vue-router'; + +import { createRouter, createWebHistory } from 'vue-router'; + +import { describe, expect, it, vi } from 'vitest'; + +import { generateMenus } from '../generate-menus'; + +// Nested route setup to test child inclusion and hideChildrenInMenu functionality + +describe('generateMenus', () => { + // 模拟路由数据 + const mockRoutes = [ + { + meta: { icon: 'home-icon', title: '首页' }, + name: 'home', + path: '/home', + }, + { + meta: { hideChildrenInMenu: true, icon: 'about-icon', title: '关于' }, + name: 'about', + path: '/about', + children: [ + { + path: 'team', + name: 'team', + meta: { icon: 'team-icon', title: '团队' }, + }, + ], + }, + ] as RouteRecordRaw[]; + + // 模拟 Vue 路由器实例 + const mockRouter = { + getRoutes: vi.fn(() => [ + { name: 'home', path: '/home' }, + { name: 'about', path: '/about' }, + { name: 'team', path: '/about/team' }, + ]), + }; + + it('the correct menu list should be generated according to the route', async () => { + const expectedMenus = [ + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: 'home-icon', + name: '首页', + order: undefined, + parent: undefined, + parents: undefined, + path: '/home', + show: true, + children: [], + }, + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: 'about-icon', + name: '关于', + order: undefined, + parent: undefined, + parents: undefined, + path: '/about', + show: true, + children: [], + }, + ]; + + const menus = await generateMenus(mockRoutes, mockRouter as any); + expect(menus).toEqual(expectedMenus); + }); + + it('includes additional meta properties in menu items', async () => { + const mockRoutesWithMeta = [ + { + meta: { icon: 'user-icon', order: 1, title: 'Profile' }, + name: 'profile', + path: '/profile', + }, + ] as RouteRecordRaw[]; + + const menus = await generateMenus(mockRoutesWithMeta, mockRouter as any); + expect(menus).toEqual([ + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: 'user-icon', + name: 'Profile', + order: 1, + parent: undefined, + parents: undefined, + path: '/profile', + show: true, + children: [], + }, + ]); + }); + + it('handles dynamic route parameters correctly', async () => { + const mockRoutesWithParams = [ + { + meta: { icon: 'details-icon', title: 'User Details' }, + name: 'userDetails', + path: '/users/:userId', + }, + ] as RouteRecordRaw[]; + + const menus = await generateMenus(mockRoutesWithParams, mockRouter as any); + expect(menus).toEqual([ + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: 'details-icon', + name: 'User Details', + order: undefined, + parent: undefined, + parents: undefined, + path: '/users/:userId', + show: true, + children: [], + }, + ]); + }); + + it('processes routes with redirects correctly', async () => { + const mockRoutesWithRedirect = [ + { + name: 'redirectedRoute', + path: '/old-path', + redirect: '/new-path', + }, + { + meta: { icon: 'path-icon', title: 'New Path' }, + name: 'newPath', + path: '/new-path', + }, + ] as RouteRecordRaw[]; + + const menus = await generateMenus( + mockRoutesWithRedirect, + mockRouter as any, + ); + expect(menus).toEqual([ + // Assuming your generateMenus function excludes redirect routes from the menu + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: undefined, + name: 'redirectedRoute', + order: undefined, + parent: undefined, + parents: undefined, + path: '/old-path', + show: true, + children: [], + }, + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: 'path-icon', + name: 'New Path', + order: undefined, + parent: undefined, + parents: undefined, + path: '/new-path', + show: true, + children: [], + }, + ]); + }); + + const routes: any = [ + { + meta: { order: 2, title: 'Home' }, + name: 'home', + path: '/', + }, + { + meta: { order: 1, title: 'About' }, + name: 'about', + path: '/about', + }, + ]; + + const router: Router = createRouter({ + history: createWebHistory(), + routes, + }); + + it('should generate menu list with correct order', async () => { + const menus = await generateMenus(routes, router); + const expectedMenus = [ + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: undefined, + name: 'About', + order: 1, + parent: undefined, + parents: undefined, + path: '/about', + show: true, + children: [], + }, + { + badge: undefined, + badgeType: undefined, + badgeVariants: undefined, + icon: undefined, + name: 'Home', + order: 2, + parent: undefined, + parents: undefined, + path: '/', + show: true, + children: [], + }, + ]; + + expect(menus).toEqual(expectedMenus); + }); + + it('should handle empty routes', async () => { + const emptyRoutes: any[] = []; + const menus = await generateMenus(emptyRoutes, router); + expect(menus).toEqual([]); + }); +}); diff --git a/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-routes-backend.test.ts b/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-routes-backend.test.ts new file mode 100644 index 0000000..45a79dc --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-routes-backend.test.ts @@ -0,0 +1,125 @@ +import { describe, expect, it, vi } from 'vitest'; + +import { generateRoutesByBackend } from '../generate-routes-backend'; + +// 布局组件与页面组件必须是不同对象:实现里用「引用是否相同」判断是不是布局 +const NullComponent = { render: () => null }; +const NullLayout = { render: () => null }; +const NullPage = { render: () => null }; + +const layoutMap = { + BasicLayout: NullLayout, + IFrameView: NullLayout, + LAYOUT: NullLayout, +}; +const pageMap = { '/iotlcm/tDashboard/index.vue': NullPage }; + +/** + * 后端菜单里可能存在指向已下线页面的菜单(前端无对应视图)。 + * 这类路由不应注册、也不应出现在菜单里,否则点进去就是一整页 404。 + */ +describe('generateRoutesByBackend 丢弃无对应视图的路由', () => { + it('丢弃解析不到视图的路由,并保留同级正常路由', async () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + try { + const routes = await generateRoutesByBackend({ + fetchMenuListAsync: async () => [ + { + children: [ + { + component: 'common/tDivisionCode/index', + name: 'menu_137', + path: 'index', + }, + { + component: 'iotlcm/tDashboard/index', + name: 'menu_ok', + path: 'dashboard', + }, + ], + component: 'LAYOUT', + name: 'Root', + path: '/', + }, + ], + layoutMap, + pageMap, + } as never); + + expect(routes).toHaveLength(1); + const children = routes[0]?.children ?? []; + expect(children.map((c) => c.name)).toEqual(['menu_ok']); + expect(warn).toHaveBeenCalledWith( + expect.stringContaining('route component is invalid, route skipped'), + expect.objectContaining({ name: 'menu_137' }), + ); + } finally { + warn.mockRestore(); + } + }); + + it('子路由被丢弃后,父目录若变空也一并去掉', async () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + try { + const routes = await generateRoutesByBackend({ + fetchMenuListAsync: async () => [ + { + children: [ + { + component: 'common/tDivisionCode/index', + name: 'menu_137', + path: 'index', + }, + ], + component: 'LAYOUT', + name: 'EmptyDir', + path: '/empty', + }, + { + component: 'iotlcm/tDashboard/index', + name: 'menu_ok', + path: '/ok', + }, + ], + layoutMap, + pageMap, + } as never); + + expect(routes.map((r) => r.name)).toEqual(['menu_ok']); + } finally { + warn.mockRestore(); + } + }); + + it('外链菜单(无组件但有 link)不会被丢弃', async () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + try { + const routes = await generateRoutesByBackend({ + fetchMenuListAsync: async () => [ + { + children: [ + { + meta: { + link: 'https://example.com/docs', + openInNewWindow: true, + }, + name: 'menu_link', + path: 'https://example.com/docs', + }, + ], + component: 'LAYOUT', + name: 'LinkDir', + path: '/links', + }, + ], + layoutMap, + pageMap, + } as never); + + expect(routes).toHaveLength(1); + expect(routes[0]?.children?.[0]?.name).toBe('menu_link'); + } finally { + warn.mockRestore(); + } + }); +}); diff --git a/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts b/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts new file mode 100644 index 0000000..8e01853 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts @@ -0,0 +1,105 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { describe, expect, it } from 'vitest'; + +import { + generateRoutesByFrontend, + hasAuthority, +} from '../generate-routes-frontend'; + +// Mock 路由数据 +const mockRoutes = [ + { + meta: { + authority: ['admin', 'user'], + hideInMenu: false, + }, + path: '/dashboard', + children: [ + { + path: '/dashboard/overview', + meta: { authority: ['admin'], hideInMenu: false }, + }, + { + path: '/dashboard/stats', + meta: { authority: ['user'], hideInMenu: true }, + }, + ], + }, + { + meta: { authority: ['admin'], hideInMenu: false }, + path: '/settings', + }, + { + meta: { hideInMenu: false }, + path: '/profile', + }, +] as RouteRecordRaw[]; + +describe('hasAuthority', () => { + it('should return true if there is no authority defined', () => { + expect(hasAuthority(mockRoutes[2], ['admin'])).toBe(true); + }); + + it('should return true if the user has the required authority', () => { + expect(hasAuthority(mockRoutes[0], ['admin'])).toBe(true); + }); + + it('should return false if the user does not have the required authority', () => { + expect(hasAuthority(mockRoutes[1], ['user'])).toBe(false); + }); +}); + +describe('generateRoutesByFrontend', () => { + it('should handle routes without children', async () => { + const generatedRoutes = await generateRoutesByFrontend(mockRoutes, [ + 'user', + ]); + expect(generatedRoutes).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + path: '/profile', // This route has no children and should be included + }), + ]), + ); + }); + + it('should handle empty roles array', async () => { + const generatedRoutes = await generateRoutesByFrontend(mockRoutes, []); + expect(generatedRoutes).toEqual( + expect.arrayContaining([ + // Only routes without authority should be included + expect.objectContaining({ + path: '/profile', + }), + ]), + ); + expect(generatedRoutes).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + path: '/dashboard', + }), + expect.objectContaining({ + path: '/settings', + }), + ]), + ); + }); + + it('should handle missing meta fields', async () => { + const routesWithMissingMeta = [ + { path: '/path1' }, // No meta + { meta: {}, path: '/path2' }, // Empty meta + { meta: { authority: ['admin'] }, path: '/path3' }, // Only authority + ]; + const generatedRoutes = await generateRoutesByFrontend( + routesWithMissingMeta as RouteRecordRaw[], + ['admin'], + ); + expect(generatedRoutes).toEqual([ + { path: '/path1' }, + { meta: {}, path: '/path2' }, + { meta: { authority: ['admin'] }, path: '/path3' }, + ]); + }); +}); diff --git a/admin-ui/vue/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts b/admin-ui/vue/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts new file mode 100644 index 0000000..3615556 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts @@ -0,0 +1,68 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import type { RouteModuleType } from '../merge-route-modules'; + +import { describe, expect, it } from 'vitest'; + +import { mergeRouteModules } from '../merge-route-modules'; + +describe('mergeRouteModules', () => { + it('should merge route modules correctly', () => { + const routeModules: Record = { + './dynamic-routes/about.ts': { + default: [ + { + component: () => Promise.resolve({ template: '
About
' }), + name: 'About', + path: '/about', + }, + ], + }, + './dynamic-routes/home.ts': { + default: [ + { + component: () => Promise.resolve({ template: '
Home
' }), + name: 'Home', + path: '/', + }, + ], + }, + }; + + const expectedRoutes: RouteRecordRaw[] = [ + { + component: expect.any(Function), + name: 'About', + path: '/about', + }, + { + component: expect.any(Function), + name: 'Home', + path: '/', + }, + ]; + + const mergedRoutes = mergeRouteModules(routeModules); + expect(mergedRoutes).toEqual(expectedRoutes); + }); + + it('should handle empty modules', () => { + const routeModules: Record = {}; + const expectedRoutes: RouteRecordRaw[] = []; + + const mergedRoutes = mergeRouteModules(routeModules); + expect(mergedRoutes).toEqual(expectedRoutes); + }); + + it('should handle modules with no default export', () => { + const routeModules: Record = { + './dynamic-routes/empty.ts': { + default: [], + }, + }; + const expectedRoutes: RouteRecordRaw[] = []; + + const mergedRoutes = mergeRouteModules(routeModules); + expect(mergedRoutes).toEqual(expectedRoutes); + }); +}); diff --git a/admin-ui/vue/packages/utils/src/helpers/file.ts b/admin-ui/vue/packages/utils/src/helpers/file.ts new file mode 100644 index 0000000..62bb7e5 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/file.ts @@ -0,0 +1,40 @@ +// 将base64转换为blob +export function dataURLtoBlob(base64Buf: string): Blob { + const arr = base64Buf.split(','); + const typeItem = arr[0]; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const mime = typeItem!.match(/:(.*?);/)![1]; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const bstr = window.atob(arr[1]!); + let n = bstr.length; + const u8arr = new Uint8Array(n); + while (n--) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + u8arr[n] = bstr.codePointAt(n)!; + } + return new Blob([u8arr], { type: mime }); +} +// // 将url转换为base64 +// export function urlToBase64(url: string, mineType?: string): Promise { +// return new Promise((resolve, reject) => { +// let canvas = document.createElement('CANVAS') as HTMLCanvasElement | null; +// // eslint-disable-next-line @typescript-eslint/no-non-null-assertion +// const ctx = canvas!.getContext('2d'); + +// const img = new Image(); +// img.crossOrigin = ''; +// img.addEventListener('load', () => { +// if (!canvas || !ctx) { +// // eslint-disable-next-line prefer-promise-reject-errors +// return reject(); +// } +// canvas.height = img.height; +// canvas.width = img.width; +// ctx.drawImage(img, 0, 0); +// const dataURL = canvas.toDataURL(mineType || 'image/png'); +// canvas = null; +// resolve(dataURL); +// }); +// img.src = url; +// }); +// } \ No newline at end of file diff --git a/admin-ui/vue/packages/utils/src/helpers/find-menu-by-path.ts b/admin-ui/vue/packages/utils/src/helpers/find-menu-by-path.ts new file mode 100644 index 0000000..747cc7f --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/find-menu-by-path.ts @@ -0,0 +1,37 @@ +import type { MenuRecordRaw } from '@vben-core/typings'; + +function findMenuByPath( + list: MenuRecordRaw[], + path?: string, +): MenuRecordRaw | null { + for (const menu of list) { + if (menu.path === path) { + return menu; + } + const findMenu = menu.children && findMenuByPath(menu.children, path); + if (findMenu) { + return findMenu; + } + } + return null; +} + +/** + * 查找根菜单 + * @param menus + * @param path + */ +function findRootMenuByPath(menus: MenuRecordRaw[], path?: string, level = 0) { + const findMenu = findMenuByPath(menus, path); + const rootMenuPath = findMenu?.parents?.[level]; + const rootMenu = rootMenuPath + ? menus.find((item) => item.path === rootMenuPath) + : undefined; + return { + findMenu, + rootMenu, + rootMenuPath, + }; +} + +export { findMenuByPath, findRootMenuByPath }; diff --git a/admin-ui/vue/packages/utils/src/helpers/generate-menus.ts b/admin-ui/vue/packages/utils/src/helpers/generate-menus.ts new file mode 100644 index 0000000..f13d599 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/generate-menus.ts @@ -0,0 +1,90 @@ +import type { Router, RouteRecordRaw } from 'vue-router'; + +import type { + ExRouteRecordRaw, + MenuRecordRaw, + RouteMeta, +} from '@vben-core/typings'; + +import { filterTree, mapTree, sortTree } from '@vben-core/shared/utils'; + +/** + * 根据 routes 生成菜单列表 + * @param routes - 路由配置列表 + * @param router - Vue Router 实例 + * @returns 生成的菜单列表 + */ +function generateMenus( + routes: RouteRecordRaw[], + router: Router, +): MenuRecordRaw[] { + // 将路由列表转换为一个以 name 为键的对象映射 + const finalRoutesMap: { [key: string]: string } = Object.fromEntries( + router.getRoutes().map(({ name, path }) => [name, path]), + ); + + let menus = mapTree(routes, (route) => { + // 获取最终的路由路径 + const path = finalRoutesMap[route.name as string] ?? route.path ?? ''; + + const { + meta = {} as RouteMeta, + name: routeName, + redirect, + children = [], + } = route; + const { + activeIcon, + badge, + badgeType, + badgeVariants, + hideChildrenInMenu = false, + icon, + link, + order, + title = '', + } = meta; + + // 确保菜单名称不为空 + const name = (title || routeName || '') as string; + + // 处理子菜单 + const resultChildren = hideChildrenInMenu + ? [] + : ((children as MenuRecordRaw[]) ?? []); + + // 设置子菜单的父子关系 + if (resultChildren.length > 0) { + resultChildren.forEach((child) => { + child.parents = [...(route.parents ?? []), path]; + child.parent = path; + }); + } + + // 确定最终路径 + const resultPath = hideChildrenInMenu ? redirect || path : link || path; + + return { + activeIcon, + badge, + badgeType, + badgeVariants, + icon, + name, + order, + parent: route.parent, + parents: route.parents, + path: resultPath, + show: !meta.hideInMenu, + children: resultChildren, + }; + }); + + // 对菜单进行排序,避免order=0时被替换成999的问题 + menus = sortTree(menus, (a, b) => (a?.order ?? 999) - (b?.order ?? 999)); + + // 过滤掉隐藏的菜单项 + return filterTree(menus, (menu) => !!menu.show); +} + +export { generateMenus }; diff --git a/admin-ui/vue/packages/utils/src/helpers/generate-routes-backend.ts b/admin-ui/vue/packages/utils/src/helpers/generate-routes-backend.ts new file mode 100644 index 0000000..b1d35f6 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/generate-routes-backend.ts @@ -0,0 +1,157 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import type { + ComponentRecordType, + GenerateMenuAndRoutesOptions, + RouteRecordStringComponent, +} from '@vben-core/typings'; + +import { mapTree } from '@vben-core/shared/utils'; + +/** + * 动态生成路由 - 后端方式 + */ +async function generateRoutesByBackend( + options: GenerateMenuAndRoutesOptions, +): Promise { + const { fetchMenuListAsync, layoutMap = {}, pageMap = {} } = options; + + try { + const menuRoutes = await fetchMenuListAsync?.(); + if (!menuRoutes) { + return []; + } + + const normalizePageMap: ComponentRecordType = {}; + + for (const [key, value] of Object.entries(pageMap)) { + normalizePageMap[normalizeViewPath(key)] = value; + } + + const routes = convertRoutes( + removePathlessRoutes(menuRoutes), + layoutMap, + normalizePageMap, + ); + + return routes; + } catch (error) { + console.error(error); + throw error; + } +} + +function removePathlessRoutes( + routes: RouteRecordStringComponent[], +): RouteRecordStringComponent[] { + return routes.flatMap((route) => { + const children = removePathlessRoutes(route.children ?? []); + if (!route.path?.trim()) { + console.warn('Skipping backend menu route with an empty path', { + name: route.name, + }); + return children; + } + + return [{ ...route, children }]; + }); +} + +function convertRoutes( + routes: RouteRecordStringComponent[], + layoutMap: ComponentRecordType, + pageMap: ComponentRecordType, +): RouteRecordRaw[] { + // 前端无对应视图、需丢弃的路由 + const invalidRoutes = new WeakSet(); + + const converted = mapTree(routes, (node) => { + const route = node as unknown as RouteRecordRaw; + const { component, name } = node; + + if (!name) { + console.error('route name is required', route); + } + + // layout转换 + if (component && layoutMap[component]) { + route.component = layoutMap[component]; + // 页面组件转换 + } else if (component) { + const normalizePath = normalizeViewPath(component); + const pageKey = normalizePath.endsWith('.vue') + ? normalizePath + : `${normalizePath}.vue`; + if (pageMap[pageKey]) { + route.component = pageMap[pageKey]; + } else { + // 前端没有对应视图(后端菜单指向了已不存在的页面)。 + // 这里不再替换成 not-found 组件——那样菜单还在、点进去却是 404 页面。 + // 直接标记丢弃:路由不注册、菜单里也不出现这个死链。 + console.warn(`route component is invalid, route skipped: ${pageKey}`, { + name, + path: node.path, + }); + invalidRoutes.add(route); + } + } + + return route; + }); + + return pruneInvalidRoutes(converted, layoutMap, invalidRoutes); +} + +/** + * 丢弃解析不到视图的路由;并去掉因此变空的目录。 + */ +function pruneInvalidRoutes( + routes: RouteRecordRaw[], + layoutMap: ComponentRecordType, + invalidRoutes: WeakSet, +): RouteRecordRaw[] { + return routes + .filter((route) => !invalidRoutes.has(route)) + .map((route) => { + if (!route.children) { + return route; + } + return { + ...route, + children: pruneInvalidRoutes(route.children, layoutMap, invalidRoutes), + }; + }) + .filter((route) => { + const children = route.children ?? []; + if (children.length > 0 || route.redirect) { + return true; + } + const meta = route.meta as Record | undefined; + // 外链菜单(新窗口打开)没有组件是正常的,不能丢 + if (meta?.openInNewWindow || meta?.link) { + return true; + } + // 只剩布局组件 = 变成了空目录,丢掉 + const isLayout = Object.values(layoutMap).includes( + route.component as never, + ); + if (isLayout) { + return false; + } + return Boolean(route.component); + }); +} + +function normalizeViewPath(path: string): string { + // 去除相对路径前缀 + const normalizedPath = path.replace(/^(\.\/|\.\.\/)+/, ''); + + // 确保路径以 '/' 开头 + const viewPath = normalizedPath.startsWith('/') + ? normalizedPath + : `/${normalizedPath}`; + + // 这里耦合了vben-admin的目录结构 + return viewPath.replace(/^\/views/, ''); +} +export { generateRoutesByBackend }; diff --git a/admin-ui/vue/packages/utils/src/helpers/generate-routes-frontend.ts b/admin-ui/vue/packages/utils/src/helpers/generate-routes-frontend.ts new file mode 100644 index 0000000..dafc8a7 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/generate-routes-frontend.ts @@ -0,0 +1,58 @@ +import type { RouteRecordRaw } from 'vue-router'; + +import { filterTree, mapTree } from '@vben-core/shared/utils'; + +/** + * 动态生成路由 - 前端方式 + */ +async function generateRoutesByFrontend( + routes: RouteRecordRaw[], + roles: string[], + forbiddenComponent?: RouteRecordRaw['component'], +): Promise { + // 根据角色标识过滤路由表,判断当前用户是否拥有指定权限 + const finalRoutes = filterTree(routes, (route) => { + return hasAuthority(route, roles); + }); + + if (!forbiddenComponent) { + return finalRoutes; + } + + // 如果有禁止访问的页面,将禁止访问的页面替换为403页面 + return mapTree(finalRoutes, (route) => { + if (menuHasVisibleWithForbidden(route)) { + route.component = forbiddenComponent; + } + return route; + }); +} + +/** + * 判断路由是否有权限访问 + * @param route + * @param access + */ +function hasAuthority(route: RouteRecordRaw, access: string[]) { + const authority = route.meta?.authority; + if (!authority) { + return true; + } + const canAccess = access.some((value) => authority.includes(value)); + + return canAccess || (!canAccess && menuHasVisibleWithForbidden(route)); +} + +/** + * 判断路由是否在菜单中显示,但是访问会被重定向到403 + * @param route + */ +function menuHasVisibleWithForbidden(route: RouteRecordRaw) { + return ( + !!route.meta?.authority && + Reflect.has(route.meta || {}, 'menuVisibleWithForbidden') && + !!route.meta?.menuVisibleWithForbidden + ); +} + +export { generateRoutesByFrontend, hasAuthority }; diff --git a/admin-ui/vue/packages/utils/src/helpers/get-popup-container.ts b/admin-ui/vue/packages/utils/src/helpers/get-popup-container.ts new file mode 100644 index 0000000..0640423 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/get-popup-container.ts @@ -0,0 +1,28 @@ +/** + * If the node is holding inside a form, return the form element, + * otherwise return the parent node of the given element or + * the document body if the element is not provided. + */ +export function getPopupContainer(node?: HTMLElement): HTMLElement { + return ( + node?.closest('form') ?? (node?.parentNode as HTMLElement) ?? document.body + ); +} + + +export function getVxePopupContainer( + _node?: HTMLElement, + id?: string, +): HTMLElement { + let selector = 'div.vxe-table--body-wrapper.body--wrapper'; + if (id) { + selector = `div#${id} ${selector}`; + } + // 挂载到vxe-table的滚动区域 + const vxeTableContainerNode = document.querySelector(selector); + if (!vxeTableContainerNode) { + console.warn('无法找到vxe-table元素, 将会挂载到body.'); + return document.body; + } + return vxeTableContainerNode as HTMLElement; +} diff --git a/admin-ui/vue/packages/utils/src/helpers/index.ts b/admin-ui/vue/packages/utils/src/helpers/index.ts new file mode 100644 index 0000000..e6292b8 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/index.ts @@ -0,0 +1,12 @@ +export * from './find-menu-by-path'; +export * from './generate-menus'; +export * from './generate-routes-backend'; +export * from './generate-routes-frontend'; +export * from './get-popup-container'; +export * from './merge-route-modules'; +export * from './reset-routes'; +export * from './unmount-global-loading'; +export * from './file'; +export * from './mitt'; +export * from './tree'; +export * from './uuid'; \ No newline at end of file diff --git a/admin-ui/vue/packages/utils/src/helpers/merge-route-modules.ts b/admin-ui/vue/packages/utils/src/helpers/merge-route-modules.ts new file mode 100644 index 0000000..53e21f3 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/merge-route-modules.ts @@ -0,0 +1,28 @@ +import type { RouteRecordRaw } from 'vue-router'; + +// 定义模块类型 +interface RouteModuleType { + default: RouteRecordRaw[]; +} + +/** + * 合并动态路由模块的默认导出 + * @param routeModules 动态导入的路由模块对象 + * @returns 合并后的路由配置数组 + */ +function mergeRouteModules( + routeModules: Record, +): RouteRecordRaw[] { + const mergedRoutes: RouteRecordRaw[] = []; + + for (const routeModule of Object.values(routeModules)) { + const moduleRoutes = (routeModule as RouteModuleType)?.default ?? []; + mergedRoutes.push(...moduleRoutes); + } + + return mergedRoutes; +} + +export { mergeRouteModules }; + +export type { RouteModuleType }; diff --git a/admin-ui/vue/packages/utils/src/helpers/mitt.ts b/admin-ui/vue/packages/utils/src/helpers/mitt.ts new file mode 100644 index 0000000..52be313 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/mitt.ts @@ -0,0 +1,135 @@ +/** + * copy to https://github.com/developit/mitt + * Expand clear method + */ +export type EventType = string | symbol; + +// An event handler can take an optional event argument +// and should not return a value +export type Handler = (event: T) => void; +export type WildcardHandler> = ( + type: keyof T, + event: T[keyof T], +) => void; + +// An array of all currently registered event handlers for a type +export type EventHandlerList = Array>; +export type WildCardEventHandlerList> = Array< + WildcardHandler +>; + +// A map of event types and their corresponding event handlers. +export type EventHandlerMap> = Map< + '*' | keyof Events, + EventHandlerList | WildCardEventHandlerList +>; + +export interface Emitter> { + all: EventHandlerMap; + + clear(): void; + emit( + type: undefined extends Events[Key] ? Key : never, + ): void; + + emit(type: Key, event: Events[Key]): void; + off(type: '*', handler: WildcardHandler): void; + + off( + type: Key, + handler?: Handler, + ): void; + on(type: '*', handler: WildcardHandler): void; + on(type: Key, handler: Handler): void; +} + +/** + * Mitt: Tiny (~200b) functional event emitter / pubsub. + * @name mitt + * @returns {Mitt} any + */ +export function mitt>( + all?: EventHandlerMap, +): Emitter { + type GenericEventHandler = + | Handler + | WildcardHandler; + all = all || new Map(); + + return { + /** + * A Map of event names to registered handler functions. + */ + all, + + /** + * Clear all + */ + clear() { + this.all.clear(); + }, + + /** + * Invoke all handlers for the given type. + * If present, `'*'` handlers are invoked after type-matched handlers. + * + * Note: Manually firing '*' handlers is not supported. + * + * @param {string|symbol} type The event type to invoke + * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler + * @memberOf mitt + */ + emit(type: Key, evt?: Events[Key]) { + let handlers = all?.get(type); + if (handlers) { + [...(handlers as EventHandlerList)].forEach( + (handler) => { + handler(evt as Events[Key]); + }, + ); + } + + handlers = all?.get('*'); + if (handlers) { + [...(handlers as WildCardEventHandlerList)].forEach( + (handler) => { + handler(type, evt as Events[Key]); + }, + ); + } + }, + + /** + * Remove an event handler for the given type. + * If `handler` is omitted, all handlers of the given type are removed. + * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler) + * @param {Function} [handler] Handler function to remove + * @memberOf mitt + */ + off(type: Key, handler?: GenericEventHandler) { + const handlers: Array | undefined = all?.get(type); + if (handlers) { + if (handler) { + handlers.splice(handlers.indexOf(handler) >>> 0, 1); + } else { + all?.set(type, []); + } + } + }, + + /** + * Register an event handler for the given type. + * @param {string|symbol} type Type of event to listen for, or `'*'` for all events + * @param {Function} handler Function to call in response to given event + * @memberOf mitt + */ + on(type: Key, handler: GenericEventHandler) { + const handlers: Array | undefined = all?.get(type); + if (handlers) { + handlers.push(handler); + } else { + all?.set(type, [handler] as EventHandlerList); + } + }, + }; +} diff --git a/admin-ui/vue/packages/utils/src/helpers/reset-routes.ts b/admin-ui/vue/packages/utils/src/helpers/reset-routes.ts new file mode 100644 index 0000000..0d53a00 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/reset-routes.ts @@ -0,0 +1,31 @@ +import type { Router, RouteRecordName, RouteRecordRaw } from 'vue-router'; + +import { traverseTreeValues } from '@vben-core/shared/utils'; + +/** + * @zh_CN 重置所有路由,如有指定白名单除外 + */ +export function resetStaticRoutes(router: Router, routes: RouteRecordRaw[]) { + // 获取静态路由所有节点包含子节点的 name,并排除不存在 name 字段的路由 + const staticRouteNames = traverseTreeValues< + RouteRecordRaw, + RouteRecordName | undefined + >(routes, (route) => { + // 这些路由需要指定 name,防止在路由重置时,不能删除没有指定 name 的路由 + if (!route.name) { + console.warn( + `The route with the path ${route.path} needs to have the field name specified.`, + ); + } + return route.name; + }); + + const { getRoutes, hasRoute, removeRoute } = router; + const allRoutes = getRoutes(); + allRoutes.forEach(({ name }) => { + // 存在于路由表且非白名单才需要删除 + if (name && !staticRouteNames.includes(name) && hasRoute(name)) { + removeRoute(name); + } + }); +} diff --git a/admin-ui/vue/packages/utils/src/helpers/tree.ts b/admin-ui/vue/packages/utils/src/helpers/tree.ts new file mode 100644 index 0000000..9b0f4b7 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/tree.ts @@ -0,0 +1,400 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +interface TreeHelperConfig { + children: string; + id: string; + pid: string; +} + +type Fn = (node: any, parentNode?: any) => any; + +// 默认配置 +const DEFAULT_CONFIG: TreeHelperConfig = { + id: 'id', + pid: 'parentId', + children: 'children', +}; + +// 获取配置。 Object.assign 从一个或多个源对象复制到目标对象 +const getConfig = (config: Partial) => + Object.assign({}, DEFAULT_CONFIG, config); + +// tree from list +// 列表中的树 +export function listToTree( + list: any[], + config: Partial = {}, +): T[] { + const conf = getConfig(config) as TreeHelperConfig; + const nodeMap = new Map(); + const result: T[] = []; + const { id, pid, children } = conf; + + for (const node of list) { + node[children] = node[children] || []; + nodeMap.set(node[id], node); + } + for (const node of list) { + const parent = nodeMap.get(node[pid]); + (parent ? parent[children] : result).push(node); + } + return result; +} + +export function treeToList( + tree: any, + config: Partial = {}, +): T { + config = getConfig(config); + const { children } = config; + const result: any = [...tree]; + for (let i = 0; i < result.length; i++) { + if (!result[i][children!]) continue; + result.splice(i + 1, 0, ...result[i][children!]); + } + return result; +} + +export function findNode( + tree: any, + func: Fn, + config: Partial = {}, +): null | T { + config = getConfig(config); + const { children } = config; + const list = [...tree]; + for (const node of list) { + if (func(node)) return node; + node[children!] && list.push(...node[children!]); + } + return null; +} + +export function findNodeAll( + tree: any, + func: Fn, + config: Partial = {}, +): T[] { + config = getConfig(config); + const { children } = config; + const list = [...tree]; + const result: T[] = []; + for (const node of list) { + func(node) && result.push(node); + node[children!] && list.push(...node[children!]); + } + return result; +} + +export function findPath( + tree: any, + func: Fn, + config: Partial = {}, +): null | T | T[] { + config = getConfig(config); + const path: T[] = []; + const list = [...tree]; + const visitedSet = new Set(); + const { children } = config; + while (list.length > 0) { + const node = list[0]; + if (visitedSet.has(node)) { + path.pop(); + list.shift(); + } else { + visitedSet.add(node); + node[children!] && list.unshift(...node[children!]); + path.push(node); + if (func(node)) { + return path; + } + } + } + return null; +} + +export function findPathAll( + tree: any, + func: Fn, + config: Partial = {}, +) { + config = getConfig(config); + const path: any[] = []; + const list = [...tree]; + const result: any[] = []; + const { children } = config; + const visitedSet = new Set(); + while (list.length > 0) { + const node = list[0]; + if (visitedSet.has(node)) { + path.pop(); + list.shift(); + } else { + visitedSet.add(node); + node[children!] && list.unshift(...node[children!]); + path.push(node); + func(node) && result.push([...path]); + } + } + return result; +} + +export function filter( + tree: T[], + func: (n: T) => boolean, + // Partial 将 T 中的所有属性设为可选 + config: Partial = {}, +): T[] { + // 获取配置 + config = getConfig(config); + const children = config.children as string; + + function listFilter(list: T[]) { + return list + .map((node: any) => ({ ...node })) + .filter((node) => { + // 递归调用 对含有children项 进行再次调用自身函数 listFilter + node[children] = node[children] && listFilter(node[children]); + // 执行传入的回调 func 进行过滤 + return func(node) || (node[children] && node[children].length > 0); + }); + } + + return listFilter(tree); +} + +export function forEach( + tree: T[], + func: (n: T) => any, + config: Partial = {}, +): void { + config = getConfig(config); + const list: any[] = [...tree]; + const { children } = config; + for (let i = 0; i < list.length; i++) { + // func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿 + if (func(list[i])) { + return; + } + children && + list[i][children] && + list.splice(i + 1, 0, ...list[i][children]); + } +} + +/** + * @description: Extract tree specified structure + * @description: 提取树指定结构 + */ +export function treeMap( + treeData: T[], + opt: { children?: string; conversion: Fn }, +): T[] { + return treeData.map((item) => treeMapEach(item, opt)); +} + +/** + * @description: Extract tree specified structure + * @description: 提取树指定结构 + */ +export function treeMapEach( + data: any, + { conversion, children = 'children' }: { children?: string; conversion: Fn }, +) { + const haveChildren = + Array.isArray(data[children]) && data[children].length > 0; + const conversionData = conversion(data) || {}; + return haveChildren + ? { + ...conversionData, + [children]: data[children].map((i: number) => + treeMapEach(i, { + children, + conversion, + }), + ), + } + : { + ...conversionData, + }; +} + +/** + * 递归遍历树结构 + * @param treeDatas 树 + * @param callBack 回调 + * @param parentNode 父节点 + */ +export function eachTree(treeDatas: any[], callBack: Fn, parentNode = {}) { + treeDatas.forEach((element) => { + const newNode = callBack(element, parentNode) || element; + if (element.children) { + eachTree(element.children, callBack, newNode); + } + }); +} + +// 如果节点的children为空, 则删除children属性 +export function removeEmptyChildren(data: any[], childrenField = 'children') { + data.forEach((item) => { + if (!item[childrenField]) { + return; + } + if (item[childrenField].length > 0) { + removeEmptyChildren(item[childrenField]); + } else { + Reflect.deleteProperty(item, childrenField); + } + }); +} + +// eslint-disable-next-line jsdoc/require-returns-check +/** + * + * 添加全名 如 祖先节点-父节点-子节点 + * @param treeData 已经是tree数据 + * @param labelName 标签的字段名称 + * @param splitStr 分隔符 + * @returns void 无返回值 会修改原始数据 + */ +export function addFullName( + treeData: any[], + labelName = 'label', + splitStr = '-', +) { + function addFullNameProperty(node: any, parentNames: any[] = []) { + const fullNameParts = [...parentNames, node[labelName]]; + node.fullName = fullNameParts.join(splitStr); + if (node.children && node.children.length > 0) { + node.children.forEach((childNode: any) => { + addFullNameProperty(childNode, fullNameParts); + }); + } + } + + treeData.forEach((item: any) => { + addFullNameProperty(item); + }); +} + +/** + * https://blog.csdn.net/Web_J/article/details/129281329 + * 给出节点nodeId 找到所有父节点ID + * @param treeList 树形结构list + * @param nodeId 要寻找的节点ID + * @param config config + * @returns 父节点ID数组 + */ +export function findParentsIds( + treeList: any[], + nodeId: number, + config: Partial = {}, +) { + const conf = getConfig(config) as TreeHelperConfig; + const { id, children } = conf; + + // 用于存储所有父节点ID的数组 + const parentIds: number[] = []; + + function traverse(node: any, nodeId: number) { + if (node[id] === nodeId) { + return true; + } + if (node[children]) { + // 如果当前节点有子节点,则继续遍历子节点 + for (const childNode of node[children]) { + if (traverse(childNode, nodeId)) { + // 如果在子节点中找到了子节点的父节点,则将当前节点的ID添加到父节点ID数组中,并返回true表示已经找到了子节点 + parentIds.push(node[id]); + return true; + } + } + } + return false; + } + + for (const node of treeList) { + if (traverse(node, nodeId)) { + // 如果在当前节点的子树中找到了子节点的父节点,则直接退出循环 + break; + } + } + + return parentIds.sort(); +} + +/** + * 给出节点数组 找到所有父节点ID + * @param treeList 树形结构list + * @param nodeIds 要寻找的节点ID list + * @param config config + * @returns 父节点ID数组 + */ +export function findGroupParentIds( + treeList: any[], + nodeIds: number[], + config: Partial = {}, +) { + // 用于存储所有父节点ID的Set 主要为了去重 + const parentIds = new Set(); + + nodeIds.forEach((nodeId) => { + findParentsIds(treeList, nodeId, config).forEach((parentId) => { + parentIds.add(parentId); + }); + }); + + return [...parentIds].sort(); +} + +/** + * 找到所有ID 返回数组 + * @param treeList list + * @param config + * @returns ID数组 + */ +export function findAllIds( + treeList: any[], + config: Partial = DEFAULT_CONFIG, +) { + const conf = getConfig(config) as TreeHelperConfig; + const { id, children } = conf; + const ids: number[] = []; + + treeList.forEach((item) => { + if (item[children]) { + const tempIds = findAllIds(item[children], config); + ids.push(...tempIds); + } + ids.push(item[id]); + }); + + return [...ids].sort(); +} + +/** + * @description 这里抄的filterByLevel函数 + * @description 主要用于获取指定层级的节点数组 + */ +export function findIdsByLevel( + level = 1, + list?: any[], + config: Partial = DEFAULT_CONFIG, + currentLevel = 1, +) { + if (!level) { + return []; + } + const res: (number | string)[] = []; + const data = list || []; + for (const item of data) { + const { id: keyField, children: childrenField } = config; + const key = keyField ? item[keyField] : ''; + const children = childrenField ? item[childrenField] : []; + res.push(key); + if (children && children.length > 0 && currentLevel < level) { + currentLevel += 1; + res.push(...findIdsByLevel(level, children, config, currentLevel)); + } + } + return res as number[] | string[]; +} diff --git a/admin-ui/vue/packages/utils/src/helpers/unmount-global-loading.ts b/admin-ui/vue/packages/utils/src/helpers/unmount-global-loading.ts new file mode 100644 index 0000000..10b88ea --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/unmount-global-loading.ts @@ -0,0 +1,31 @@ +/** + * 移除并销毁loading + * 放在这里是而不是放在 index.html 的app标签内,是因为这样比较不会生硬,渲染过快可能会有闪烁 + * 通过先添加css动画隐藏,在动画结束后在移除loading节点来改善体验 + * 不好的地方是会增加一些代码量 + * 自定义loading可以见:https://doc.vben.pro/guide/in-depth/loading.html + */ +export function unmountGlobalLoading() { + // 查找全局 loading 元素 + const loadingElement = document.querySelector('#__app-loading__'); + + if (loadingElement) { + // 添加隐藏类,触发过渡动画 + loadingElement.classList.add('hidden'); + + // 查找所有需要移除的注入 loading 元素 + const injectLoadingElements = document.querySelectorAll( + '[data-app-loading^="inject"]', + ); + + // 当过渡动画结束时,移除 loading 元素和所有注入的 loading 元素 + loadingElement.addEventListener( + 'transitionend', + () => { + loadingElement.remove(); // 移除 loading 元素 + injectLoadingElements.forEach((el) => el.remove()); // 移除所有注入的 loading 元素 + }, + { once: true }, + ); // 确保事件只触发一次 + } +} diff --git a/admin-ui/vue/packages/utils/src/helpers/uuid.ts b/admin-ui/vue/packages/utils/src/helpers/uuid.ts new file mode 100644 index 0000000..81c49a0 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/helpers/uuid.ts @@ -0,0 +1,42 @@ +const hexList: string[] = []; +for (let i = 0; i <= 15; i++) { + hexList[i] = i.toString(16); +} + +export function buildUUID(): string { + let uuid = ''; + for (let i = 1; i <= 36; i++) { + switch (i) { + case 9: + case 14: + case 19: + case 24: { + uuid += '-'; + + break; + } + case 15: { + uuid += 4; + + break; + } + case 20: { + uuid += hexList[(Math.random() * 4) | 8]; + + break; + } + default: { + uuid += hexList[Math.trunc(Math.random() * 16)]; + } + } + } + return uuid.replaceAll('-', ''); +} + +let unique = 0; +export function buildShortUUID(prefix = ''): string { + const time = Date.now(); + const random = Math.floor(Math.random() * 1_000_000_000); + unique++; + return `${prefix}_${random}${unique}${String(time)}`; +} diff --git a/admin-ui/vue/packages/utils/src/index.ts b/admin-ui/vue/packages/utils/src/index.ts new file mode 100644 index 0000000..dd84fa7 --- /dev/null +++ b/admin-ui/vue/packages/utils/src/index.ts @@ -0,0 +1,5 @@ +export * from './helpers'; +export * from '@vben-core/shared/cache'; +export * from '@vben-core/shared/color'; +export * from '@vben-core/shared/utils'; +export { fileTypeFromBlob } from 'file-type'; diff --git a/admin-ui/vue/packages/utils/tsconfig.json b/admin-ui/vue/packages/utils/tsconfig.json new file mode 100644 index 0000000..255148a --- /dev/null +++ b/admin-ui/vue/packages/utils/tsconfig.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/library.json", + "compilerOptions": { + "types": ["@vben-core/typings/vue-router"] + }, + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/pnpm-lock.yaml b/admin-ui/vue/pnpm-lock.yaml new file mode 100644 index 0000000..1673764 --- /dev/null +++ b/admin-ui/vue/pnpm-lock.yaml @@ -0,0 +1,19158 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +catalogs: + default: + '@changesets/changelog-github': + specifier: ^0.5.1 + version: 0.5.2 + '@changesets/cli': + specifier: ^2.29.7 + version: 2.29.8 + '@changesets/git': + specifier: ^3.0.4 + version: 3.0.4 + '@clack/prompts': + specifier: ^0.11.0 + version: 0.11.0 + '@commitlint/cli': + specifier: ^19.8.1 + version: 19.8.1 + '@commitlint/config-conventional': + specifier: ^19.8.1 + version: 19.8.1 + '@eslint/js': + specifier: ^9.39.1 + version: 9.39.2 + '@iconify/json': + specifier: ^2.2.406 + version: 2.2.417 + '@iconify/tailwind': + specifier: ^1.2.0 + version: 1.2.0 + '@iconify/vue': + specifier: ^5.0.0 + version: 5.0.0 + '@intlify/core-base': + specifier: ^11.1.7 + version: 11.2.7 + '@intlify/unplugin-vue-i18n': + specifier: ^6.0.8 + version: 6.0.8 + '@jspm/generator': + specifier: ^2.6.2 + version: 2.8.0 + '@manypkg/get-packages': + specifier: ^3.0.0 + version: 3.1.0 + '@playwright/test': + specifier: ^1.56.1 + version: 1.57.0 + '@pnpm/workspace.read-manifest': + specifier: ^1000.2.6 + version: 1000.2.9 + '@stylistic/stylelint-plugin': + specifier: ^3.1.3 + version: 3.1.3 + '@tailwindcss/nesting': + specifier: 0.0.0-insiders.565cd3e + version: 0.0.0-insiders.565cd3e + '@tailwindcss/typography': + specifier: ^0.5.16 + version: 0.5.19 + '@tanstack/vue-store': + specifier: ^0.8.0 + version: 0.8.0 + '@types/archiver': + specifier: ^6.0.3 + version: 6.0.4 + '@types/eslint': + specifier: ^9.6.1 + version: 9.6.1 + '@types/html-minifier-terser': + specifier: ^7.0.2 + version: 7.0.2 + '@types/lodash.clonedeep': + specifier: ^4.5.9 + version: 4.5.9 + '@types/lodash.get': + specifier: ^4.4.9 + version: 4.4.9 + '@types/lodash.isequal': + specifier: ^4.5.8 + version: 4.5.8 + '@types/lodash.set': + specifier: ^4.3.9 + version: 4.3.9 + '@types/node': + specifier: ^24.10.1 + version: 24.10.4 + '@types/nprogress': + specifier: ^0.2.3 + version: 0.2.3 + '@types/postcss-import': + specifier: ^14.0.3 + version: 14.0.3 + '@types/qrcode': + specifier: ^1.5.5 + version: 1.5.6 + '@types/qs': + specifier: ^6.14.0 + version: 6.14.0 + '@types/sortablejs': + specifier: ^1.15.8 + version: 1.15.9 + '@typescript-eslint/eslint-plugin': + specifier: ^8.46.4 + version: 8.50.1 + '@typescript-eslint/parser': + specifier: ^8.46.4 + version: 8.50.1 + '@vee-validate/zod': + specifier: ^4.15.1 + version: 4.15.1 + '@vitejs/plugin-vue': + specifier: ^6.0.1 + version: 6.0.3 + '@vitejs/plugin-vue-jsx': + specifier: ^5.1.1 + version: 5.1.3 + '@vue/shared': + specifier: ^3.5.24 + version: 3.5.26 + '@vue/test-utils': + specifier: ^2.4.6 + version: 2.4.6 + '@vueuse/core': + specifier: ^13.4.0 + version: 13.9.0 + '@vueuse/integrations': + specifier: ^14.0.0 + version: 14.1.0 + '@vueuse/motion': + specifier: ^3.0.3 + version: 3.0.3 + ant-design-vue: + specifier: ^4.2.6 + version: 4.2.6 + archiver: + specifier: ^7.0.1 + version: 7.0.1 + autoprefixer: + specifier: ^10.4.22 + version: 10.4.23 + axios: + specifier: ^1.10.0 + version: 1.13.2 + axios-mock-adapter: + specifier: ^2.1.0 + version: 2.1.0 + cac: + specifier: ^6.7.14 + version: 6.7.14 + chalk: + specifier: ^5.4.1 + version: 5.6.2 + cheerio: + specifier: ^1.1.0 + version: 1.1.2 + circular-dependency-scanner: + specifier: ^2.3.0 + version: 2.3.0 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + commitlint-plugin-function-rules: + specifier: ^4.1.1 + version: 4.2.0 + consola: + specifier: ^3.4.2 + version: 3.4.2 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + cspell: + specifier: ^8.19.4 + version: 8.19.4 + cssnano: + specifier: ^7.0.7 + version: 7.1.2 + cz-git: + specifier: ^1.11.2 + version: 1.12.0 + czg: + specifier: ^1.11.1 + version: 1.12.0 + dayjs: + specifier: ^1.11.13 + version: 1.11.19 + defu: + specifier: ^6.1.4 + version: 6.1.4 + depcheck: + specifier: ^1.4.7 + version: 1.4.7 + dotenv: + specifier: ^16.6.1 + version: 16.6.1 + echarts: + specifier: ^6.0.0 + version: 6.0.0 + es-toolkit: + specifier: ^1.41.0 + version: 1.43.0 + eslint: + specifier: ^9.39.1 + version: 9.39.2 + eslint-config-turbo: + specifier: ^2.6.1 + version: 2.7.2 + eslint-plugin-command: + specifier: ^3.3.1 + version: 3.4.0 + eslint-plugin-eslint-comments: + specifier: ^3.2.0 + version: 3.2.0 + eslint-plugin-import-x: + specifier: ^4.16.1 + version: 4.16.1 + eslint-plugin-jsdoc: + specifier: ^61.2.1 + version: 61.5.0 + eslint-plugin-jsonc: + specifier: ^2.21.0 + version: 2.21.0 + eslint-plugin-n: + specifier: ^17.23.1 + version: 17.23.1 + eslint-plugin-no-only-tests: + specifier: ^3.3.0 + version: 3.3.0 + eslint-plugin-perfectionist: + specifier: ^4.15.1 + version: 4.15.1 + eslint-plugin-prettier: + specifier: ^5.5.4 + version: 5.5.4 + eslint-plugin-regexp: + specifier: ^2.10.0 + version: 2.10.0 + eslint-plugin-unicorn: + specifier: ^62.0.0 + version: 62.0.0 + eslint-plugin-unused-imports: + specifier: ^4.3.0 + version: 4.3.0 + eslint-plugin-vitest: + specifier: ^0.5.4 + version: 0.5.4 + eslint-plugin-vue: + specifier: ^10.5.1 + version: 10.6.2 + execa: + specifier: ^9.6.0 + version: 9.6.1 + find-up: + specifier: ^7.0.0 + version: 7.0.0 + get-port: + specifier: ^7.1.0 + version: 7.1.0 + globals: + specifier: ^16.3.0 + version: 16.5.0 + happy-dom: + specifier: ^17.6.3 + version: 17.6.3 + html-minifier-terser: + specifier: ^7.2.0 + version: 7.2.0 + is-ci: + specifier: ^4.1.0 + version: 4.1.0 + json-bigint: + specifier: ^1.0.0 + version: 1.0.0 + jsonc-eslint-parser: + specifier: ^2.4.1 + version: 2.4.2 + lefthook: + specifier: ^1.13.6 + version: 1.13.6 + lodash.clonedeep: + specifier: ^4.5.0 + version: 4.5.0 + lucide-vue-next: + specifier: ^0.553.0 + version: 0.553.0 + nitropack: + specifier: ^2.11.13 + version: 2.12.9 + nprogress: + specifier: ^0.2.0 + version: 0.2.0 + ora: + specifier: ^8.2.0 + version: 8.2.0 + pinia-plugin-persistedstate: + specifier: ^4.4.1 + version: 4.7.1 + pkg-types: + specifier: ^2.2.0 + version: 2.3.0 + playwright: + specifier: ^1.56.1 + version: 1.57.0 + postcss: + specifier: ^8.5.6 + version: 8.5.6 + postcss-antd-fixes: + specifier: ^0.2.0 + version: 0.2.0 + postcss-html: + specifier: ^1.8.0 + version: 1.8.0 + postcss-import: + specifier: ^16.1.1 + version: 16.1.1 + postcss-preset-env: + specifier: ^10.2.4 + version: 10.5.0 + postcss-scss: + specifier: ^4.0.9 + version: 4.0.9 + prettier: + specifier: ^3.6.2 + version: 3.7.4 + prettier-plugin-tailwindcss: + specifier: ^0.7.1 + version: 0.7.2 + publint: + specifier: ^0.3.12 + version: 0.3.16 + qrcode: + specifier: ^1.5.4 + version: 1.5.4 + qs: + specifier: ^6.14.0 + version: 6.14.0 + reka-ui: + specifier: ^2.6.0 + version: 2.7.0 + resolve.exports: + specifier: ^2.0.3 + version: 2.0.3 + rimraf: + specifier: ^6.1.0 + version: 6.1.2 + rollup: + specifier: ^4.44.1 + version: 4.54.0 + rollup-plugin-visualizer: + specifier: ^5.14.0 + version: 5.14.0 + sass: + specifier: ^1.94.0 + version: 1.97.1 + secure-ls: + specifier: ^2.0.0 + version: 2.0.0 + sortablejs: + specifier: ^1.15.6 + version: 1.15.6 + stylelint: + specifier: ^16.21.0 + version: 16.26.1 + stylelint-config-recess-order: + specifier: ^6.1.0 + version: 6.1.0 + stylelint-config-recommended: + specifier: ^17.0.0 + version: 17.0.0 + stylelint-config-recommended-scss: + specifier: ^14.1.0 + version: 14.1.0 + stylelint-config-recommended-vue: + specifier: ^1.6.1 + version: 1.6.1 + stylelint-config-standard: + specifier: ^38.0.0 + version: 38.0.0 + stylelint-order: + specifier: ^7.0.0 + version: 7.0.0 + stylelint-prettier: + specifier: ^5.0.3 + version: 5.0.3 + stylelint-scss: + specifier: ^6.12.1 + version: 6.13.0 + tailwind-merge: + specifier: ^2.6.0 + version: 2.6.0 + tailwindcss: + specifier: ^3.4.18 + version: 3.4.19 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7 + theme-colors: + specifier: ^0.1.0 + version: 0.1.0 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 + turbo: + specifier: ^2.6.1 + version: 2.7.2 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + unbuild: + specifier: ^3.6.1 + version: 3.6.1 + vee-validate: + specifier: ^4.15.1 + version: 4.15.1 + vite: + specifier: ^7.2.2 + version: 7.3.0 + vite-plugin-compression: + specifier: ^0.5.1 + version: 0.5.1 + vite-plugin-dts: + specifier: ^4.5.4 + version: 4.5.4 + vite-plugin-html: + specifier: ^3.2.2 + version: 3.2.2 + vite-plugin-lazy-import: + specifier: ^1.0.7 + version: 1.0.7 + vite-plugin-pwa: + specifier: ^1.0.1 + version: 1.2.0 + vite-plugin-vue-devtools: + specifier: ^8.0.3 + version: 8.0.5 + vitest: + specifier: ^3.2.4 + version: 3.2.4 + vue-eslint-parser: + specifier: ^10.2.0 + version: 10.2.0 + vue-i18n: + specifier: ^11.1.7 + version: 11.2.7 + vue-json-viewer: + specifier: ^3.0.4 + version: 3.0.4 + vue-router: + specifier: ^4.5.1 + version: 4.6.4 + vue-tippy: + specifier: ^6.7.1 + version: 6.7.1 + vue-tsc: + specifier: ^3.1.4 + version: 3.2.1 + vxe-pc-ui: + specifier: ^4.10.22 + version: 4.11.17 + vxe-table: + specifier: ^4.17.14 + version: 4.17.33 + watermark-js-plus: + specifier: ^1.6.2 + version: 1.6.3 + zod: + specifier: ^3.25.67 + version: 3.25.76 + zod-defaults: + specifier: 0.1.3 + version: 0.1.3 + +overrides: + '@ast-grep/napi': ^0.39.9 + '@ctrl/tinycolor': ^4.1.0 + clsx: ^2.1.1 + esbuild: 0.25.3 + jiti: ^2.6.1 + pinia: ^3.0.3 + vue: ^3.5.24 + +importers: + + .: + devDependencies: + '@changesets/changelog-github': + specifier: 'catalog:' + version: 0.5.2 + '@changesets/cli': + specifier: 'catalog:' + version: 2.29.8(@types/node@24.10.4) + '@playwright/test': + specifier: 'catalog:' + version: 1.57.0 + '@types/node': + specifier: 'catalog:' + version: 24.10.4 + '@vben/commitlint-config': + specifier: workspace:* + version: link:internal/lint-configs/commitlint-config + '@vben/eslint-config': + specifier: workspace:* + version: link:internal/lint-configs/eslint-config + '@vben/prettier-config': + specifier: workspace:* + version: link:internal/lint-configs/prettier-config + '@vben/stylelint-config': + specifier: workspace:* + version: link:internal/lint-configs/stylelint-config + '@vben/tailwind-config': + specifier: workspace:* + version: link:internal/tailwind-config + '@vben/tsconfig': + specifier: workspace:* + version: link:internal/tsconfig + '@vben/turbo-run': + specifier: workspace:* + version: link:scripts/turbo-run + '@vben/vite-config': + specifier: workspace:* + version: link:internal/vite-config + '@vben/vsh': + specifier: workspace:* + version: link:scripts/vsh + '@vitejs/plugin-vue': + specifier: 'catalog:' + version: 6.0.3(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': + specifier: 'catalog:' + version: 5.1.3(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + '@vue/test-utils': + specifier: 'catalog:' + version: 2.4.6 + autoprefixer: + specifier: 'catalog:' + version: 10.4.23(postcss@8.5.6) + cross-env: + specifier: 'catalog:' + version: 7.0.3 + cspell: + specifier: 'catalog:' + version: 8.19.4 + happy-dom: + specifier: 'catalog:' + version: 17.6.3 + is-ci: + specifier: 'catalog:' + version: 4.1.0 + lefthook: + specifier: 'catalog:' + version: 1.13.6 + playwright: + specifier: 'catalog:' + version: 1.57.0 + rimraf: + specifier: 'catalog:' + version: 6.1.2 + tailwindcss: + specifier: 'catalog:' + version: 3.4.19(yaml@2.8.2) + turbo: + specifier: 'catalog:' + version: 2.7.2 + typescript: + specifier: 'catalog:' + version: 5.9.3 + unbuild: + specifier: 'catalog:' + version: 3.6.1(sass@1.97.1)(typescript@5.9.3)(vue-tsc@3.2.1(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3)) + vite: + specifier: 'catalog:' + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vitest: + specifier: 'catalog:' + version: 3.2.4(@types/node@24.10.4)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-tsc: + specifier: 'catalog:' + version: 3.2.1(typescript@5.9.3) + + apps/web-antd: + dependencies: + '@highlightjs/vue-plugin': + specifier: ^2.1.0 + version: 2.1.0(highlight.js@11.11.1)(vue@3.5.26(typescript@5.9.3)) + '@tinymce/tinymce-vue': + specifier: ^6.1.0 + version: 6.3.0(tinymce@7.9.1)(vue@3.5.26(typescript@5.9.3)) + '@vben/access': + specifier: workspace:* + version: link:../../packages/effects/access + '@vben/common-ui': + specifier: workspace:* + version: link:../../packages/effects/common-ui + '@vben/constants': + specifier: workspace:* + version: link:../../packages/constants + '@vben/hooks': + specifier: workspace:* + version: link:../../packages/effects/hooks + '@vben/icons': + specifier: workspace:* + version: link:../../packages/icons + '@vben/layouts': + specifier: workspace:* + version: link:../../packages/effects/layouts + '@vben/locales': + specifier: workspace:* + version: link:../../packages/locales + '@vben/plugins': + specifier: workspace:* + version: link:../../packages/effects/plugins + '@vben/preferences': + specifier: workspace:* + version: link:../../packages/preferences + '@vben/request': + specifier: workspace:* + version: link:../../packages/effects/request + '@vben/stores': + specifier: workspace:* + version: link:../../packages/stores + '@vben/styles': + specifier: workspace:* + version: link:../../packages/styles + '@vben/types': + specifier: workspace:* + version: link:../../packages/types + '@vben/utils': + specifier: workspace:* + version: link:../../packages/utils + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + ant-design-vue: + specifier: 'catalog:' + version: 4.2.6(vue@3.5.26(typescript@5.9.3)) + cropperjs: + specifier: ^1.6.2 + version: 1.6.2 + dayjs: + specifier: 'catalog:' + version: 1.11.19 + highlight.js: + specifier: ^11.11.1 + version: 11.11.1 + js-md5: + specifier: ^0.8.3 + version: 0.8.3 + lodash-es: + specifier: ^4.17.21 + version: 4.17.22 + pinia: + specifier: ^3.0.3 + version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) + tinymce: + specifier: ^7.3.0 + version: 7.9.1 + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + devDependencies: + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 + + internal/lint-configs/commitlint-config: + dependencies: + '@commitlint/cli': + specifier: 'catalog:' + version: 19.8.1(@types/node@25.0.3)(typescript@5.9.3) + '@commitlint/config-conventional': + specifier: 'catalog:' + version: 19.8.1 + '@vben/node-utils': + specifier: workspace:* + version: link:../../node-utils + commitlint-plugin-function-rules: + specifier: 'catalog:' + version: 4.2.0(@commitlint/lint@19.8.1) + cz-git: + specifier: 'catalog:' + version: 1.12.0 + czg: + specifier: 'catalog:' + version: 1.12.0 + + internal/lint-configs/eslint-config: + dependencies: + eslint-config-turbo: + specifier: 'catalog:' + version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.2) + eslint-plugin-command: + specifier: 'catalog:' + version: 3.4.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import-x: + specifier: 'catalog:' + version: 4.16.1(@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + devDependencies: + '@eslint/js': + specifier: 'catalog:' + version: 9.39.2 + '@types/eslint': + specifier: 'catalog:' + version: 9.6.1 + '@typescript-eslint/eslint-plugin': + specifier: 'catalog:' + version: 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: 'catalog:' + version: 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: + specifier: 'catalog:' + version: 9.39.2(jiti@2.6.1) + eslint-plugin-eslint-comments: + specifier: 'catalog:' + version: 3.2.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-jsdoc: + specifier: 'catalog:' + version: 61.5.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-jsonc: + specifier: 'catalog:' + version: 2.21.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-n: + specifier: 'catalog:' + version: 17.23.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-no-only-tests: + specifier: 'catalog:' + version: 3.3.0 + eslint-plugin-perfectionist: + specifier: 'catalog:' + version: 4.15.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-prettier: + specifier: 'catalog:' + version: 5.5.4(@types/eslint@9.6.1)(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4) + eslint-plugin-regexp: + specifier: 'catalog:' + version: 2.10.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-unicorn: + specifier: 'catalog:' + version: 62.0.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-unused-imports: + specifier: 'catalog:' + version: 4.3.0(@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-vitest: + specifier: 'catalog:' + version: 0.5.4(@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@25.0.3)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + eslint-plugin-vue: + specifier: 'catalog:' + version: 10.6.2(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))) + globals: + specifier: 'catalog:' + version: 16.5.0 + jsonc-eslint-parser: + specifier: 'catalog:' + version: 2.4.2 + vue-eslint-parser: + specifier: 'catalog:' + version: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + + internal/lint-configs/prettier-config: + dependencies: + prettier: + specifier: 'catalog:' + version: 3.7.4 + prettier-plugin-tailwindcss: + specifier: 'catalog:' + version: 0.7.2(prettier@3.7.4) + + internal/lint-configs/stylelint-config: + dependencies: + '@stylistic/stylelint-plugin': + specifier: 'catalog:' + version: 3.1.3(stylelint@16.26.1(typescript@5.9.3)) + stylelint-config-recess-order: + specifier: 'catalog:' + version: 6.1.0(stylelint@16.26.1(typescript@5.9.3)) + stylelint-scss: + specifier: 'catalog:' + version: 6.13.0(stylelint@16.26.1(typescript@5.9.3)) + devDependencies: + postcss: + specifier: 'catalog:' + version: 8.5.6 + postcss-html: + specifier: 'catalog:' + version: 1.8.0 + postcss-scss: + specifier: 'catalog:' + version: 4.0.9(postcss@8.5.6) + prettier: + specifier: 'catalog:' + version: 3.7.4 + stylelint: + specifier: 'catalog:' + version: 16.26.1(typescript@5.9.3) + stylelint-config-recommended: + specifier: 'catalog:' + version: 17.0.0(stylelint@16.26.1(typescript@5.9.3)) + stylelint-config-recommended-scss: + specifier: 'catalog:' + version: 14.1.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)) + stylelint-config-recommended-vue: + specifier: 'catalog:' + version: 1.6.1(postcss-html@1.8.0)(stylelint@16.26.1(typescript@5.9.3)) + stylelint-config-standard: + specifier: 'catalog:' + version: 38.0.0(stylelint@16.26.1(typescript@5.9.3)) + stylelint-order: + specifier: 'catalog:' + version: 7.0.0(stylelint@16.26.1(typescript@5.9.3)) + stylelint-prettier: + specifier: 'catalog:' + version: 5.0.3(prettier@3.7.4)(stylelint@16.26.1(typescript@5.9.3)) + + internal/node-utils: + dependencies: + '@changesets/git': + specifier: 'catalog:' + version: 3.0.4 + '@manypkg/get-packages': + specifier: 'catalog:' + version: 3.1.0 + chalk: + specifier: 'catalog:' + version: 5.6.2 + consola: + specifier: 'catalog:' + version: 3.4.2 + dayjs: + specifier: 'catalog:' + version: 1.11.19 + execa: + specifier: 'catalog:' + version: 9.6.1 + find-up: + specifier: 'catalog:' + version: 7.0.0 + ora: + specifier: 'catalog:' + version: 8.2.0 + pkg-types: + specifier: 'catalog:' + version: 2.3.0 + prettier: + specifier: 'catalog:' + version: 3.7.4 + rimraf: + specifier: 'catalog:' + version: 6.1.2 + + internal/tailwind-config: + dependencies: + '@iconify/json': + specifier: 'catalog:' + version: 2.2.417 + '@iconify/tailwind': + specifier: 'catalog:' + version: 1.2.0 + '@manypkg/get-packages': + specifier: 'catalog:' + version: 3.1.0 + '@tailwindcss/nesting': + specifier: 'catalog:' + version: 0.0.0-insiders.565cd3e(postcss@8.5.6) + '@tailwindcss/typography': + specifier: 'catalog:' + version: 0.5.19(tailwindcss@3.4.19(yaml@2.8.2)) + autoprefixer: + specifier: 'catalog:' + version: 10.4.23(postcss@8.5.6) + cssnano: + specifier: 'catalog:' + version: 7.1.2(postcss@8.5.6) + jiti: + specifier: ^2.6.1 + version: 2.6.1 + postcss: + specifier: 'catalog:' + version: 8.5.6 + postcss-antd-fixes: + specifier: 'catalog:' + version: 0.2.0(postcss@8.5.6) + postcss-import: + specifier: 'catalog:' + version: 16.1.1(postcss@8.5.6) + postcss-preset-env: + specifier: 'catalog:' + version: 10.5.0(postcss@8.5.6) + tailwindcss: + specifier: 'catalog:' + version: 3.4.19(yaml@2.8.2) + tailwindcss-animate: + specifier: 'catalog:' + version: 1.0.7(tailwindcss@3.4.19(yaml@2.8.2)) + devDependencies: + '@types/postcss-import': + specifier: 'catalog:' + version: 14.0.3 + + internal/tsconfig: + dependencies: + '@vben/types': + specifier: workspace:* + version: link:../../packages/types + vite: + specifier: 'catalog:' + version: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + + internal/vite-config: + dependencies: + '@intlify/unplugin-vue-i18n': + specifier: 'catalog:' + version: 6.0.8(@vue/compiler-dom@3.5.26)(eslint@9.39.2(jiti@2.6.1))(rollup@4.54.0)(typescript@5.9.3)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3)) + '@jspm/generator': + specifier: 'catalog:' + version: 2.8.0 + archiver: + specifier: 'catalog:' + version: 7.0.1 + cheerio: + specifier: 'catalog:' + version: 1.1.2 + get-port: + specifier: 'catalog:' + version: 7.1.0 + html-minifier-terser: + specifier: 'catalog:' + version: 7.2.0 + nitropack: + specifier: 'catalog:' + version: 2.12.9 + resolve.exports: + specifier: 'catalog:' + version: 2.0.3 + vite-plugin-pwa: + specifier: 'catalog:' + version: 1.2.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(workbox-build@7.4.0)(workbox-window@7.4.0) + vite-plugin-vue-devtools: + specifier: 'catalog:' + version: 8.0.5(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + devDependencies: + '@pnpm/workspace.read-manifest': + specifier: 'catalog:' + version: 1000.2.9 + '@types/archiver': + specifier: 'catalog:' + version: 6.0.4 + '@types/html-minifier-terser': + specifier: 'catalog:' + version: 7.0.2 + '@vben/node-utils': + specifier: workspace:* + version: link:../node-utils + '@vitejs/plugin-vue': + specifier: 'catalog:' + version: 6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + '@vitejs/plugin-vue-jsx': + specifier: 'catalog:' + version: 5.1.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + dayjs: + specifier: 'catalog:' + version: 1.11.19 + dotenv: + specifier: 'catalog:' + version: 16.6.1 + rollup: + specifier: 'catalog:' + version: 4.54.0 + rollup-plugin-visualizer: + specifier: 'catalog:' + version: 5.14.0(rollup@4.54.0) + sass: + specifier: 'catalog:' + version: 1.97.1 + vite: + specifier: 'catalog:' + version: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vite-plugin-compression: + specifier: 'catalog:' + version: 0.5.1(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + vite-plugin-dts: + specifier: 'catalog:' + version: 4.5.4(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + vite-plugin-html: + specifier: 'catalog:' + version: 3.2.2(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + vite-plugin-lazy-import: + specifier: 'catalog:' + version: 1.0.7 + + packages/@core/base/design: {} + + packages/@core/base/icons: + dependencies: + '@iconify/vue': + specifier: 'catalog:' + version: 5.0.0(vue@3.5.26(typescript@5.9.3)) + lucide-vue-next: + specifier: 'catalog:' + version: 0.553.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/@core/base/shared: + dependencies: + '@ctrl/tinycolor': + specifier: ^4.1.0 + version: 4.2.0 + '@tanstack/vue-store': + specifier: 'catalog:' + version: 0.8.0(vue@3.5.26(typescript@5.9.3)) + '@vue/shared': + specifier: 'catalog:' + version: 3.5.26 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + dayjs: + specifier: 'catalog:' + version: 1.11.19 + defu: + specifier: 'catalog:' + version: 6.1.4 + es-toolkit: + specifier: 'catalog:' + version: 1.43.0 + lodash.clonedeep: + specifier: 'catalog:' + version: 4.5.0 + nprogress: + specifier: 'catalog:' + version: 0.2.0 + tailwind-merge: + specifier: 'catalog:' + version: 2.6.0 + theme-colors: + specifier: 'catalog:' + version: 0.1.0 + devDependencies: + '@types/lodash.clonedeep': + specifier: 'catalog:' + version: 4.5.9 + '@types/lodash.get': + specifier: 'catalog:' + version: 4.4.9 + '@types/lodash.isequal': + specifier: 'catalog:' + version: 4.5.8 + '@types/lodash.set': + specifier: 'catalog:' + version: 4.3.9 + '@types/nprogress': + specifier: 'catalog:' + version: 0.2.3 + + packages/@core/base/typings: + dependencies: + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + + packages/@core/composables: + dependencies: + '@vben-core/shared': + specifier: workspace:* + version: link:../base/shared + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + reka-ui: + specifier: 'catalog:' + version: 2.7.0(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) + sortablejs: + specifier: 'catalog:' + version: 1.15.6 + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + devDependencies: + '@types/sortablejs': + specifier: 'catalog:' + version: 1.15.9 + + packages/@core/preferences: + dependencies: + '@vben-core/shared': + specifier: workspace:* + version: link:../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../base/typings + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/@core/ui-kit/form-ui: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../composables + '@vben-core/icons': + specifier: workspace:* + version: link:../../base/icons + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../../base/typings + '@vee-validate/zod': + specifier: 'catalog:' + version: 4.15.1(vue@3.5.26(typescript@5.9.3))(zod@3.25.76) + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vee-validate: + specifier: 'catalog:' + version: 4.15.1(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + zod: + specifier: 'catalog:' + version: 3.25.76 + zod-defaults: + specifier: 'catalog:' + version: 0.1.3(zod@3.25.76) + + packages/@core/ui-kit/layout-ui: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../composables + '@vben-core/icons': + specifier: workspace:* + version: link:../../base/icons + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../../base/typings + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/@core/ui-kit/menu-ui: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../composables + '@vben-core/icons': + specifier: workspace:* + version: link:../../base/icons + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../../base/typings + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/@core/ui-kit/popup-ui: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../composables + '@vben-core/icons': + specifier: workspace:* + version: link:../../base/icons + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../../base/typings + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/@core/ui-kit/shadcn-ui: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../composables + '@vben-core/icons': + specifier: workspace:* + version: link:../../base/icons + '@vben-core/shared': + specifier: workspace:* + version: link:../../base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../../base/typings + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + class-variance-authority: + specifier: 'catalog:' + version: 0.7.1 + lucide-vue-next: + specifier: 'catalog:' + version: 0.553.0(vue@3.5.26(typescript@5.9.3)) + reka-ui: + specifier: 'catalog:' + version: 2.7.0(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) + vee-validate: + specifier: 'catalog:' + version: 4.15.1(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/@core/ui-kit/tabs-ui: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../composables + '@vben-core/icons': + specifier: workspace:* + version: link:../../base/icons + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../shadcn-ui + '@vben-core/typings': + specifier: workspace:* + version: link:../../base/typings + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/constants: + dependencies: + '@vben-core/shared': + specifier: workspace:* + version: link:../@core/base/shared + + packages/effects/access: + dependencies: + '@vben/preferences': + specifier: workspace:* + version: link:../../preferences + '@vben/stores': + specifier: workspace:* + version: link:../../stores + '@vben/types': + specifier: workspace:* + version: link:../../types + '@vben/utils': + specifier: workspace:* + version: link:../../utils + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + + packages/effects/common-ui: + dependencies: + '@vben-core/form-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/form-ui + '@vben-core/popup-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/popup-ui + '@vben-core/preferences': + specifier: workspace:* + version: link:../../@core/preferences + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../@core/base/shared + '@vben/constants': + specifier: workspace:* + version: link:../../constants + '@vben/hooks': + specifier: workspace:* + version: link:../hooks + '@vben/icons': + specifier: workspace:* + version: link:../../icons + '@vben/locales': + specifier: workspace:* + version: link:../../locales + '@vben/types': + specifier: workspace:* + version: link:../../types + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/integrations': + specifier: 'catalog:' + version: 14.1.0(async-validator@4.2.5)(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.7.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.26(typescript@5.9.3)) + json-bigint: + specifier: 'catalog:' + version: 1.0.0 + qrcode: + specifier: 'catalog:' + version: 1.5.4 + tippy.js: + specifier: 'catalog:' + version: 6.3.7 + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-json-viewer: + specifier: 'catalog:' + version: 3.0.4(vue@3.5.26(typescript@5.9.3)) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + vue-tippy: + specifier: 'catalog:' + version: 6.7.1(vue@3.5.26(typescript@5.9.3)) + devDependencies: + '@types/qrcode': + specifier: 'catalog:' + version: 1.5.6 + + packages/effects/hooks: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../@core/composables + '@vben/preferences': + specifier: workspace:* + version: link:../../preferences + '@vben/stores': + specifier: workspace:* + version: link:../../stores + '@vben/types': + specifier: workspace:* + version: link:../../types + '@vben/utils': + specifier: workspace:* + version: link:../../utils + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + watermark-js-plus: + specifier: 'catalog:' + version: 1.6.3 + + packages/effects/layouts: + dependencies: + '@vben-core/composables': + specifier: workspace:* + version: link:../../@core/composables + '@vben-core/form-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/form-ui + '@vben-core/layout-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/layout-ui + '@vben-core/menu-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/menu-ui + '@vben-core/popup-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/popup-ui + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../@core/base/shared + '@vben-core/tabs-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/tabs-ui + '@vben/constants': + specifier: workspace:* + version: link:../../constants + '@vben/hooks': + specifier: workspace:* + version: link:../hooks + '@vben/icons': + specifier: workspace:* + version: link:../../icons + '@vben/locales': + specifier: workspace:* + version: link:../../locales + '@vben/preferences': + specifier: workspace:* + version: link:../../preferences + '@vben/stores': + specifier: workspace:* + version: link:../../stores + '@vben/types': + specifier: workspace:* + version: link:../../types + '@vben/utils': + specifier: workspace:* + version: link:../../utils + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + + packages/effects/plugins: + dependencies: + '@vben-core/form-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/form-ui + '@vben-core/shadcn-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/shadcn-ui + '@vben-core/shared': + specifier: workspace:* + version: link:../../@core/base/shared + '@vben/hooks': + specifier: workspace:* + version: link:../hooks + '@vben/icons': + specifier: workspace:* + version: link:../../icons + '@vben/locales': + specifier: workspace:* + version: link:../../locales + '@vben/preferences': + specifier: workspace:* + version: link:../../preferences + '@vben/types': + specifier: workspace:* + version: link:../../types + '@vben/utils': + specifier: workspace:* + version: link:../../utils + '@vueuse/core': + specifier: 'catalog:' + version: 13.9.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/motion': + specifier: 'catalog:' + version: 3.0.3(magicast@0.5.1)(vue@3.5.26(typescript@5.9.3)) + echarts: + specifier: 'catalog:' + version: 6.0.0 + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vxe-pc-ui: + specifier: 'catalog:' + version: 4.11.17(vue@3.5.26(typescript@5.9.3)) + vxe-table: + specifier: 'catalog:' + version: 4.17.33(vue@3.5.26(typescript@5.9.3)) + + packages/effects/request: + dependencies: + '@vben/locales': + specifier: workspace:* + version: link:../../locales + '@vben/utils': + specifier: workspace:* + version: link:../../utils + axios: + specifier: 'catalog:' + version: 1.13.2 + qs: + specifier: 'catalog:' + version: 6.14.0 + devDependencies: + '@types/qs': + specifier: 'catalog:' + version: 6.14.0 + axios-mock-adapter: + specifier: 'catalog:' + version: 2.1.0(axios@1.13.2) + + packages/icons: + dependencies: + '@vben-core/icons': + specifier: workspace:* + version: link:../@core/base/icons + devDependencies: + '@iconify/icons-ant-design': + specifier: ^1.2.7 + version: 1.2.7 + '@iconify/icons-arcticons': + specifier: ^1.2.1 + version: 1.2.77 + '@iconify/icons-fa-brands': + specifier: ^1.2.4 + version: 1.2.4 + '@iconify/icons-flat-color-icons': + specifier: ^1.2.5 + version: 1.2.5 + '@iconify/icons-la': + specifier: ^1.2.3 + version: 1.2.3 + '@iconify/icons-logos': + specifier: ^1.2.36 + version: 1.2.36 + '@iconify/icons-ri': + specifier: ^1.2.10 + version: 1.2.10 + '@iconify/icons-simple-icons': + specifier: ^1.2.74 + version: 1.2.74 + '@iconify/icons-uiw': + specifier: ^1.2.6 + version: 1.2.6 + + packages/locales: + dependencies: + '@intlify/core-base': + specifier: 'catalog:' + version: 11.2.7 + '@vben-core/composables': + specifier: workspace:* + version: link:../@core/composables + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-i18n: + specifier: 'catalog:' + version: 11.2.7(vue@3.5.26(typescript@5.9.3)) + + packages/preferences: + dependencies: + '@vben-core/preferences': + specifier: workspace:* + version: link:../@core/preferences + '@vben-core/typings': + specifier: workspace:* + version: link:../@core/base/typings + + packages/stores: + dependencies: + '@vben-core/preferences': + specifier: workspace:* + version: link:../@core/preferences + '@vben-core/shared': + specifier: workspace:* + version: link:../@core/base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../@core/base/typings + pinia: + specifier: ^3.0.3 + version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) + pinia-plugin-persistedstate: + specifier: 'catalog:' + version: 4.7.1(@nuxt/kit@4.2.2(magicast@0.5.1))(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3))) + secure-ls: + specifier: 'catalog:' + version: 2.0.0 + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + + packages/styles: + dependencies: + '@vben-core/design': + specifier: workspace:* + version: link:../@core/base/design + + packages/types: + dependencies: + '@vben-core/typings': + specifier: workspace:* + version: link:../@core/base/typings + vue: + specifier: ^3.5.24 + version: 3.5.26(typescript@5.9.3) + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + + packages/utils: + dependencies: + '@vben-core/shared': + specifier: workspace:* + version: link:../@core/base/shared + '@vben-core/typings': + specifier: workspace:* + version: link:../@core/base/typings + file-type: + specifier: ^19.5.0 + version: 19.6.0 + vue-router: + specifier: 'catalog:' + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) + + scripts/turbo-run: + dependencies: + '@clack/prompts': + specifier: 'catalog:' + version: 0.11.0 + '@vben/node-utils': + specifier: workspace:* + version: link:../../internal/node-utils + cac: + specifier: 'catalog:' + version: 6.7.14 + + scripts/vsh: + dependencies: + '@vben/node-utils': + specifier: workspace:* + version: link:../../internal/node-utils + cac: + specifier: 'catalog:' + version: 6.7.14 + circular-dependency-scanner: + specifier: 'catalog:' + version: 2.3.0 + depcheck: + specifier: 'catalog:' + version: 1.4.7 + publint: + specifier: 'catalog:' + version: 0.3.16 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@ant-design/colors@6.0.0': + resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==} + + '@ant-design/icons-svg@4.4.2': + resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} + + '@ant-design/icons-vue@7.0.1': + resolution: {integrity: sha512-eCqY2unfZK6Fe02AwFlDHLfoyEFreP6rBwAZMIJ1LugmfMiVgwWDYlp1YsRugaPtICYOabV1iWxXdP12u9U43Q==} + peerDependencies: + vue: ^3.5.24 + + '@apideck/better-ajv-errors@0.3.6': + resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} + engines: {node: '>=10'} + peerDependencies: + ajv: '>=8' + + '@ast-grep/napi-darwin-arm64@0.39.9': + resolution: {integrity: sha512-0gdBC2oPBkIBsh89yUXxJeK37QYRbp1qNZVuRGizT666ljgCw+2NIxHeQGNjwWuI0+g3exrd8FyqD3gMixRx3w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@ast-grep/napi-darwin-x64@0.39.9': + resolution: {integrity: sha512-7QuQNFwcVj71hDAMBErF+mVq2h92vUdHLKa/vq58HdRpix5G3DZqcTKoFjwhCNzc2wsNRAjV+BiIR01znQSxLA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@ast-grep/napi-linux-arm64-gnu@0.39.9': + resolution: {integrity: sha512-qXTjhagRYkPyHNACEzGi5q26OMRdSvLRRqi799oZaSDf96Xj+8tcB5+tFlH0NpqaP84GsZoQ15SfDXeoP4qdmQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@ast-grep/napi-linux-arm64-musl@0.39.9': + resolution: {integrity: sha512-U9KVohyburVGEWiiREFq+iTxdMdSbRyXL+yzCVvGPmLPW4Ca4zpX9Cret4jCJBp8dljSIK0C7txXAc7fM+6rag==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@ast-grep/napi-linux-x64-gnu@0.39.9': + resolution: {integrity: sha512-C5WwiNr/eE7lS0vl9bNdSXrsGIUAga2SaqV3G+ogVl9HeRU2jtGhv+3AgzGvYWj+PtnbtuZ2Nxkm10gEVPhv1A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@ast-grep/napi-linux-x64-musl@0.39.9': + resolution: {integrity: sha512-KutzZSMhHP3P43nQ+kNSbuiDaqkCcdqOcXLnq28MRvS+qwvW+01dJ8eWRlpMJC9vCJmaJAZfI7xkNSp74WkdxA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@ast-grep/napi-win32-arm64-msvc@0.39.9': + resolution: {integrity: sha512-S2kC6K9I7e70oMVn2FDICzVlz7SPZVWNCRKCBD+Dgy1OTn0byzmMLaGpjth3pqN93UCssEC03ooP3tuclS0JSA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@ast-grep/napi-win32-ia32-msvc@0.39.9': + resolution: {integrity: sha512-n18Dqtc7O5q8ZM9gBNkvLd+ajdjLNraw4ZoIcHelI7TnTvh1m6zR3tUuHNxPhL+IJfdKx3ne7ATKlEeiSlMn4g==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@ast-grep/napi-win32-x64-msvc@0.39.9': + resolution: {integrity: sha512-YOF7mO+6nvyRtMC179u82Vr1qIGOmoE1yjwr4cmAf7DVNd+vs42y9tbQGYwLmVY8M3Hg1PviB8XX7FQKewuOGQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@ast-grep/napi@0.39.9': + resolution: {integrity: sha512-qtLLQq1a3isK0iaq0Drl7Qt4PqeyjTrpFxNdA/20O/jYkGiA/oJA8DLMn1bzczsfjlUohe4dg39bpeAqG02uvA==} + engines: {node: '>= 10'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.5': + resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.27.1': + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.27.1': + resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.28.3': + resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': + resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-decorators@7.28.0': + resolution: {integrity: sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-decorators@7.27.1': + resolution: {integrity: sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.27.1': + resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.27.1': + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.28.0': + resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.27.1': + resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.27.1': + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.28.5': + resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.27.1': + resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.28.3': + resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.28.4': + resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.27.1': + resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.27.1': + resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.27.1': + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': + resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.27.1': + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.28.0': + resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.28.5': + resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.27.1': + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.27.1': + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.27.1': + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.27.1': + resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.27.1': + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.28.5': + resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.27.1': + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.27.1': + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.27.1': + resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.28.5': + resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.27.1': + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': + resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.27.1': + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': + resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.27.1': + resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.28.4': + resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.27.1': + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.27.1': + resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.28.5': + resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.27.7': + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.27.1': + resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.27.1': + resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.27.1': + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.28.4': + resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.27.1': + resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.27.1': + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.27.1': + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.27.1': + resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.27.1': + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.27.1': + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.28.5': + resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.27.1': + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.27.1': + resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.27.1': + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.27.1': + resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.28.5': + resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.2.1': + resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + + '@cacheable/memory@2.0.6': + resolution: {integrity: sha512-7e8SScMocHxcAb8YhtkbMhGG+EKLRIficb1F5sjvhSYsWTZGxvg4KIDp8kgxnV2PUJ3ddPe6J9QESjKvBWRDkg==} + + '@cacheable/utils@2.3.2': + resolution: {integrity: sha512-8kGE2P+HjfY8FglaOiW+y8qxcaQAfAhVML+i66XJR3YX5FtyDqn6Txctr3K2FrbxLKixRRYYBWMbuGciOhYNDg==} + + '@changesets/apply-release-plan@7.0.14': + resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} + + '@changesets/assemble-release-plan@6.0.9': + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} + + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/changelog-github@0.5.2': + resolution: {integrity: sha512-HeGeDl8HaIGj9fQHo/tv5XKQ2SNEi9+9yl1Bss1jttPqeiASRXhfi0A2wv8yFKCp07kR1gpOI5ge6+CWNm1jPw==} + + '@changesets/cli@2.29.8': + resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} + hasBin: true + + '@changesets/config@3.1.2': + resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.3': + resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} + + '@changesets/get-github-info@0.7.0': + resolution: {integrity: sha512-+i67Bmhfj9V4KfDeS1+Tz3iF32btKZB2AAx+cYMqDSRFP7r3/ZdGbjCo+c6qkyViN9ygDuBjzageuPGJtKGe5A==} + + '@changesets/get-release-plan@4.0.14': + resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.2': + resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} + + '@changesets/pre@2.0.2': + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + + '@changesets/read@0.6.6': + resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} + + '@changesets/should-skip-package@0.1.2': + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.1.0': + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + + '@clack/core@0.5.0': + resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + + '@clack/prompts@0.11.0': + resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + + '@cloudflare/kv-asset-handler@0.4.1': + resolution: {integrity: sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==} + engines: {node: '>=18.0.0'} + + '@commitlint/cli@19.8.1': + resolution: {integrity: sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==} + engines: {node: '>=v18'} + hasBin: true + + '@commitlint/config-conventional@19.8.1': + resolution: {integrity: sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==} + engines: {node: '>=v18'} + + '@commitlint/config-validator@19.8.1': + resolution: {integrity: sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==} + engines: {node: '>=v18'} + + '@commitlint/ensure@19.8.1': + resolution: {integrity: sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==} + engines: {node: '>=v18'} + + '@commitlint/execute-rule@19.8.1': + resolution: {integrity: sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==} + engines: {node: '>=v18'} + + '@commitlint/format@19.8.1': + resolution: {integrity: sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==} + engines: {node: '>=v18'} + + '@commitlint/is-ignored@19.8.1': + resolution: {integrity: sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==} + engines: {node: '>=v18'} + + '@commitlint/lint@19.8.1': + resolution: {integrity: sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==} + engines: {node: '>=v18'} + + '@commitlint/load@19.8.1': + resolution: {integrity: sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==} + engines: {node: '>=v18'} + + '@commitlint/message@19.8.1': + resolution: {integrity: sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==} + engines: {node: '>=v18'} + + '@commitlint/parse@19.8.1': + resolution: {integrity: sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==} + engines: {node: '>=v18'} + + '@commitlint/read@19.8.1': + resolution: {integrity: sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==} + engines: {node: '>=v18'} + + '@commitlint/resolve-extends@19.8.1': + resolution: {integrity: sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==} + engines: {node: '>=v18'} + + '@commitlint/rules@19.8.1': + resolution: {integrity: sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==} + engines: {node: '>=v18'} + + '@commitlint/to-lines@19.8.1': + resolution: {integrity: sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==} + engines: {node: '>=v18'} + + '@commitlint/top-level@19.8.1': + resolution: {integrity: sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==} + engines: {node: '>=v18'} + + '@commitlint/types@19.8.1': + resolution: {integrity: sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==} + engines: {node: '>=v18'} + + '@cspell/cspell-bundled-dicts@8.19.4': + resolution: {integrity: sha512-2ZRcZP/ncJ5q953o8i+R0fb8+14PDt5UefUNMrFZZHvfTI0jukAASOQeLY+WT6ASZv6CgbPrApAdbppy9FaXYQ==} + engines: {node: '>=18'} + + '@cspell/cspell-json-reporter@8.19.4': + resolution: {integrity: sha512-pOlUtLUmuDdTIOhDTvWxxta0Wm8RCD/p1V0qUqeP6/Ups1ajBI4FWEpRFd7yMBTUHeGeSNicJX5XeX7wNbAbLQ==} + engines: {node: '>=18'} + + '@cspell/cspell-pipe@8.19.4': + resolution: {integrity: sha512-GNAyk+7ZLEcL2fCMT5KKZprcdsq3L1eYy3e38/tIeXfbZS7Sd1R5FXUe6CHXphVWTItV39TvtLiDwN/2jBts9A==} + engines: {node: '>=18'} + + '@cspell/cspell-resolver@8.19.4': + resolution: {integrity: sha512-S8vJMYlsx0S1D60glX8H2Jbj4mD8519VjyY8lu3fnhjxfsl2bDFZvF3ZHKsLEhBE+Wh87uLqJDUJQiYmevHjDg==} + engines: {node: '>=18'} + + '@cspell/cspell-service-bus@8.19.4': + resolution: {integrity: sha512-uhY+v8z5JiUogizXW2Ft/gQf3eWrh5P9036jN2Dm0UiwEopG/PLshHcDjRDUiPdlihvA0RovrF0wDh4ptcrjuQ==} + engines: {node: '>=18'} + + '@cspell/cspell-types@8.19.4': + resolution: {integrity: sha512-ekMWuNlFiVGfsKhfj4nmc8JCA+1ZltwJgxiKgDuwYtR09ie340RfXFF6YRd2VTW5zN7l4F1PfaAaPklVz6utSg==} + engines: {node: '>=18'} + + '@cspell/dict-ada@4.1.1': + resolution: {integrity: sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==} + + '@cspell/dict-al@1.1.1': + resolution: {integrity: sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==} + + '@cspell/dict-aws@4.0.17': + resolution: {integrity: sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==} + + '@cspell/dict-bash@4.2.2': + resolution: {integrity: sha512-kyWbwtX3TsCf5l49gGQIZkRLaB/P8g73GDRm41Zu8Mv51kjl2H7Au0TsEvHv7jzcsRLS6aUYaZv6Zsvk1fOz+Q==} + + '@cspell/dict-companies@3.2.9': + resolution: {integrity: sha512-y5GdU+LnuMhUE/WYwOYt7GcJdrpmV4KXE1oFb5toEsnGa2KzffUbS6lwPpeRBocQoqZj8jJYFtxoQ+2KVg++/A==} + + '@cspell/dict-cpp@6.0.15': + resolution: {integrity: sha512-N7MKK3llRNoBncygvrnLaGvmjo4xzVr5FbtAc9+MFGHK6/LeSySBupr1FM72XDaVSIsmBEe7sDYCHHwlI9Jb2w==} + + '@cspell/dict-cryptocurrencies@5.0.5': + resolution: {integrity: sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==} + + '@cspell/dict-csharp@4.0.8': + resolution: {integrity: sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==} + + '@cspell/dict-css@4.0.19': + resolution: {integrity: sha512-VYHtPnZt/Zd/ATbW3rtexWpBnHUohUrQOHff/2JBhsVgxOrksAxJnLAO43Q1ayLJBJUUwNVo+RU0sx0aaysZfg==} + + '@cspell/dict-dart@2.3.2': + resolution: {integrity: sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==} + + '@cspell/dict-data-science@2.0.13': + resolution: {integrity: sha512-l1HMEhBJkPmw4I2YGVu2eBSKM89K9pVF+N6qIr5Uo5H3O979jVodtuwP8I7LyPrJnC6nz28oxeGRCLh9xC5CVA==} + + '@cspell/dict-django@4.1.6': + resolution: {integrity: sha512-SdbSFDGy9ulETqNz15oWv2+kpWLlk8DJYd573xhIkeRdcXOjskRuxjSZPKfW7O3NxN/KEf3gm3IevVOiNuFS+w==} + + '@cspell/dict-docker@1.1.17': + resolution: {integrity: sha512-OcnVTIpHIYYKhztNTyK8ShAnXTfnqs43hVH6p0py0wlcwRIXe5uj4f12n7zPf2CeBI7JAlPjEsV0Rlf4hbz/xQ==} + + '@cspell/dict-dotnet@5.0.10': + resolution: {integrity: sha512-ooar8BP/RBNP1gzYfJPStKEmpWy4uv/7JCq6FOnJLeD1yyfG3d/LFMVMwiJo+XWz025cxtkM3wuaikBWzCqkmg==} + + '@cspell/dict-elixir@4.0.8': + resolution: {integrity: sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==} + + '@cspell/dict-en-common-misspellings@2.1.10': + resolution: {integrity: sha512-+S10oo15G3Axz1W4FGmYNq9u0xxS6OhNl9dXY3qjYBOqhzfF3l1oM/TpkfH/1NH31r3GneuPVXKXT7y16qwJYA==} + + '@cspell/dict-en-gb@1.1.33': + resolution: {integrity: sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==} + + '@cspell/dict-en_us@4.4.26': + resolution: {integrity: sha512-rpjM87n2e3PN3mx9SbzQOIniEWUKewZj0xFA796Pzeu3gJlYsHsSkZZC6Jxdea2992EfrzJZYwJb+mjxa3gWGg==} + + '@cspell/dict-filetypes@3.0.15': + resolution: {integrity: sha512-uDMeqYlLlK476w/muEFQGBy9BdQWS0mQ7BJiy/iQv5XUWZxE2O54ZQd9nW8GyQMzAgoyg5SG4hf9l039Qt66oA==} + + '@cspell/dict-flutter@1.1.1': + resolution: {integrity: sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==} + + '@cspell/dict-fonts@4.0.5': + resolution: {integrity: sha512-BbpkX10DUX/xzHs6lb7yzDf/LPjwYIBJHJlUXSBXDtK/1HaeS+Wqol4Mlm2+NAgZ7ikIE5DQMViTgBUY3ezNoQ==} + + '@cspell/dict-fsharp@1.1.1': + resolution: {integrity: sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==} + + '@cspell/dict-fullstack@3.2.7': + resolution: {integrity: sha512-IxEk2YAwAJKYCUEgEeOg3QvTL4XLlyArJElFuMQevU1dPgHgzWElFevN5lsTFnvMFA1riYsVinqJJX0BanCFEg==} + + '@cspell/dict-gaming-terms@1.1.2': + resolution: {integrity: sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==} + + '@cspell/dict-git@3.0.7': + resolution: {integrity: sha512-odOwVKgfxCQfiSb+nblQZc4ErXmnWEnv8XwkaI4sNJ7cNmojnvogYVeMqkXPjvfrgEcizEEA4URRD2Ms5PDk1w==} + + '@cspell/dict-golang@6.0.25': + resolution: {integrity: sha512-Q0mkUj1mFN1P5LZoKBeTLOQehlHMYv62K0Px9FS7qykSvZjBz44bhCezJuepTPCiCFqmwQgT2fc3Ixw+fhO6pQ==} + + '@cspell/dict-google@1.0.9': + resolution: {integrity: sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==} + + '@cspell/dict-haskell@4.0.6': + resolution: {integrity: sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==} + + '@cspell/dict-html-symbol-entities@4.0.5': + resolution: {integrity: sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==} + + '@cspell/dict-html@4.0.14': + resolution: {integrity: sha512-2bf7n+kS92g+cMKV0wr9o/Oq9n8JzU7CcrB96gIh2GHgnF+0xDOqO2W/1KeFAqOfqosoOVE48t+4dnEMkkoJ2Q==} + + '@cspell/dict-java@5.0.12': + resolution: {integrity: sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==} + + '@cspell/dict-julia@1.1.1': + resolution: {integrity: sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==} + + '@cspell/dict-k8s@1.0.12': + resolution: {integrity: sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==} + + '@cspell/dict-kotlin@1.1.1': + resolution: {integrity: sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==} + + '@cspell/dict-latex@4.0.4': + resolution: {integrity: sha512-YdTQhnTINEEm/LZgTzr9Voz4mzdOXH7YX+bSFs3hnkUHCUUtX/mhKgf1CFvZ0YNM2afjhQcmLaR9bDQVyYBvpA==} + + '@cspell/dict-lorem-ipsum@4.0.5': + resolution: {integrity: sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==} + + '@cspell/dict-lua@4.0.8': + resolution: {integrity: sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==} + + '@cspell/dict-makefile@1.0.5': + resolution: {integrity: sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==} + + '@cspell/dict-markdown@2.0.14': + resolution: {integrity: sha512-uLKPNJsUcumMQTsZZgAK9RgDLyQhUz/uvbQTEkvF/Q4XfC1i/BnA8XrOrd0+Vp6+tPOKyA+omI5LRWfMu5K/Lw==} + peerDependencies: + '@cspell/dict-css': ^4.0.19 + '@cspell/dict-html': ^4.0.14 + '@cspell/dict-html-symbol-entities': ^4.0.5 + '@cspell/dict-typescript': ^3.2.3 + + '@cspell/dict-monkeyc@1.0.12': + resolution: {integrity: sha512-MN7Vs11TdP5mbdNFQP5x2Ac8zOBm97ARg6zM5Sb53YQt/eMvXOMvrep7+/+8NJXs0jkp70bBzjqU4APcqBFNAw==} + + '@cspell/dict-node@5.0.8': + resolution: {integrity: sha512-AirZcN2i84ynev3p2/1NCPEhnNsHKMz9zciTngGoqpdItUb2bDt1nJBjwlsrFI78GZRph/VaqTVFwYikmncpXg==} + + '@cspell/dict-npm@5.2.27': + resolution: {integrity: sha512-REy2vRQ9BJkjoW8cEr8ewoJAZ0DsTh+TimJ58KgIG1d81caanNgdvKLSgDkPd8OlGxPfLKHe7o2TJuk/l7VqhA==} + + '@cspell/dict-php@4.1.0': + resolution: {integrity: sha512-dTDeabyOj7eFvn2Q4Za3uVXM2+SzeFMqX8ly2P0XTo4AzbCmI2hulFD/QIADwWmwiRrInbbf8cxwFHNIYrXl4w==} + + '@cspell/dict-powershell@5.0.15': + resolution: {integrity: sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==} + + '@cspell/dict-public-licenses@2.0.15': + resolution: {integrity: sha512-cJEOs901H13Pfy0fl4dCD1U+xpWIMaEPq8MeYU83FfDZvellAuSo4GqWCripfIqlhns/L6+UZEIJSOZnjgy7Wg==} + + '@cspell/dict-python@4.2.24': + resolution: {integrity: sha512-B1oXYTa0+3sKOvx/svwxFaT3MrkHJ7ZLWpA1N7ZyHoET7IJhLCwcfAu7DCTq1f24Wnd4t+ARJvPEmFbMx65VBw==} + + '@cspell/dict-r@2.1.1': + resolution: {integrity: sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==} + + '@cspell/dict-ruby@5.0.9': + resolution: {integrity: sha512-H2vMcERMcANvQshAdrVx0XoWaNX8zmmiQN11dZZTQAZaNJ0xatdJoSqY8C8uhEMW89bfgpN+NQgGuDXW2vmXEw==} + + '@cspell/dict-rust@4.1.0': + resolution: {integrity: sha512-ysFxxKc3QjPWtPacbwxzz8sDOACHNShlhQpnBsDXAHN3LogmuBsQtfyuU30APqFjCOg9KwGciKYC/hcGxJCbiA==} + + '@cspell/dict-scala@5.0.8': + resolution: {integrity: sha512-YdftVmumv8IZq9zu1gn2U7A4bfM2yj9Vaupydotyjuc+EEZZSqAafTpvW/jKLWji2TgybM1L2IhmV0s/Iv9BTw==} + + '@cspell/dict-shell@1.1.2': + resolution: {integrity: sha512-WqOUvnwcHK1X61wAfwyXq04cn7KYyskg90j4lLg3sGGKMW9Sq13hs91pqrjC44Q+lQLgCobrTkMDw9Wyl9nRFA==} + + '@cspell/dict-software-terms@5.1.18': + resolution: {integrity: sha512-+RUM+DnRnGzDjnJrAEiEQnopPGBXQ5kUY9t38WdTVYVgkpIE0/dcMX+s5uAp7vvKezhU6gW+CGW5K5xdF2KKiw==} + + '@cspell/dict-sql@2.2.1': + resolution: {integrity: sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==} + + '@cspell/dict-svelte@1.0.7': + resolution: {integrity: sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==} + + '@cspell/dict-swift@2.0.6': + resolution: {integrity: sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==} + + '@cspell/dict-terraform@1.1.3': + resolution: {integrity: sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==} + + '@cspell/dict-typescript@3.2.3': + resolution: {integrity: sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==} + + '@cspell/dict-vue@3.0.5': + resolution: {integrity: sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==} + + '@cspell/dynamic-import@8.19.4': + resolution: {integrity: sha512-0LLghC64+SiwQS20Sa0VfFUBPVia1rNyo0bYeIDoB34AA3qwguDBVJJkthkpmaP1R2JeR/VmxmJowuARc4ZUxA==} + engines: {node: '>=18.0'} + + '@cspell/filetypes@8.19.4': + resolution: {integrity: sha512-D9hOCMyfKtKjjqQJB8F80PWsjCZhVGCGUMiDoQpcta0e+Zl8vHgzwaC0Ai4QUGBhwYEawHGiWUd7Y05u/WXiNQ==} + engines: {node: '>=18'} + + '@cspell/strong-weak-map@8.19.4': + resolution: {integrity: sha512-MUfFaYD8YqVe32SQaYLI24/bNzaoyhdBIFY5pVrvMo1ZCvMl8AlfI2OcBXvcGb5aS5z7sCNCJm11UuoYbLI1zw==} + engines: {node: '>=18'} + + '@cspell/url@8.19.4': + resolution: {integrity: sha512-Pa474iBxS+lxsAL4XkETPGIq3EgMLCEb9agj3hAd2VGMTCApaiUvamR4b+uGXIPybN70piFxvzrfoxsG2uIP6A==} + engines: {node: '>=18.0'} + + '@csstools/cascade-layer-name-parser@2.0.5': + resolution: {integrity: sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-syntax-patches-for-csstree@1.0.22': + resolution: {integrity: sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==} + engines: {node: '>=18'} + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + + '@csstools/media-query-list-parser@3.0.1': + resolution: {integrity: sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.1 + '@csstools/css-tokenizer': ^3.0.1 + + '@csstools/media-query-list-parser@4.0.3': + resolution: {integrity: sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/postcss-alpha-function@1.0.1': + resolution: {integrity: sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-cascade-layers@5.0.2': + resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-color-function-display-p3-linear@1.0.1': + resolution: {integrity: sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-color-function@4.0.12': + resolution: {integrity: sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-color-mix-function@3.0.12': + resolution: {integrity: sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-color-mix-variadic-function-arguments@1.0.2': + resolution: {integrity: sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-content-alt-text@2.0.8': + resolution: {integrity: sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-contrast-color-function@2.0.12': + resolution: {integrity: sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-exponential-functions@2.0.9': + resolution: {integrity: sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-font-format-keywords@4.0.0': + resolution: {integrity: sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-gamut-mapping@2.0.11': + resolution: {integrity: sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-gradients-interpolation-method@5.0.12': + resolution: {integrity: sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-hwb-function@4.0.12': + resolution: {integrity: sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-ic-unit@4.0.4': + resolution: {integrity: sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-initial@2.0.1': + resolution: {integrity: sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-is-pseudo-class@5.0.3': + resolution: {integrity: sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-light-dark-function@2.0.11': + resolution: {integrity: sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-float-and-clear@3.0.0': + resolution: {integrity: sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-overflow@2.0.0': + resolution: {integrity: sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-overscroll-behavior@2.0.0': + resolution: {integrity: sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-resize@3.0.0': + resolution: {integrity: sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-logical-viewport-units@3.0.4': + resolution: {integrity: sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-media-minmax@2.0.9': + resolution: {integrity: sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-media-queries-aspect-ratio-number-values@3.0.5': + resolution: {integrity: sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-nested-calc@4.0.0': + resolution: {integrity: sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-normalize-display-values@4.0.0': + resolution: {integrity: sha512-HlEoG0IDRoHXzXnkV4in47dzsxdsjdz6+j7MLjaACABX2NfvjFS6XVAnpaDyGesz9gK2SC7MbNwdCHusObKJ9Q==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-oklab-function@4.0.12': + resolution: {integrity: sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-position-area-property@1.0.0': + resolution: {integrity: sha512-fUP6KR8qV2NuUZV3Cw8itx0Ep90aRjAZxAEzC3vrl6yjFv+pFsQbR18UuQctEKmA72K9O27CoYiKEgXxkqjg8Q==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-progressive-custom-properties@4.2.1': + resolution: {integrity: sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-random-function@2.0.1': + resolution: {integrity: sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-relative-color-syntax@3.0.12': + resolution: {integrity: sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-scope-pseudo-class@4.0.1': + resolution: {integrity: sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-sign-functions@1.1.4': + resolution: {integrity: sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-stepped-value-functions@4.0.9': + resolution: {integrity: sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-system-ui-font-family@1.0.0': + resolution: {integrity: sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-text-decoration-shorthand@4.0.3': + resolution: {integrity: sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-trigonometric-functions@4.0.9': + resolution: {integrity: sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/postcss-unset-value@4.0.0': + resolution: {integrity: sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-resolve-nested@3.1.0': + resolution: {integrity: sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + + '@csstools/utilities@2.0.0': + resolution: {integrity: sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@ctrl/tinycolor@4.2.0': + resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} + engines: {node: '>=14'} + + '@dual-bundle/import-meta-resolve@4.2.1': + resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/unitless@0.8.1': + resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + + '@es-joy/jsdoccomment@0.76.0': + resolution: {integrity: sha512-g+RihtzFgGTx2WYCuTHbdOXJeAlGnROws0TeALx9ow/ZmOROOZkVg5wp/B44n0WJgI4SQFP1eWM2iRPlU2Y14w==} + engines: {node: '>=20.11.0'} + + '@es-joy/jsdoccomment@0.78.0': + resolution: {integrity: sha512-rQkU5u8hNAq2NVRzHnIUUvR6arbO0b6AOlvpTNS48CkiKSn/xtNfOzBK23JE4SiW89DgvU7GtxLVgV4Vn2HBAw==} + engines: {node: '>=20.11.0'} + + '@es-joy/resolve.exports@1.2.0': + resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} + engines: {node: '>=10'} + + '@esbuild/aix-ppc64@0.25.3': + resolution: {integrity: sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.3': + resolution: {integrity: sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.3': + resolution: {integrity: sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.3': + resolution: {integrity: sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.3': + resolution: {integrity: sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.3': + resolution: {integrity: sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.3': + resolution: {integrity: sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.3': + resolution: {integrity: sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.3': + resolution: {integrity: sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.3': + resolution: {integrity: sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.3': + resolution: {integrity: sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.3': + resolution: {integrity: sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.3': + resolution: {integrity: sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.3': + resolution: {integrity: sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.3': + resolution: {integrity: sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.3': + resolution: {integrity: sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.3': + resolution: {integrity: sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.3': + resolution: {integrity: sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.3': + resolution: {integrity: sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.3': + resolution: {integrity: sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.3': + resolution: {integrity: sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.25.3': + resolution: {integrity: sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.3': + resolution: {integrity: sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.3': + resolution: {integrity: sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.3': + resolution: {integrity: sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@floating-ui/vue@1.1.9': + resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + + '@highlightjs/vue-plugin@2.1.0': + resolution: {integrity: sha512-E+bmk4ncca+hBEYRV2a+1aIzIV0VSY/e5ArjpuSN9IO7wBJrzUE2u4ESCwrbQD7sAy+jWQjkV5qCCWgc+pu7CQ==} + peerDependencies: + highlight.js: ^11.0.1 + vue: ^3.5.24 + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@iconify/icons-ant-design@1.2.7': + resolution: {integrity: sha512-X5OaFEhBroyUZru7aYi30q1EkLcAtqQqTdsq4g8oJUJOuVL8CxS43naaJVlFFgHj+F9QnuCT65yTpTIW3mdQEg==} + + '@iconify/icons-arcticons@1.2.77': + resolution: {integrity: sha512-N7RoFR/YmOgKj96kkU+DFxghkrxvaJo5huKW/CsBk1Di94CLRQSwVy8AXa6hKh04q3ThfpO89zgeeWhp1VlC9g==} + + '@iconify/icons-fa-brands@1.2.4': + resolution: {integrity: sha512-MnUUfPhKJ6ECvVNxipBCmyuvJPDgRJcJ1f9nfgv0obikp6D9d6dGtMrR+bw4Gku6Gr/WCnS1e/Qd5gdmXlE84w==} + + '@iconify/icons-flat-color-icons@1.2.5': + resolution: {integrity: sha512-tlvRMTNVE006O1FFEb59TbseADRSeiDIg7tvZdPpCo7aRIzGyaeoI3A4SUl7ufdmKR8W36Sm4J3v0LccLVOfGA==} + + '@iconify/icons-la@1.2.3': + resolution: {integrity: sha512-CD/7X9NXRPV0Ow7OKlBWBLvfQQPoBmJx/v4UWWX0LVMbwu1Mfftfg2hb4EeIjxbWaE5dBMkWGoc88YhV3K1vrA==} + + '@iconify/icons-logos@1.2.36': + resolution: {integrity: sha512-RVdZE9figuWmd8HeVmM8oQvOdv/4YzXV6lZ+G9QJgzCB/VBLV0inPltZxOt939oj4GbKbr7PF6J4bADMua/GPw==} + + '@iconify/icons-ri@1.2.10': + resolution: {integrity: sha512-w/Xu177artcK7P1LPUMq85WcRbqFE8sKYQEuNfEkuex/47DOaCgW6oBFdjlFBAmBczKlsJPdcy2pAGBGZvXdYw==} + + '@iconify/icons-simple-icons@1.2.74': + resolution: {integrity: sha512-bsmbvwO8hauz49z740CYg70IDevOgshUoq4q1IKt6NnElnn+N2F6AseO3Uti82yUU4OHyQqkWjjUwoPTazlNnA==} + + '@iconify/icons-uiw@1.2.6': + resolution: {integrity: sha512-y6LCoHQ3o1/C5cYipQ5/kt6I4h15JOS5YzBvv2INpj4kSEdUuZ4u9SF4gsLxKqLMxDlTE+mF9skF+Qaypputpw==} + + '@iconify/json@2.2.417': + resolution: {integrity: sha512-/MzthgckJ4vEwdHmAbAn6Bph5WnR4tzVcHMs/nZl3v5hOVRw80SK28UPnG7jjsCB41WWjWPnWdMEdOZfUMZS5w==} + + '@iconify/tailwind@1.2.0': + resolution: {integrity: sha512-KgpIHWOTcRYw1XcoUqyNSrmYyfLLqZYu3AmP8zdfLk0F5TqRO8YerhlvlQmGfn7rJXgPeZN569xPAJnJ53zZxA==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/vue@5.0.0': + resolution: {integrity: sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==} + peerDependencies: + vue: ^3.5.24 + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@internationalized/date@3.10.1': + resolution: {integrity: sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==} + + '@internationalized/number@3.6.5': + resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} + + '@intlify/bundle-utils@10.0.1': + resolution: {integrity: sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ==} + engines: {node: '>= 18'} + peerDependencies: + petite-vue-i18n: '*' + vue-i18n: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + + '@intlify/core-base@11.2.7': + resolution: {integrity: sha512-+Ra9I/LAzXDnmv/IrTO03WMCiLya7pHRmGJvNl9fKwx/W4REJ0xaMk2PxCRqnxcBsX443amEMdebQ3R1geiuIw==} + engines: {node: '>= 16'} + + '@intlify/message-compiler@11.2.7': + resolution: {integrity: sha512-TFamC+GzJAotAFwUNvbtRVBgvuSn2nCwKNresmPUHv3IIVMmXJt7QQJj/DORI1h8hs46ZF6L0Fs2xBohSOE4iQ==} + engines: {node: '>= 16'} + + '@intlify/shared@11.2.7': + resolution: {integrity: sha512-uvlkvc/0uQ4FDlHQZccpUnmcOwNcaI3i+69ck2YJ+GqM35AoVbuS63b+YfirV4G0SZh64Ij2UMcFRMmB4nr95w==} + engines: {node: '>= 16'} + + '@intlify/unplugin-vue-i18n@6.0.8': + resolution: {integrity: sha512-Vvm3KhjE6TIBVUQAk37rBiaYy2M5OcWH0ZcI1XKEsOTeN1o0bErk+zeuXmcrcMc/73YggfI8RoxOUz9EB/69JQ==} + engines: {node: '>= 18'} + peerDependencies: + petite-vue-i18n: '*' + vue: ^3.5.24 + vue-i18n: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + + '@intlify/vue-i18n-extensions@8.0.0': + resolution: {integrity: sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ==} + engines: {node: '>= 18'} + peerDependencies: + '@intlify/shared': ^9.0.0 || ^10.0.0 || ^11.0.0 + '@vue/compiler-dom': ^3.0.0 + vue: ^3.5.24 + vue-i18n: ^9.0.0 || ^10.0.0 || ^11.0.0 + peerDependenciesMeta: + '@intlify/shared': + optional: true + '@vue/compiler-dom': + optional: true + vue: + optional: true + vue-i18n: + optional: true + + '@ioredis/commands@1.4.0': + resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==} + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jspm/generator@2.8.0': + resolution: {integrity: sha512-7HfZs8m6gEg9JSsio/3uoYWMEHU7kaOZPuHQCDeR3Us86Kd5aaBPn3Dv3UogVAJZsBu+SjIjGb/nIf8G4hWyog==} + + '@jspm/import-map@1.2.2': + resolution: {integrity: sha512-QrM7+lkgVE8t9NZSm9fDSzheguEOVCOxueKxSwgoOt7yUWesWKDFmmL9bQFURl4IqMcpPz7VV2Tvw9s9emaJzQ==} + + '@keyv/bigmap@1.3.0': + resolution: {integrity: sha512-KT01GjzV6AQD5+IYrcpoYLkCu1Jod3nau1Z7EsEuViO3TZGRacSbO9MfHmbJ1WaOXFtWLxPVj169cn2WNKPkIg==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.5.4 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/find-root@3.1.0': + resolution: {integrity: sha512-BcSqCyKhBVZ5YkSzOiheMCV41kqAFptW6xGqYSTjkVTl9XQpr+pqHhwgGCOHQtjDCv7Is6EFyA14Sm5GVbVABA==} + engines: {node: '>=20.0.0'} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + + '@manypkg/get-packages@3.1.0': + resolution: {integrity: sha512-0TbBVyvPrP7xGYBI/cP8UP+yl/z+HtbTttAD7FMAJgn/kXOTwh5/60TsqP9ZYY710forNfyV0N8P/IE/ujGZJg==} + engines: {node: '>=20.0.0'} + + '@manypkg/tools@2.1.0': + resolution: {integrity: sha512-0FOIepYR4ugPYaHwK7hDeHDkfPOBVvayt9QpvRbi2LT/h2b0GaE/gM9Gag7fsnyYyNaTZ2IGyOuVg07IYepvYQ==} + engines: {node: '>=20.0.0'} + + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} + hasBin: true + + '@microsoft/api-extractor-model@7.32.2': + resolution: {integrity: sha512-Ussc25rAalc+4JJs9HNQE7TuO9y6jpYQX9nWD1DhqUzYPBr3Lr7O9intf+ZY8kD5HnIqeIRJX7ccCT0QyBy2Ww==} + + '@microsoft/api-extractor@7.55.2': + resolution: {integrity: sha512-1jlWO4qmgqYoVUcyh+oXYRztZde/pAi7cSVzBz/rc+S7CoVzDasy8QE13dx6sLG4VRo8SfkkLbFORR6tBw4uGQ==} + hasBin: true + + '@microsoft/tsdoc-config@0.18.0': + resolution: {integrity: sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@npmcli/fs@5.0.0': + resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@nuxt/kit@3.20.2': + resolution: {integrity: sha512-laqfmMcWWNV1FsVmm1+RQUoGY8NIJvCRl0z0K8ikqPukoEry0LXMqlQ+xaf8xJRvoH2/78OhZmsEEsUBTXipcw==} + engines: {node: '>=18.12.0'} + + '@nuxt/kit@4.2.2': + resolution: {integrity: sha512-ZAgYBrPz/yhVgDznBNdQj2vhmOp31haJbO0I0iah/P9atw+OHH7NJLUZ3PK+LOz/0fblKTN1XJVSi8YQ1TQ0KA==} + engines: {node: '>=18.12.0'} + + '@one-ini/wasm@0.1.1': + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + + '@parcel/watcher-android-arm64@2.5.1': + resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + + '@parcel/watcher-darwin-arm64@2.5.1': + resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + + '@parcel/watcher-darwin-x64@2.5.1': + resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + + '@parcel/watcher-freebsd-x64@2.5.1': + resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + + '@parcel/watcher-linux-arm-glibc@2.5.1': + resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm-musl@2.5.1': + resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-arm64-musl@2.5.1': + resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@parcel/watcher-linux-x64-glibc@2.5.1': + resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@parcel/watcher-linux-x64-musl@2.5.1': + resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@parcel/watcher-wasm@2.5.1': + resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} + engines: {node: '>= 10.0.0'} + bundledDependencies: + - napi-wasm + + '@parcel/watcher-win32-arm64@2.5.1': + resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + + '@parcel/watcher-win32-ia32@2.5.1': + resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.1': + resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + + '@parcel/watcher@2.5.1': + resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + engines: {node: '>= 10.0.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@playwright/test@1.57.0': + resolution: {integrity: sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==} + engines: {node: '>=18'} + hasBin: true + + '@pnpm/config.env-replace@1.1.0': + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + + '@pnpm/constants@1001.3.1': + resolution: {integrity: sha512-2hf0s4pVrVEH8RvdJJ7YRKjQdiG8m0iAT26TTqXnCbK30kKwJW69VLmP5tED5zstmDRXcOeH5eRcrpkdwczQ9g==} + engines: {node: '>=18.12'} + + '@pnpm/error@1000.0.5': + resolution: {integrity: sha512-GjH0TPjbVNrPnl/BAGoFuBLJ2sFfXNKbS33lll/Ehe9yw0fyc8Kdw7kO9if37yQqn6vaa4dAHKkPllum7f/IPQ==} + engines: {node: '>=18.12'} + + '@pnpm/network.ca-file@1.0.2': + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + + '@pnpm/npm-conf@2.3.1': + resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + engines: {node: '>=12'} + + '@pnpm/types@1001.2.0': + resolution: {integrity: sha512-UIju+OadUVS0q5q/MbRAzMS5M9HZcZyT6evyrgPUH0DV9przkcW7/LH1Sj33Q2MpJO9Nzqw4b4w72x8mvtUAew==} + engines: {node: '>=18.12'} + + '@pnpm/workspace.read-manifest@1000.2.9': + resolution: {integrity: sha512-zyJf9UQrC6dyEyKm9aUkBChAFEC6wk5Lhn5c/UtRGOlncKC68gxmNJXIQa9seRidLA0ExvJkIack7ThHe4Efow==} + engines: {node: '>=18.12'} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@publint/pack@0.1.2': + resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} + engines: {node: '>=18'} + + '@rolldown/pluginutils@1.0.0-beta.53': + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + + '@rolldown/pluginutils@1.0.0-beta.57': + resolution: {integrity: sha512-aQNelgx14tGA+n2tNSa9x6/jeoCL9fkDeCei7nOKnHx0fEFRRMu5ReiITo+zZD5TzWDGGRjbSYCs93IfRIyTuQ==} + + '@rollup/plugin-alias@5.1.1': + resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-babel@5.3.1': + resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} + engines: {node: '>= 10.0.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@types/babel__core': ^7.1.9 + rollup: ^1.20.0||^2.0.0 + peerDependenciesMeta: + '@types/babel__core': + optional: true + + '@rollup/plugin-commonjs@28.0.9': + resolution: {integrity: sha512-PIR4/OHZ79romx0BVVll/PkwWpJ7e5lsqFa3gFfcrFPWwLXLV39JVUzQV9RKjWerE7B845Hqjj9VYlQeieZ2dA==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-inject@5.0.5': + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-json@6.1.0': + resolution: {integrity: sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@15.3.1': + resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-replace@2.4.2': + resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-terser@0.4.4': + resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@3.1.0': + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.54.0': + resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.54.0': + resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.54.0': + resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.54.0': + resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.54.0': + resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.54.0': + resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.54.0': + resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.54.0': + resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.54.0': + resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.54.0': + resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-gnu@4.54.0': + resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-gnu@4.54.0': + resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.54.0': + resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.54.0': + resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.54.0': + resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.54.0': + resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openharmony-arm64@4.54.0': + resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.54.0': + resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.54.0': + resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.54.0': + resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.54.0': + resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} + cpu: [x64] + os: [win32] + + '@rushstack/node-core-library@5.19.1': + resolution: {integrity: sha512-ESpb2Tajlatgbmzzukg6zyAhH+sICqJR2CNXNhXcEbz6UGCQfrKCtkxOpJTftWc8RGouroHG0Nud1SJAszvpmA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/problem-matcher@0.1.1': + resolution: {integrity: sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.6.0': + resolution: {integrity: sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==} + + '@rushstack/terminal@0.19.5': + resolution: {integrity: sha512-6k5tpdB88G0K7QrH/3yfKO84HK9ggftfUZ51p7fePyCE7+RLLHkWZbID9OFWbXuna+eeCFE7AkKnRMHMxNbz7Q==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@5.1.5': + resolution: {integrity: sha512-YmrFTFUdHXblYSa+Xc9OO9FsL/XFcckZy0ycQ6q7VSBsVs5P0uD9vcges5Q9vctGlVdu27w+Ct6IuJ458V0cTQ==} + + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + + '@simonwep/pickr@1.8.2': + resolution: {integrity: sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==} + + '@sindresorhus/base62@1.0.0': + resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} + engines: {node: '>=18'} + + '@sindresorhus/is@7.1.1': + resolution: {integrity: sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.12': + resolution: {integrity: sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA==} + + '@stylistic/stylelint-plugin@3.1.3': + resolution: {integrity: sha512-85fsmzgsIVmyG3/GFrjuYj6Cz8rAM7IZiPiXCMiSMfoDOC1lOrzrXPDk24WqviAghnPqGpx8b0caK2PuewWGFg==} + engines: {node: ^18.12 || >=20.9} + peerDependencies: + stylelint: ^16.8.0 + + '@surma/rollup-plugin-off-main-thread@2.2.3': + resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} + + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + + '@tailwindcss/nesting@0.0.0-insiders.565cd3e': + resolution: {integrity: sha512-WhHoFBx19TnH/c+xLwT/sxei6+4RpdfiyG3MYXfmLaMsADmVqBkF7B6lDalgZD9YdM459MF7DtxVbWkOrV7IaQ==} + peerDependencies: + postcss: ^8.2.15 + + '@tailwindcss/typography@0.5.19': + resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + + '@tanstack/virtual-core@3.13.13': + resolution: {integrity: sha512-uQFoSdKKf5S8k51W5t7b2qpfkyIbdHMzAn+AMQvHPxKUPeo1SsGaA4JRISQT87jm28b7z8OEqPcg1IOZagQHcA==} + + '@tanstack/vue-store@0.8.0': + resolution: {integrity: sha512-YLsinYboBLIjNkxDpAn1ydaMS35dKq3M3a788JRCJi4/stWcN7Swp0pxxJ+p0IwKSY4tBXx7vMz22OYWQ1QsUQ==} + peerDependencies: + '@vue/composition-api': ^1.2.1 + vue: ^3.5.24 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + '@tanstack/vue-virtual@3.13.13': + resolution: {integrity: sha512-Cf2xIEE8nWAfsX0N5nihkPYMeQRT+pHt4NEkuP8rNCn6lVnLDiV8rC8IeIxbKmQC0yPnj4SIBLwXYVf86xxKTQ==} + peerDependencies: + vue: ^3.5.24 + + '@tinymce/tinymce-vue@6.3.0': + resolution: {integrity: sha512-DSP8Jhd3XqCCliTnusfbmz3D8GqQ4iRzkc4aadYHDcJPVjkaqopJ61McOdH82CSy599vGLkPjGzqJYWJkRMiUA==} + peerDependencies: + tinymce: ^8.0.0 || ^7.0.0 || ^6.0.0 || ^5.5.1 + vue: ^3.5.24 + peerDependenciesMeta: + tinymce: + optional: true + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/archiver@6.0.4': + resolution: {integrity: sha512-ULdQpARQ3sz9WH4nb98mJDYA0ft2A8C4f4fovvUcFwINa1cgGjY36JCAYuP5YypRq4mco1lJp1/7jEMS2oR0Hg==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/bintrees@1.0.6': + resolution: {integrity: sha512-pZWT4Bz+tWwxlDspSjdoIza4PE5lbGI4Xvs3FZV/2v5m5SDA8LwNpU8AXxlndmARO7OaQ1Vf3zFenOsNMzaRkQ==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/conventional-commits-parser@5.0.2': + resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@0.0.39': + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/html-minifier-terser@7.0.2': + resolution: {integrity: sha512-mm2HqV22l8lFQh4r2oSsOEVea+m0qqxEmwpc9kC1p/XzmjLWrReR9D/GRs8Pex2NX/imyEH9c5IU/7tMBQCHOA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash.clonedeep@4.5.9': + resolution: {integrity: sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q==} + + '@types/lodash.get@4.4.9': + resolution: {integrity: sha512-J5dvW98sxmGnamqf+/aLP87PYXyrha9xIgc2ZlHl6OHMFR2Ejdxep50QfU0abO1+CH6+ugx+8wEUN1toImAinA==} + + '@types/lodash.isequal@4.5.8': + resolution: {integrity: sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==} + + '@types/lodash.set@4.3.9': + resolution: {integrity: sha512-KOxyNkZpbaggVmqbpr82N2tDVTx05/3/j0f50Es1prxrWB0XYf9p3QNxqcbWb7P1Q9wlvsUSlCFnwlPCIJ46PQ==} + + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + + '@types/minimatch@3.0.5': + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@24.10.4': + resolution: {integrity: sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==} + + '@types/node@25.0.3': + resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} + + '@types/nprogress@0.2.3': + resolution: {integrity: sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/postcss-import@14.0.3': + resolution: {integrity: sha512-raZhRVTf6Vw5+QbmQ7LOHSDML71A5rj4+EqDzAbrZPfxfoGzFxMHRCq16VlddGIZpHELw0BG4G0YE2ANkdZiIQ==} + + '@types/qrcode@1.5.6': + resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/readdir-glob@1.1.5': + resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@types/sortablejs@1.15.9': + resolution: {integrity: sha512-7HP+rZGE2p886PKV9c9OJzLBI6BBJu1O7lJGYnPyG3fS4/duUCcngkNCjsLwIMV+WMqANe3tt4irrXHSIe68OQ==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + + '@typescript-eslint/eslint-plugin@8.50.1': + resolution: {integrity: sha512-PKhLGDq3JAg0Jk/aK890knnqduuI/Qj+udH7wCf0217IGi4gt+acgCyPVe79qoT+qKUvHMDQkwJeKW9fwl8Cyw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.50.1 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.50.1': + resolution: {integrity: sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.50.1': + resolution: {integrity: sha512-E1ur1MCVf+YiP89+o4Les/oBAVzmSbeRB0MQLfSlYtbWU17HPxZ6Bhs5iYmKZRALvEuBoXIZMOIRRc/P++Ortg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@7.18.0': + resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/scope-manager@8.50.1': + resolution: {integrity: sha512-mfRx06Myt3T4vuoHaKi8ZWNTPdzKPNBhiblze5N50//TSHOAQQevl/aolqA/BcqqbJ88GUnLqjjcBc8EWdBcVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.50.1': + resolution: {integrity: sha512-ooHmotT/lCWLXi55G4mvaUF60aJa012QzvLK0Y+Mp4WdSt17QhMhWOaBWeGTFVkb2gDgBe19Cxy1elPXylslDw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.50.1': + resolution: {integrity: sha512-7J3bf022QZE42tYMO6SL+6lTPKFk/WphhRPe9Tw/el+cEwzLz1Jjz2PX3GtGQVxooLDKeMVmMt7fWpYRdG5Etg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@7.18.0': + resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/types@8.50.1': + resolution: {integrity: sha512-v5lFIS2feTkNyMhd7AucE/9j/4V9v5iIbpVRncjk/K0sQ6Sb+Np9fgYS/63n6nwqahHQvbmujeBL7mp07Q9mlA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@7.18.0': + resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@8.50.1': + resolution: {integrity: sha512-woHPdW+0gj53aM+cxchymJCrh0cyS7BTIdcDxWUNsclr9VDkOSbqC13juHzxOmQ22dDkMZEpZB+3X1WpUvzgVQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@7.18.0': + resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + + '@typescript-eslint/utils@8.50.1': + resolution: {integrity: sha512-lCLp8H1T9T7gPbEuJSnHwnSuO9mDf8mfK/Nion5mZmiEaQD9sWf9W4dfeFqRyqRjF06/kBuTmAqcs9sewM2NbQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@7.18.0': + resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/visitor-keys@8.50.1': + resolution: {integrity: sha512-IrDKrw7pCRUR94zeuCSUWQ+w8JEf5ZX5jl/e6AHGSLi1/zIr0lgutfn/7JpfCey+urpgQEdrZVYzCaVVKiTwhQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@vee-validate/zod@4.15.1': + resolution: {integrity: sha512-329Z4TDBE5Vx0FdbA8S4eR9iGCFFUNGbxjpQ20ff5b5wGueScjocUIx9JHPa79LTG06RnlUR4XogQsjN4tecKA==} + peerDependencies: + zod: ^3.24.0 + + '@vercel/nft@0.30.4': + resolution: {integrity: sha512-wE6eAGSXScra60N2l6jWvNtVK0m+sh873CpfZW4KI2v8EHuUQp+mSEi4T+IcdPCSEDgCdAS/7bizbhQlkjzrSA==} + engines: {node: '>=18'} + hasBin: true + + '@vitejs/plugin-vue-jsx@5.1.3': + resolution: {integrity: sha512-I6Zr8cYVr5WHMW5gNOP09DNqW9rgO8RX73Wa6Czgq/0ndpTfJM4vfDChfOT1+3KtdrNqilNBtNlFwVeB02ZzGw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.5.24 + + '@vitejs/plugin-vue@6.0.3': + resolution: {integrity: sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + vue: ^3.5.24 + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + + '@volar/language-core@2.4.27': + resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} + + '@volar/source-map@2.4.27': + resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==} + + '@volar/typescript@2.4.27': + resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==} + + '@vue/babel-helper-vue-transform-on@1.5.0': + resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==} + + '@vue/babel-helper-vue-transform-on@2.0.1': + resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} + + '@vue/babel-plugin-jsx@1.5.0': + resolution: {integrity: sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-jsx@2.0.1': + resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + + '@vue/babel-plugin-resolve-type@1.5.0': + resolution: {integrity: sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/babel-plugin-resolve-type@2.0.1': + resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@vue/compiler-core@3.5.26': + resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} + + '@vue/compiler-dom@3.5.26': + resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==} + + '@vue/compiler-sfc@3.5.26': + resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==} + + '@vue/compiler-ssr@3.5.26': + resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + '@vue/devtools-api@7.7.9': + resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==} + + '@vue/devtools-core@8.0.5': + resolution: {integrity: sha512-dpCw8nl0GDBuiL9SaY0mtDxoGIEmU38w+TQiYEPOLhW03VDC0lfNMYXS/qhl4I0YlysGp04NLY4UNn6xgD0VIQ==} + peerDependencies: + vue: ^3.5.24 + + '@vue/devtools-kit@7.7.9': + resolution: {integrity: sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==} + + '@vue/devtools-kit@8.0.5': + resolution: {integrity: sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==} + + '@vue/devtools-shared@7.7.9': + resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} + + '@vue/devtools-shared@8.0.5': + resolution: {integrity: sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==} + + '@vue/language-core@2.2.0': + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/language-core@3.2.1': + resolution: {integrity: sha512-g6oSenpnGMtpxHGAwKuu7HJJkNZpemK/zg3vZzZbJ6cnnXq1ssxuNrXSsAHYM3NvH8p4IkTw+NLmuxyeYz4r8A==} + + '@vue/reactivity@3.5.26': + resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==} + + '@vue/runtime-core@3.5.26': + resolution: {integrity: sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==} + + '@vue/runtime-dom@3.5.26': + resolution: {integrity: sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==} + + '@vue/server-renderer@3.5.26': + resolution: {integrity: sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==} + peerDependencies: + vue: ^3.5.24 + + '@vue/shared@3.5.26': + resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} + + '@vue/test-utils@2.4.6': + resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + + '@vueuse/core@12.8.2': + resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} + + '@vueuse/core@13.9.0': + resolution: {integrity: sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==} + peerDependencies: + vue: ^3.5.24 + + '@vueuse/core@14.1.0': + resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} + peerDependencies: + vue: ^3.5.24 + + '@vueuse/integrations@14.1.0': + resolution: {integrity: sha512-eNQPdisnO9SvdydTIXnTE7c29yOsJBD/xkwEyQLdhDC/LKbqrFpXHb3uS//7NcIrQO3fWVuvMGp8dbK6mNEMCA==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 || ^8 + vue: ^3.5.24 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@12.8.2': + resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} + + '@vueuse/metadata@13.9.0': + resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==} + + '@vueuse/metadata@14.1.0': + resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} + + '@vueuse/motion@3.0.3': + resolution: {integrity: sha512-4B+ITsxCI9cojikvrpaJcLXyq0spj3sdlzXjzesWdMRd99hhtFI6OJ/1JsqwtF73YooLe0hUn/xDR6qCtmn5GQ==} + peerDependencies: + vue: ^3.5.24 + + '@vueuse/shared@12.8.2': + resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} + + '@vueuse/shared@13.9.0': + resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==} + peerDependencies: + vue: ^3.5.24 + + '@vueuse/shared@14.1.0': + resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} + peerDependencies: + vue: ^3.5.24 + + '@vxe-ui/core@4.2.16': + resolution: {integrity: sha512-clfS0UcW15I+vWDVv7+D7ifYb1UgG1As3lUPPyROSN01bDiAzbDEoyOg4bLlvjhySN+m4qbSb+SEV6gosbo9yA==} + peerDependencies: + vue: ^3.5.24 + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + + alien-signals@3.1.1: + resolution: {integrity: sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@7.2.0: + resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + ant-design-vue@4.2.6: + resolution: {integrity: sha512-t7eX13Yj3i9+i5g9lqFyYneoIb3OzTvQjq9Tts1i+eiOd3Eva/6GagxBSXM1fOCjqemIu0FYVE1ByZ/38epR3Q==} + engines: {node: '>=12.22.0'} + peerDependencies: + vue: ^3.5.24 + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + archiver-utils@5.0.2: + resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} + engines: {node: '>= 14'} + + archiver@7.0.1: + resolution: {integrity: sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==} + engines: {node: '>= 14'} + + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-differ@3.0.0: + resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} + engines: {node: '>=8'} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + array-timsort@1.0.3: + resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + + array-tree-filter@2.1.0: + resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + arrify@2.0.1: + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + + async-validator@4.2.5: + resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + atomically@2.1.0: + resolution: {integrity: sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q==} + + autoprefixer@10.4.23: + resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios-mock-adapter@2.1.0: + resolution: {integrity: sha512-AZUe4OjECGCNNssH8SOdtneiQELsqTsat3SQQCWLPjN436/H+L9AjWfV7bF+Zg/YL9cgbhrz5671hoh+Tbn98w==} + peerDependencies: + axios: '>= 0.17.0' + + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + + b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + babel-plugin-polyfill-corejs2@0.4.14: + resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.13.0: + resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.5: + resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.9.11: + resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} + hasBin: true + + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bintrees@1.0.2: + resolution: {integrity: sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + boxen@8.0.1: + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@1.0.0: + resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} + engines: {node: '>=8.0.0'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + builtin-modules@5.0.0: + resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} + engines: {node: '>=18.20'} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + c12@3.3.3: + resolution: {integrity: sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cacache@20.0.3: + resolution: {integrity: sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==} + engines: {node: ^20.17.0 || >=22.9.0} + + cacheable@2.3.1: + resolution: {integrity: sha512-yr+FSHWn1ZUou5LkULX/S+jhfgfnLbuKQjE40tyEd4fxGZVMbBL5ifno0J0OauykS8UiCSgHi+DV/YD+rjFxFg==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsite@1.0.0: + resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001761: + resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chalk-template@1.1.2: + resolution: {integrity: sha512-2bxTP2yUH7AJj/VAXfcA+4IcWGdQ87HwBANLt5XxGTeomo8yG0y95N1um9i5StvhT/Bl0/2cARA5v1PpPXUxUA==} + engines: {node: '>=14.16'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.1.2: + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + circular-dependency-scanner@2.3.0: + resolution: {integrity: sha512-J1a6SeOL1pfaVdCVECg4h1cLxZipjnibha2uutY7gG7Ax8lre03sWdK1raJew0P+8AGv9/zRF5DCWHkceOYPBQ==} + hasBin: true + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} + engines: {node: '>= 10.0'} + + clean-regexp@1.0.0: + resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} + engines: {node: '>=4'} + + clear-module@4.1.2: + resolution: {integrity: sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==} + engines: {node: '>=8'} + + cli-boxes@3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + clipboard@2.0.11: + resolution: {integrity: sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==} + + clipboardy@4.0.0: + resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} + engines: {node: '>=18'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + comment-json@4.5.0: + resolution: {integrity: sha512-aKl8CwoMKxVTfAK4dFN4v54AEvuUh9pzmgVIBeK6gBomLwMgceQUKKWHzJdW1u1VQXQuwnJ7nJGWYYMTl5U4yg==} + engines: {node: '>= 6'} + + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} + + commitlint-plugin-function-rules@4.2.0: + resolution: {integrity: sha512-v0FKexDFIOgb1ca5fMIpPrYf2VCSyx2dkw5ayCXW7nHF/u4TzAJu1ATFhWj1XfKjq2Gr1/3FVAoLEx/Xm9Lisw==} + engines: {node: '>=20'} + peerDependencies: + '@commitlint/lint': '>=19 <21' + + common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + compatx@0.2.0: + resolution: {integrity: sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==} + + compress-commons@6.0.2: + resolution: {integrity: sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==} + engines: {node: '>= 14'} + + compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + + configstore@7.1.0: + resolution: {integrity: sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==} + engines: {node: '>=18'} + + connect-history-api-fallback@1.6.0: + resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} + engines: {node: '>=0.8'} + + consola@2.15.3: + resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + conventional-changelog-angular@7.0.0: + resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} + engines: {node: '>=16'} + + conventional-changelog-conventionalcommits@7.0.2: + resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} + engines: {node: '>=16'} + + conventional-commits-parser@5.0.0: + resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} + engines: {node: '>=16'} + hasBin: true + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} + + core-js-compat@3.47.0: + resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + + core-js@3.47.0: + resolution: {integrity: sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig-typescript-loader@6.2.0: + resolution: {integrity: sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==} + engines: {node: '>=v18'} + peerDependencies: + '@types/node': '*' + cosmiconfig: '>=9' + typescript: '>=5' + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@6.0.0: + resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} + engines: {node: '>= 14'} + + croner@9.1.0: + resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} + engines: {node: '>=18.0'} + + cropperjs@1.6.2: + resolution: {integrity: sha512-nhymn9GdnV3CqiEHJVai54TULFAE3VshJTXSqSJKa8yXAKyBKDWdhHarnlIPrshJ0WMFTGuFvG02YjLXfPiuOA==} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + + crypto-random-string@2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + + cspell-config-lib@8.19.4: + resolution: {integrity: sha512-LtFNZEWVrnpjiTNgEDsVN05UqhhJ1iA0HnTv4jsascPehlaUYVoyucgNbFeRs6UMaClJnqR0qT9lnPX+KO1OLg==} + engines: {node: '>=18'} + + cspell-dictionary@8.19.4: + resolution: {integrity: sha512-lr8uIm7Wub8ToRXO9f6f7in429P1Egm3I+Ps3ZGfWpwLTCUBnHvJdNF/kQqF7PL0Lw6acXcjVWFYT7l2Wdst2g==} + engines: {node: '>=18'} + + cspell-gitignore@8.19.4: + resolution: {integrity: sha512-KrViypPilNUHWZkMV0SM8P9EQVIyH8HvUqFscI7+cyzWnlglvzqDdV4N5f+Ax5mK+IqR6rTEX8JZbCwIWWV7og==} + engines: {node: '>=18'} + hasBin: true + + cspell-glob@8.19.4: + resolution: {integrity: sha512-042uDU+RjAz882w+DXKuYxI2rrgVPfRQDYvIQvUrY1hexH4sHbne78+OMlFjjzOCEAgyjnm1ktWUCCmh08pQUw==} + engines: {node: '>=18'} + + cspell-grammar@8.19.4: + resolution: {integrity: sha512-lzWgZYTu/L7DNOHjxuKf8H7DCXvraHMKxtFObf8bAzgT+aBmey5fW2LviXUkZ2Lb2R0qQY+TJ5VIGoEjNf55ow==} + engines: {node: '>=18'} + hasBin: true + + cspell-io@8.19.4: + resolution: {integrity: sha512-W48egJqZ2saEhPWf5ftyighvm4mztxEOi45ILsKgFikXcWFs0H0/hLwqVFeDurgELSzprr12b6dXsr67dV8amg==} + engines: {node: '>=18'} + + cspell-lib@8.19.4: + resolution: {integrity: sha512-NwfdCCYtIBNQuZcoMlMmL3HSv2olXNErMi/aOTI9BBAjvCHjhgX5hbHySMZ0NFNynnN+Mlbu5kooJ5asZeB3KA==} + engines: {node: '>=18'} + + cspell-trie-lib@8.19.4: + resolution: {integrity: sha512-yIPlmGSP3tT3j8Nmu+7CNpkPh/gBO2ovdnqNmZV+LNtQmVxqFd2fH7XvR1TKjQyctSH1ip0P5uIdJmzY1uhaYg==} + engines: {node: '>=18'} + + cspell@8.19.4: + resolution: {integrity: sha512-toaLrLj3usWY0Bvdi661zMmpKW2DVLAG3tcwkAv4JBTisdIRn15kN/qZDrhSieUEhVgJgZJDH4UKRiq29mIFxA==} + engines: {node: '>=18'} + hasBin: true + + css-blank-pseudo@7.0.1: + resolution: {integrity: sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + css-declaration-sorter@7.3.0: + resolution: {integrity: sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.0.9 + + css-functions-list@3.2.3: + resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} + engines: {node: '>=12 || >=16'} + + css-has-pseudo@7.0.3: + resolution: {integrity: sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + css-prefers-color-scheme@10.0.0: + resolution: {integrity: sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssdb@8.5.2: + resolution: {integrity: sha512-Pmoj9RmD8RIoIzA2EQWO4D4RMeDts0tgAH0VXdlNdxjuBGI3a9wMOIcUwaPNmD4r2qtIa06gqkIf7sECl+cBCg==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-preset-default@7.0.10: + resolution: {integrity: sha512-6ZBjW0Lf1K1Z+0OKUAUpEN62tSXmYChXWi2NAA0afxEVsj9a+MbcB1l5qel6BHJHmULai2fCGRthCeKSFbScpA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + cssnano-utils@5.0.1: + resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + cssnano@7.1.2: + resolution: {integrity: sha512-HYOPBsNvoiFeR1eghKD5C3ASm64v9YVyJB4Ivnl2gqKoQYvjjN/G0rztvKQq8OxocUtC6sjqY8jwYngIB4AByA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + cz-git@1.12.0: + resolution: {integrity: sha512-LaZ+8whPPUOo6Y0Zy4nIbf6JOleV3ejp41sT6N4RPKiKKA+ICWf4ueeIlxIO8b6JtdlDxRzHH/EcRji07nDxcg==} + engines: {node: '>=v12.20.0'} + + czg@1.12.0: + resolution: {integrity: sha512-LGltcoZ5m7vhe3WNw16QXqd5WurnHegx9V15MwZJtFAU2AVCYLCqDbwxPUgZOnAcdzzooq33ONcU148HOQsjdA==} + engines: {node: '>=v12.20.0'} + hasBin: true + + dargs@8.1.0: + resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} + engines: {node: '>=12'} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + dataloader@1.4.0: + resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + + db0@0.3.4: + resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==} + peerDependencies: + '@electric-sql/pglite': '*' + '@libsql/client': '*' + better-sqlite3: '*' + drizzle-orm: '*' + mysql2: '*' + sqlite3: '*' + peerDependenciesMeta: + '@electric-sql/pglite': + optional: true + '@libsql/client': + optional: true + better-sqlite3: + optional: true + drizzle-orm: + optional: true + mysql2: + optional: true + sqlite3: + optional: true + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.4.0: + resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} + engines: {node: '>=18'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + delegate@3.2.0: + resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} + + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + + depcheck@1.4.7: + resolution: {integrity: sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==} + engines: {node: '>=10'} + hasBin: true + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + deps-regex@0.2.0: + resolution: {integrity: sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-file@1.0.0: + resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} + engines: {node: '>=0.10.0'} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff-sequences@27.5.1: + resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-align@1.12.4: + resolution: {integrity: sha512-R8LUSEay/68zE5c8/3BDxiTEvgb4xZTF0RKmAHfiEVN3klfIpXfi2/QCoiWPccVQ0J/ZGdz9OjzL4uJEP/MRAw==} + + dom-scroll-into-view@2.0.1: + resolution: {integrity: sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==} + + dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + dom-zindex@1.0.6: + resolution: {integrity: sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dot-prop@10.1.0: + resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} + engines: {node: '>=20'} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dot-prop@9.0.0: + resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} + engines: {node: '>=18'} + + dotenv-expand@8.0.3: + resolution: {integrity: sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==} + engines: {node: '>=12'} + + dotenv@16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dotenv@17.2.3: + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + engines: {node: '>=12'} + + dotenv@8.6.0: + resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} + engines: {node: '>=10'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + echarts@6.0.0: + resolution: {integrity: sha512-Tte/grDQRiETQP4xz3iZWSvoHrkCQtwqd6hs+mifXcjrCuo2iKWbajFObuLJVBlDIJlOzgQPd1hsaKt/3+OMkQ==} + + editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + enhanced-resolve@5.18.4: + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + engines: {node: '>=10.13.0'} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + entities@7.0.0: + resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + env-paths@3.0.0: + resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + errx@0.1.0: + resolution: {integrity: sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==} + + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + es-toolkit@1.43.0: + resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} + + esbuild@0.25.3: + resolution: {integrity: sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-goat@4.0.0: + resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} + engines: {node: '>=12'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-compat-utils@0.6.5: + resolution: {integrity: sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-config-turbo@2.7.2: + resolution: {integrity: sha512-Tj8P1kJFVNFZxH+BaQO9sowg11N5PkpD34aWZ87PImqkWo7Qk8yRGRpshCeqGwdO5YKX631ZyTQfcDvs4bqBMQ==} + peerDependencies: + eslint: '>6.6.0' + turbo: '>2.0.0' + + eslint-import-context@0.1.9: + resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true + + eslint-json-compat-utils@0.2.1: + resolution: {integrity: sha512-YzEodbDyW8DX8bImKhAcCeu/L31Dd/70Bidx2Qex9OFUtgzXLqtfWL4Hr5fM/aCCB8QUZLuJur0S9k6UfgFkfg==} + engines: {node: '>=12'} + peerDependencies: + '@eslint/json': '*' + eslint: '*' + jsonc-eslint-parser: ^2.4.0 + peerDependenciesMeta: + '@eslint/json': + optional: true + + eslint-plugin-command@3.4.0: + resolution: {integrity: sha512-EW4eg/a7TKEhG0s5IEti72kh3YOTlnhfFNuctq5WnB1fst37/IHTd5OkD+vnlRf3opTvUcSRihAateP6bT5ZcA==} + peerDependencies: + eslint: '*' + + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + + eslint-plugin-eslint-comments@3.2.0: + resolution: {integrity: sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==} + engines: {node: '>=6.5.0'} + peerDependencies: + eslint: '>=4.19.1' + + eslint-plugin-import-x@4.16.1: + resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/utils': ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + eslint-import-resolver-node: '*' + peerDependenciesMeta: + '@typescript-eslint/utils': + optional: true + eslint-import-resolver-node: + optional: true + + eslint-plugin-jsdoc@61.5.0: + resolution: {integrity: sha512-PR81eOGq4S7diVnV9xzFSBE4CDENRQGP0Lckkek8AdHtbj+6Bm0cItwlFnxsLFriJHspiE3mpu8U20eODyToIg==} + engines: {node: '>=20.11.0'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-jsonc@2.21.0: + resolution: {integrity: sha512-HttlxdNG5ly3YjP1cFMP62R4qKLxJURfBZo2gnMY+yQojZxkLyOpY1H1KRTKBmvQeSG9pIpSGEhDjE17vvYosg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + + eslint-plugin-n@17.23.1: + resolution: {integrity: sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' + + eslint-plugin-no-only-tests@3.3.0: + resolution: {integrity: sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==} + engines: {node: '>=5.0.0'} + + eslint-plugin-perfectionist@4.15.1: + resolution: {integrity: sha512-MHF0cBoOG0XyBf7G0EAFCuJJu4I18wy0zAoT1OHfx2o6EOx1EFTIzr2HGeuZa1kDcusoX0xJ9V7oZmaeFd773Q==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + eslint: '>=8.45.0' + + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-regexp@2.10.0: + resolution: {integrity: sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==} + engines: {node: ^18 || >=20} + peerDependencies: + eslint: '>=8.44.0' + + eslint-plugin-turbo@2.7.2: + resolution: {integrity: sha512-rZs+l0vQcFo/37OiCWDcTIcksrVfvSBwS6/CI41wc3hA/hWxGOAbT1Diy9/+PBrh2VJts0SzBXb80SqGgVFFPQ==} + peerDependencies: + eslint: '>6.6.0' + turbo: '>2.0.0' + + eslint-plugin-unicorn@62.0.0: + resolution: {integrity: sha512-HIlIkGLkvf29YEiS/ImuDZQbP12gWyx5i3C6XrRxMvVdqMroCI9qoVYCoIl17ChN+U89pn9sVwLxhIWj5nEc7g==} + engines: {node: ^20.10.0 || >=21.0.0} + peerDependencies: + eslint: '>=9.38.0' + + eslint-plugin-unused-imports@4.3.0: + resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 + eslint: ^9.0.0 || ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + + eslint-plugin-vitest@0.5.4: + resolution: {integrity: sha512-um+odCkccAHU53WdKAw39MY61+1x990uXjSPguUCq3VcEHdqJrOb8OTMrbYlY6f9jAKx7x98kLVlIe3RJeJqoQ==} + engines: {node: ^18.0.0 || >= 20.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': '*' + eslint: ^8.57.0 || ^9.0.0 + vitest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + vitest: + optional: true + + eslint-plugin-vue@10.6.2: + resolution: {integrity: sha512-nA5yUs/B1KmKzvC42fyD0+l9Yd+LtEpVhWRbXuDj0e+ZURcTtyRbMDWUeJmTAh2wC6jC83raS63anNM2YT3NPw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + '@typescript-eslint/parser': ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + vue-eslint-parser: ^10.0.0 + peerDependenciesMeta: + '@stylistic/eslint-plugin': + optional: true + '@typescript-eslint/parser': + optional: true + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: ^2.6.1 + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + + expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-equals@5.4.0: + resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} + engines: {node: '>=6.0.0'} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-string-compare@3.0.0: + resolution: {integrity: sha512-PY66/8HelapGo5nqMN17ZTKqJj1nppuS1OoC9Y0aI2jsUDlZDEYhMODTpb68wVCq+xMbaEbPGXRd7qutHzkRXA==} + engines: {node: ^14.13.1 || >=16.0.0} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + + file-entry-cache@11.1.1: + resolution: {integrity: sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-entry-cache@9.1.0: + resolution: {integrity: sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==} + engines: {node: '>=18'} + + file-type@19.6.0: + resolution: {integrity: sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==} + engines: {node: '>=18'} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up-simple@1.0.1: + resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} + engines: {node: '>=18'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + + findup-sync@5.0.0: + resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} + engines: {node: '>= 10.13.0'} + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flat-cache@5.0.0: + resolution: {integrity: sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==} + engines: {node: '>=18'} + + flat-cache@6.1.19: + resolution: {integrity: sha512-l/K33newPTZMTGAnnzaiqSl6NnH7Namh8jBNjrgjprWxGmZUuxx/sJNIRaijOh3n7q7ESbhNZC+pvVZMFdeU4A==} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + focus-trap@7.7.0: + resolution: {integrity: sha512-DJJDHpEgoSbP8ZE1MNeU2IzCpfFyFdNZZRilqmfH2XiQsPK6PtD8AfJqWzEBudUQB2yHwZc5iq54rjTaGQ+ljw==} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formdata-node@6.0.3: + resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==} + engines: {node: '>= 18'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + framesync@6.1.2: + resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensequence@7.0.0: + resolution: {integrity: sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==} + engines: {node: '>=18'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.4.0: + resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-own-enumerable-property-symbols@3.0.2: + resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} + + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + + get-port@7.1.0: + resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==} + engines: {node: '>=16'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + + git-raw-commits@4.0.0: + resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} + engines: {node: '>=16'} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + hasBin: true + + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} + hasBin: true + + glob@13.0.0: + resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} + engines: {node: 20 || >=22} + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + + global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@15.0.0: + resolution: {integrity: sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==} + engines: {node: '>=20'} + + globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + good-listener@1.2.2: + resolution: {integrity: sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graph-cycles@3.0.0: + resolution: {integrity: sha512-9qxd8BQK0tZJ3cRUW0Yn2q6P/9h+bgz/4UYuscpdxPz6851NNBA1IwoYDRHDpKzCqmr1UHlGHcp5+0WzpY9F7A==} + engines: {node: ^14.13.1 || >=16.0.0} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + gzip-size@7.0.0: + resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + h3@1.15.4: + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + + happy-dom@17.6.3: + resolution: {integrity: sha512-UVIHeVhxmxedbWPCfgS55Jg2rDfwf2BCKeylcPSqazLz5w3Kri7Q4xdBJubsr/+VUzFLh0VjIvh13RaDA2/Xug==} + engines: {node: '>=20.0.0'} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hashery@1.3.0: + resolution: {integrity: sha512-fWltioiy5zsSAs9ouEnvhsVJeAXRybGCNNv0lvzpzNOSDbULXRy7ivFWwCCv4I5Am6kSo75hmbsCduOoc2/K4w==} + engines: {node: '>=20'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hey-listen@1.0.8: + resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} + + highlight.js@11.11.1: + resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} + engines: {node: '>=12.0.0'} + + homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hookified@1.14.0: + resolution: {integrity: sha512-pi1ynXIMFx/uIIwpWJ/5CEtOHLGtnUB0WhGeeYT+fKcQ+WCQbm3/rrkAXnpfph++PgepNqPdTC2WTj8A6k6zoQ==} + + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + + html-minifier-terser@6.1.0: + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} + engines: {node: '>=12'} + hasBin: true + + html-minifier-terser@7.2.0: + resolution: {integrity: sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==} + engines: {node: ^14.13.1 || >=16.0.0} + hasBin: true + + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-shutdown@1.2.2: + resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + httpxy@0.1.7: + resolution: {integrity: sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==} + + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.1: + resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==} + engines: {node: '>=0.10.0'} + + idb@7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + immutable@5.1.4: + resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + ioredis@5.8.2: + resolution: {integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==} + engines: {node: '>=12.22.0'} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + + is-builtin-module@5.0.0: + resolution: {integrity: sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==} + engines: {node: '>=18.20'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-ci@4.1.0: + resolution: {integrity: sha512-Ab9bQDQ11lWootZUI5qxgN2ZXwxNI5hTwnsvOc1wyxQ7zQ8OkEDw79mI0+9jI3x432NfwbVRru+3noJfXF6lSQ==} + hasBin: true + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-in-ci@1.0.0: + resolution: {integrity: sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==} + engines: {node: '>=18'} + hasBin: true + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-installed-globally@1.0.0: + resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} + engines: {node: '>=18'} + + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-npm@6.1.0: + resolution: {integrity: sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@1.0.1: + resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} + engines: {node: '>=0.10.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-plain-object@3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-regexp@1.0.0: + resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} + engines: {node: '>=0.10.0'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-text-path@2.0.0: + resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} + engines: {node: '>=8'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + + is64bit@2.0.0: + resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} + engines: {node: '>=18'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} + hasBin: true + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + js-beautify@1.15.4: + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} + hasBin: true + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + + js-md5@0.8.3: + resolution: {integrity: sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsdoc-type-pratt-parser@4.8.0: + resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} + engines: {node: '>=12.0.0'} + + jsdoc-type-pratt-parser@6.10.0: + resolution: {integrity: sha512-+LexoTRyYui5iOhJGn13N9ZazL23nAHGkXsa1p/C8yeq79WRfLBag6ZZ0FQG2aRoc9yfo59JT9EYCQonOkHKkQ==} + engines: {node: '>=20.0.0'} + + jsdoc-type-pratt-parser@7.0.0: + resolution: {integrity: sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA==} + engines: {node: '>=20.0.0'} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-eslint-parser@2.4.2: + resolution: {integrity: sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + keyv@5.5.5: + resolution: {integrity: sha512-FA5LmZVF1VziNc0bIdCSA1IoSVnDCqE8HJIZZv2/W8YmoAM50+tnUgJR/gQZwEeIMleuIOnRnHA/UaZRNeV4iQ==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + knitwork@1.3.0: + resolution: {integrity: sha512-4LqMNoONzR43B1W0ek0fhXMsDNW/zxa1NdFAVMY+k28pgZLovR4G3PB5MrpTxCy1QaZCqNoiaKPr5w5qZHfSNw==} + + known-css-properties@0.37.0: + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + ky@1.14.1: + resolution: {integrity: sha512-hYje4L9JCmpEQBtudo+v52X5X8tgWXUYyPcxKSuxQNboqufecl9VMWjGiucAFH060AwPXHZuH+WB2rrqfkmafw==} + engines: {node: '>=18'} + + latest-version@9.0.0: + resolution: {integrity: sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==} + engines: {node: '>=18'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + lefthook-darwin-arm64@1.13.6: + resolution: {integrity: sha512-m6Lb77VGc84/Qo21Lhq576pEvcgFCnvloEiP02HbAHcIXD0RTLy9u2yAInrixqZeaz13HYtdDaI7OBYAAdVt8A==} + cpu: [arm64] + os: [darwin] + + lefthook-darwin-x64@1.13.6: + resolution: {integrity: sha512-CoRpdzanu9RK3oXR1vbEJA5LN7iB+c7hP+sONeQJzoOXuq4PNKVtEaN84Gl1BrVtCNLHWFAvCQaZPPiiXSy8qg==} + cpu: [x64] + os: [darwin] + + lefthook-freebsd-arm64@1.13.6: + resolution: {integrity: sha512-X4A7yfvAJ68CoHTqP+XvQzdKbyd935sYy0bQT6Ajz7FL1g7hFiro8dqHSdPdkwei9hs8hXeV7feyTXbYmfjKQQ==} + cpu: [arm64] + os: [freebsd] + + lefthook-freebsd-x64@1.13.6: + resolution: {integrity: sha512-ai2m+Sj2kGdY46USfBrCqLKe9GYhzeq01nuyDYCrdGISePeZ6udOlD1k3lQKJGQCHb0bRz4St0r5nKDSh1x/2A==} + cpu: [x64] + os: [freebsd] + + lefthook-linux-arm64@1.13.6: + resolution: {integrity: sha512-cbo4Wtdq81GTABvikLORJsAWPKAJXE8Q5RXsICFUVznh5PHigS9dFW/4NXywo0+jfFPCT6SYds2zz4tCx6DA0Q==} + cpu: [arm64] + os: [linux] + + lefthook-linux-x64@1.13.6: + resolution: {integrity: sha512-uJl9vjCIIBTBvMZkemxCE+3zrZHlRO7Oc+nZJ+o9Oea3fu+W82jwX7a7clw8jqNfaeBS+8+ZEQgiMHWCloTsGw==} + cpu: [x64] + os: [linux] + + lefthook-openbsd-arm64@1.13.6: + resolution: {integrity: sha512-7r153dxrNRQ9ytRs2PmGKKkYdvZYFPre7My7XToSTiRu5jNCq++++eAKVkoyWPduk97dGIA+YWiEr5Noe0TK2A==} + cpu: [arm64] + os: [openbsd] + + lefthook-openbsd-x64@1.13.6: + resolution: {integrity: sha512-Z+UhLlcg1xrXOidK3aLLpgH7KrwNyWYE3yb7ITYnzJSEV8qXnePtVu8lvMBHs/myzemjBzeIr/U/+ipjclR06g==} + cpu: [x64] + os: [openbsd] + + lefthook-windows-arm64@1.13.6: + resolution: {integrity: sha512-Uxef6qoDxCmUNQwk8eBvddYJKSBFglfwAY9Y9+NnnmiHpWTjjYiObE9gT2mvGVpEgZRJVAatBXc+Ha5oDD/OgQ==} + cpu: [arm64] + os: [win32] + + lefthook-windows-x64@1.13.6: + resolution: {integrity: sha512-mOZoM3FQh3o08M8PQ/b3IYuL5oo36D9ehczIw1dAgp1Ly+Tr4fJ96A+4SEJrQuYeRD4mex9bR7Ps56I73sBSZA==} + cpu: [x64] + os: [win32] + + lefthook@1.13.6: + resolution: {integrity: sha512-ojj4/4IJ29Xn4drd5emqVgilegAPN3Kf0FQM2p/9+lwSTpU+SZ1v4Ig++NF+9MOa99UKY8bElmVrLhnUUNFh5g==} + hasBin: true + + less@4.5.1: + resolution: {integrity: sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==} + engines: {node: '>=14'} + hasBin: true + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + listhen@1.9.0: + resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==} + hasBin: true + + listr2@8.3.3: + resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} + engines: {node: '>=18.0.0'} + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locko@1.1.0: + resolution: {integrity: sha512-pYB2dzRY93fJkg2RIl41AMNgTQftEjyTK9vlPrGOJvuGQsOjb267VJBw15BjiN3RBd1oBoKkOu9E2dRdFKIfAA==} + + lodash-es@4.17.22: + resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lucide-vue-next@0.553.0: + resolution: {integrity: sha512-0tg9XT+VCElTT+7EXXbBRhWe1nU7Doa32Xv/dHP5/LCleFVgV6cAqziM3C7AetqmsYIsfAtNwRYdtvs4Ds7aUg==} + peerDependencies: + vue: ^3.5.24 + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.1: + resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + + mdn-data@2.25.0: + resolution: {integrity: sha512-T2LPsjgUE/tgMmRXREVmwsux89DwWfNjiynOeXuLd2mX6jphGQ2YE3Ukz7LQ2VOFKiVZU/Ee1GqzHiipZCjymw==} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + + mime@4.1.0: + resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} + engines: {node: '>=16'} + hasBin: true + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + + minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass-collect@2.0.1: + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mkdist@2.4.1: + resolution: {integrity: sha512-Ezk0gi04GJBkqMfsksICU5Rjoemc4biIekwgrONWVPor2EO/N9nBgN6MZXAf7Yw4mDDhrNyKbdETaHNevfumKg==} + hasBin: true + peerDependencies: + sass: ^1.92.1 + typescript: '>=5.9.2' + vue: ^3.5.24 + vue-sfc-transformer: ^0.1.1 + vue-tsc: ^1.8.27 || ^2.0.21 || ^3.0.0 + peerDependenciesMeta: + sass: + optional: true + typescript: + optional: true + vue: + optional: true + vue-sfc-transformer: + optional: true + vue-tsc: + optional: true + + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + multimatch@5.0.0: + resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} + engines: {node: '>=10'} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanoid@5.1.6: + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + engines: {node: ^18 || >=20} + hasBin: true + + nanopop@2.4.2: + resolution: {integrity: sha512-NzOgmMQ+elxxHeIha+OG/Pv3Oc3p4RU2aBhwWwAqDpXrdTbtRylbRLQztLy8dMMwfl6pclznBdfUhccEn9ZIzw==} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + natural-orderby@5.0.0: + resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} + engines: {node: '>=18'} + + needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + + nitropack@2.12.9: + resolution: {integrity: sha512-t6qqNBn2UDGMWogQuORjbL2UPevB8PvIPsPHmqvWpeGOlPr4P8Oc5oA8t3wFwGmaolM2M/s2SwT23nx9yARmOg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + xml2js: ^0.6.2 + peerDependenciesMeta: + xml2js: + optional: true + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-cleanup@2.1.2: + resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch-cache@5.1.0: + resolution: {integrity: sha512-4j3rRHNGIKGX7VzXSrBT0bh7+wFuyJv1DxCfCLDHsnDahJWoD9lXe3BzL3BJg/GEIJiM7KIvqVs3byW1GFtRsQ==} + engines: {node: '>=18.19.0'} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + node-forge@1.3.3: + resolution: {integrity: sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==} + engines: {node: '>= 6.13.0'} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-html-parser@5.4.2: + resolution: {integrity: sha512-RaBPP3+51hPne/OolXxcz89iYvQvKOydaqoePpOgXcrOKZhjVIzmpKZz+Hd/RBO2/zN2q6CNJhQzucVz+u3Jyw==} + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + + nprogress@0.2.0: + resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nypm@0.6.2: + resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-deep-merge@2.0.0: + resolution: {integrity: sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-json@10.0.1: + resolution: {integrity: sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==} + engines: {node: '>=18'} + + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + + param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parent-module@2.0.0: + resolution: {integrity: sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==} + engines: {node: '>=8'} + + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.1: + resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} + engines: {node: 20 || >=22} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + + pathe@0.2.0: + resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + perfect-debounce@2.0.0: + resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pinia-plugin-persistedstate@4.7.1: + resolution: {integrity: sha512-WHOqh2esDlR3eAaknPbqXrkkj0D24h8shrDPqysgCFR6ghqP/fpFfJmMPJp0gETHsvrh9YNNg6dQfo2OEtDnIQ==} + peerDependencies: + '@nuxt/kit': '>=3.0.0' + '@pinia/nuxt': '>=0.10.0' + pinia: ^3.0.3 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + '@pinia/nuxt': + optional: true + pinia: + optional: true + + pinia@3.0.4: + resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==} + peerDependencies: + typescript: '>=4.5.0' + vue: ^3.5.24 + peerDependenciesMeta: + typescript: + optional: true + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + + playwright-core@1.57.0: + resolution: {integrity: sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.57.0: + resolution: {integrity: sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==} + engines: {node: '>=18'} + hasBin: true + + please-upgrade-node@3.2.0: + resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + + popmotion@11.0.5: + resolution: {integrity: sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-antd-fixes@0.2.0: + resolution: {integrity: sha512-WuV4Ip5DnLg8q+wmNXUq13wZZcA5Lrj+em3Jznl4cxItZDgFp4wEh+5ba59TvFeHfwNuTEZ6YNDsYP9DG6NurQ==} + peerDependencies: + postcss: ^8.0.0 + + postcss-attribute-case-insensitive@7.0.1: + resolution: {integrity: sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-calc@10.1.1: + resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} + engines: {node: ^18.12 || ^20.9 || >=22.0} + peerDependencies: + postcss: ^8.4.38 + + postcss-clamp@4.1.0: + resolution: {integrity: sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==} + engines: {node: '>=7.6.0'} + peerDependencies: + postcss: ^8.4.6 + + postcss-color-functional-notation@7.0.12: + resolution: {integrity: sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-color-hex-alpha@10.0.0: + resolution: {integrity: sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-color-rebeccapurple@10.0.0: + resolution: {integrity: sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-colormin@7.0.5: + resolution: {integrity: sha512-ekIBP/nwzRWhEMmIxHHbXHcMdzd1HIUzBECaj5KEdLz9DVP2HzT065sEhvOx1dkLjYW7jyD0CngThx6bpFi2fA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-convert-values@7.0.8: + resolution: {integrity: sha512-+XNKuPfkHTCEo499VzLMYn94TiL3r9YqRE3Ty+jP7UX4qjewUONey1t7CG21lrlTLN07GtGM8MqFVp86D4uKJg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-custom-media@11.0.6: + resolution: {integrity: sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-custom-properties@14.0.6: + resolution: {integrity: sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-custom-selectors@8.0.5: + resolution: {integrity: sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-dir-pseudo-class@9.0.1: + resolution: {integrity: sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-discard-comments@7.0.5: + resolution: {integrity: sha512-IR2Eja8WfYgN5n32vEGSctVQ1+JARfu4UH8M7bgGh1bC+xI/obsPJXaBpQF7MAByvgwZinhpHpdrmXtvVVlKcQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-duplicates@7.0.2: + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-empty@7.0.1: + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-overridden@7.0.1: + resolution: {integrity: sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-double-position-gradients@6.0.4: + resolution: {integrity: sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-focus-visible@10.0.1: + resolution: {integrity: sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-focus-within@9.0.1: + resolution: {integrity: sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-font-variant@5.0.0: + resolution: {integrity: sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==} + peerDependencies: + postcss: ^8.1.0 + + postcss-gap-properties@6.0.0: + resolution: {integrity: sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-html@1.8.0: + resolution: {integrity: sha512-5mMeb1TgLWoRKxZ0Xh9RZDfwUUIqRrcxO2uXO+Ezl1N5lqpCiSU5Gk6+1kZediBfBHFtPCdopr2UZ2SgUsKcgQ==} + engines: {node: ^12 || >=14} + + postcss-image-set-function@7.0.0: + resolution: {integrity: sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-import@16.1.1: + resolution: {integrity: sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-lab-function@7.0.12: + resolution: {integrity: sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: ^2.6.1 + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-logical@8.1.0: + resolution: {integrity: sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-media-query-parser@0.2.3: + resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} + + postcss-merge-longhand@7.0.5: + resolution: {integrity: sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-merge-rules@7.0.7: + resolution: {integrity: sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-font-values@7.0.1: + resolution: {integrity: sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-gradients@7.0.1: + resolution: {integrity: sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-params@7.0.5: + resolution: {integrity: sha512-FGK9ky02h6Ighn3UihsyeAH5XmLEE2MSGH5Tc4tXMFtEDx7B+zTG6hD/+/cT+fbF7PbYojsmmWjyTwFwW1JKQQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-selectors@7.0.5: + resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-nested@5.0.6: + resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-nested@7.0.2: + resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-nesting@13.0.2: + resolution: {integrity: sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-normalize-charset@7.0.1: + resolution: {integrity: sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-display-values@7.0.1: + resolution: {integrity: sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-positions@7.0.1: + resolution: {integrity: sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-repeat-style@7.0.1: + resolution: {integrity: sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-string@7.0.1: + resolution: {integrity: sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-timing-functions@7.0.1: + resolution: {integrity: sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-unicode@7.0.5: + resolution: {integrity: sha512-X6BBwiRxVaFHrb2WyBMddIeB5HBjJcAaUHyhLrM2FsxSq5TFqcHSsK7Zu1otag+o0ZphQGJewGH1tAyrD0zX1Q==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-url@7.0.1: + resolution: {integrity: sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-normalize-whitespace@7.0.1: + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-opacity-percentage@3.0.0: + resolution: {integrity: sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-ordered-values@7.0.2: + resolution: {integrity: sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-overflow-shorthand@6.0.0: + resolution: {integrity: sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-page-break@3.0.4: + resolution: {integrity: sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==} + peerDependencies: + postcss: ^8 + + postcss-place@10.0.0: + resolution: {integrity: sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-preset-env@10.5.0: + resolution: {integrity: sha512-xgxFQPAPxeWmsgy8cR7GM1PGAL/smA5E9qU7K//D4vucS01es3M0fDujhDJn3kY8Ip7/vVYcecbe1yY+vBo3qQ==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-pseudo-class-any-link@10.0.1: + resolution: {integrity: sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-reduce-initial@7.0.5: + resolution: {integrity: sha512-RHagHLidG8hTZcnr4FpyMB2jtgd/OcyAazjMhoy5qmWJOx1uxKh4ntk0Pb46ajKM0rkf32lRH4C8c9qQiPR6IA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-reduce-transforms@7.0.1: + resolution: {integrity: sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-replace-overflow-wrap@4.0.0: + resolution: {integrity: sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==} + peerDependencies: + postcss: ^8.0.3 + + postcss-resolve-nested-selector@0.1.6: + resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} + + postcss-safe-parser@6.0.0: + resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.3.3 + + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + + postcss-selector-not@8.0.1: + resolution: {integrity: sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-sorting@8.0.2: + resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==} + peerDependencies: + postcss: ^8.4.20 + + postcss-sorting@9.1.0: + resolution: {integrity: sha512-Mn8KJ45HNNG6JBpBizXcyf6LqY/qyqetGcou/nprDnFwBFBLGj0j/sNKV2lj2KMOVOwdXu14aEzqJv8CIV6e8g==} + peerDependencies: + postcss: ^8.4.20 + + postcss-svgo@7.1.0: + resolution: {integrity: sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==} + engines: {node: ^18.12.0 || ^20.9.0 || >= 18} + peerDependencies: + postcss: ^8.4.32 + + postcss-unique-selectors@7.0.4: + resolution: {integrity: sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier-plugin-tailwindcss@0.7.2: + resolution: {integrity: sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==} + engines: {node: '>=20.19'} + peerDependencies: + '@ianvs/prettier-plugin-sort-imports': '*' + '@prettier/plugin-hermes': '*' + '@prettier/plugin-oxc': '*' + '@prettier/plugin-pug': '*' + '@shopify/prettier-plugin-liquid': '*' + '@trivago/prettier-plugin-sort-imports': '*' + '@zackad/prettier-plugin-twig': '*' + prettier: ^3.0 + prettier-plugin-astro: '*' + prettier-plugin-css-order: '*' + prettier-plugin-jsdoc: '*' + prettier-plugin-marko: '*' + prettier-plugin-multiline-arrays: '*' + prettier-plugin-organize-attributes: '*' + prettier-plugin-organize-imports: '*' + prettier-plugin-sort-imports: '*' + prettier-plugin-svelte: '*' + peerDependenciesMeta: + '@ianvs/prettier-plugin-sort-imports': + optional: true + '@prettier/plugin-hermes': + optional: true + '@prettier/plugin-oxc': + optional: true + '@prettier/plugin-pug': + optional: true + '@shopify/prettier-plugin-liquid': + optional: true + '@trivago/prettier-plugin-sort-imports': + optional: true + '@zackad/prettier-plugin-twig': + optional: true + prettier-plugin-astro: + optional: true + prettier-plugin-css-order: + optional: true + prettier-plugin-jsdoc: + optional: true + prettier-plugin-marko: + optional: true + prettier-plugin-multiline-arrays: + optional: true + prettier-plugin-organize-attributes: + optional: true + prettier-plugin-organize-imports: + optional: true + prettier-plugin-sort-imports: + optional: true + prettier-plugin-svelte: + optional: true + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + engines: {node: '>=14'} + hasBin: true + + pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + + pretty-bytes@6.1.1: + resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} + engines: {node: ^14.13.1 || >=16.0.0} + + pretty-bytes@7.1.0: + resolution: {integrity: sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==} + engines: {node: '>=20'} + + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + publint@0.3.16: + resolution: {integrity: sha512-MFqyfRLAExPVZdTQFwkAQELzA8idyXzROVOytg6nEJ/GEypXBUmMGrVaID8cTuzRS1U5L8yTOdOJtMXgFUJAeA==} + engines: {node: '>=18'} + hasBin: true + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pupa@3.3.0: + resolution: {integrity: sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==} + engines: {node: '>=12.20'} + + qified@0.5.3: + resolution: {integrity: sha512-kXuQdQTB6oN3KhI6V4acnBSZx8D2I4xzZvn9+wFLLFCoBNQY/sFnCW6c43OL7pOQ2HvGV4lnWIXNmgfp7cTWhQ==} + engines: {node: '>=20'} + + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + + read-yaml-file@2.1.0: + resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} + engines: {node: '>=10.13'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + redis-errors@1.2.0: + resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} + engines: {node: '>=4'} + + redis-parser@3.0.0: + resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} + engines: {node: '>=4'} + + refa@0.12.1: + resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regexp-ast-analysis@0.7.1: + resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + regexp-tree@0.1.27: + resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} + hasBin: true + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + registry-auth-token@5.1.0: + resolution: {integrity: sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==} + engines: {node: '>=14'} + + registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + + reka-ui@2.7.0: + resolution: {integrity: sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==} + peerDependencies: + vue: ^3.5.24 + + relateurl@0.2.7: + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} + engines: {node: '>= 0.10'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + require-package-name@2.0.1: + resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} + + reserved-identifiers@1.2.0: + resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} + engines: {node: '>=18'} + + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + + resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rimraf@6.1.2: + resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} + engines: {node: 20 || >=22} + hasBin: true + + rollup-plugin-dts@6.3.0: + resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==} + engines: {node: '>=16'} + peerDependencies: + rollup: ^3.29.4 || ^4 + typescript: ^4.5 || ^5.0 + + rollup-plugin-visualizer@5.14.0: + resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup-plugin-visualizer@6.0.5: + resolution: {integrity: sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x || ^1.0.0-beta + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup@2.79.2: + resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} + engines: {node: '>=10.0.0'} + hasBin: true + + rollup@4.54.0: + resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rotated-array-set@3.0.0: + resolution: {integrity: sha512-G7689wvCM0szMFXUAhi3GfNGcSPlndg077cdRWoq7UegOAwfU2MJ0jD7s7jB+2ppKA75Kr/O0HwAP9+rRdBctg==} + engines: {node: ^14.13.1 || >=16.0.0} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sass@1.97.1: + resolution: {integrity: sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==} + engines: {node: '>=14.0.0'} + hasBin: true + + sax@1.4.3: + resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==} + + scroll-into-view-if-needed@2.2.31: + resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==} + + scslre@0.3.0: + resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} + engines: {node: ^14.0.0 || >=16.0.0} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + secure-ls@2.0.0: + resolution: {integrity: sha512-Wgtnw0QSm0v7gVKv11nOoeyGS65EThGXnBB7jfd4IhZd2eq3B4AMPcXAL5qJ1h55+Qolun7TONTwX7H5m6e2pQ==} + engines: {node: '>=8.0'} + + select@1.1.2: + resolution: {integrity: sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==} + + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + serve-placeholder@2.0.2: + resolution: {integrity: sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shallow-equal@1.2.1: + resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + short-tree@3.0.0: + resolution: {integrity: sha512-Yd9NFs/o9QSoH4/wTjxk4Xe0+CIzitDRN1Qg7iBeTSejKjlCg/3PbgiRwDUVuaIxD0RRdv7Iz9jKr7e0HljtUg==} + engines: {node: ^14.13.1 || >=16.0.0} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + + smob@1.5.0: + resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + + sortablejs@1.15.6: + resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions + + sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.22: + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssri@13.0.0: + resolution: {integrity: sha512-yizwGBpbCn4YomB2lzhZqrHLJoqFGXihNbib3ozhqF/cIp5ue+xSmOQrjNasEE62hFxsCcg/V/z23t4n8jMEng==} + engines: {node: ^20.17.0 || >=22.9.0} + + stable-hash-x@0.2.0: + resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} + engines: {node: '>=12.0.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + standard-as-callback@2.1.0: + resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-object@3.3.0: + resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} + engines: {node: '>=4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-comments@2.0.1: + resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} + engines: {node: '>=10'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + + strip-indent@4.1.1: + resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} + engines: {node: '>=12'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + strtok3@9.1.1: + resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==} + engines: {node: '>=16'} + + stubborn-fs@2.0.0: + resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} + + stubborn-utils@1.0.2: + resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} + + style-search@0.1.0: + resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} + + style-value-types@5.1.2: + resolution: {integrity: sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==} + + stylehacks@7.0.7: + resolution: {integrity: sha512-bJkD0JkEtbRrMFtwgpJyBbFIwfDDONQ1Ov3sDLZQP8HuJ73kBOyx66H4bOcAbVWmnfLdvQ0AJwXxOMkpujcO6g==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + stylelint-config-html@1.1.0: + resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==} + engines: {node: ^12 || >=14} + peerDependencies: + postcss-html: ^1.0.0 + stylelint: '>=14.0.0' + + stylelint-config-recess-order@6.1.0: + resolution: {integrity: sha512-0rGZgJQjUKqv1PXZnRJxr13f3hb3i2snx2nIL6luDWUf4nD3BAweB8noS7jdfBQ56HQG3RKSF0a+MAHfBGFxgw==} + peerDependencies: + stylelint: '>=16' + + stylelint-config-recommended-scss@14.1.0: + resolution: {integrity: sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==} + engines: {node: '>=18.12.0'} + peerDependencies: + postcss: ^8.3.3 + stylelint: ^16.6.1 + peerDependenciesMeta: + postcss: + optional: true + + stylelint-config-recommended-vue@1.6.1: + resolution: {integrity: sha512-lLW7hTIMBiTfjenGuDq2kyHA6fBWd/+Df7MO4/AWOxiFeXP9clbpKgg27kHfwA3H7UNMGC7aeP3mNlZB5LMmEQ==} + engines: {node: ^12 || >=14} + peerDependencies: + postcss-html: ^1.0.0 + stylelint: '>=14.0.0' + + stylelint-config-recommended@14.0.1: + resolution: {integrity: sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.1.0 + + stylelint-config-recommended@16.0.0: + resolution: {integrity: sha512-4RSmPjQegF34wNcK1e1O3Uz91HN8P1aFdFzio90wNK9mjgAI19u5vsU868cVZboKzCaa5XbpvtTzAAGQAxpcXA==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.16.0 + + stylelint-config-recommended@17.0.0: + resolution: {integrity: sha512-WaMSdEiPfZTSFVoYmJbxorJfA610O0tlYuU2aEwY33UQhSPgFbClrVJYWvy3jGJx+XW37O+LyNLiZOEXhKhJmA==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.23.0 + + stylelint-config-standard@38.0.0: + resolution: {integrity: sha512-uj3JIX+dpFseqd/DJx8Gy3PcRAJhlEZ2IrlFOc4LUxBX/PNMEQ198x7LCOE2Q5oT9Vw8nyc4CIL78xSqPr6iag==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.18.0 + + stylelint-order@6.0.4: + resolution: {integrity: sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==} + peerDependencies: + stylelint: ^14.0.0 || ^15.0.0 || ^16.0.1 + + stylelint-order@7.0.0: + resolution: {integrity: sha512-rSWxx0KscYfxU02wEskKXES9lkRzuuONMMNkZ7SUc6uiF3tDKm7e+sE0Ax/SBlG4TUf1sp1R6f3/SlsPGmzthg==} + engines: {node: '>=20.19.0'} + peerDependencies: + stylelint: ^16.18.0 + + stylelint-prettier@5.0.3: + resolution: {integrity: sha512-B6V0oa35ekRrKZlf+6+jA+i50C4GXJ7X1PPmoCqSUoXN6BrNF6NhqqhanvkLjqw2qgvrS0wjdpeC+Tn06KN3jw==} + engines: {node: '>=18.12.0'} + peerDependencies: + prettier: '>=3.0.0' + stylelint: '>=16.0.0' + + stylelint-scss@6.13.0: + resolution: {integrity: sha512-kZPwFUJkfup2gP1enlrS2h9U5+T5wFoqzJ1n/56AlpwSj28kmFe7ww/QFydvPsg5gLjWchAwWWBLtterynZrOw==} + engines: {node: '>=18.12.0'} + peerDependencies: + stylelint: ^16.8.2 + + stylelint@16.26.1: + resolution: {integrity: sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==} + engines: {node: '>=18.12.0'} + hasBin: true + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + sver@1.8.4: + resolution: {integrity: sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==} + + svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + + svgo@4.0.0: + resolution: {integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==} + engines: {node: '>=16'} + hasBin: true + + synckit@0.11.11: + resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + engines: {node: ^14.18.0 || >=16.0.0} + + system-architecture@0.1.0: + resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} + engines: {node: '>=18'} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tailwind-merge@2.6.0: + resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + tar@7.5.2: + resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} + engines: {node: '>=18'} + + temp-dir@2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + + tempy@0.6.0: + resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} + engines: {node: '>=10'} + + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + + terser@5.44.1: + resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + engines: {node: '>=10'} + hasBin: true + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + + text-extensions@2.4.0: + resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} + engines: {node: '>=8'} + + theme-colors@0.1.0: + resolution: {integrity: sha512-6gTEHQqWlQNiOEGHCSSQmU//E5SnXHJ4H7oHQOD8x77CvNYNQAmt73dqR71mzw5ULV87zaHLxK5pIBnsToFuZw==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tiny-emitter@2.1.0: + resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinymce@7.9.1: + resolution: {integrity: sha512-zaOHwmiP1EqTeLRXAvVriDb00JYnfEjWGPdKEuac7MiZJ5aiDMZ4Unc98Gmajn+PBljOmO1GKV6G0KwWn3+k8A==} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-valid-identifier@1.0.0: + resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} + engines: {node: '>=20'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + turbo-darwin-64@2.7.2: + resolution: {integrity: sha512-dxY3X6ezcT5vm3coK6VGixbrhplbQMwgNsCsvZamS/+/6JiebqW9DKt4NwpgYXhDY2HdH00I7FWs3wkVuan4rA==} + cpu: [x64] + os: [darwin] + + turbo-darwin-arm64@2.7.2: + resolution: {integrity: sha512-1bXmuwPLqNFt3mzrtYcVx1sdJ8UYb124Bf48nIgcpMCGZy3kDhgxNv1503kmuK/37OGOZbsWSQFU4I08feIuSg==} + cpu: [arm64] + os: [darwin] + + turbo-linux-64@2.7.2: + resolution: {integrity: sha512-kP+TiiMaiPugbRlv57VGLfcjFNsFbo8H64wMBCPV2270Or2TpDCBULMzZrvEsvWFjT3pBFvToYbdp8/Kw0jAQg==} + cpu: [x64] + os: [linux] + + turbo-linux-arm64@2.7.2: + resolution: {integrity: sha512-VDJwQ0+8zjAfbyY6boNaWfP6RIez4ypKHxwkuB6SrWbOSk+vxTyW5/hEjytTwK8w/TsbKVcMDyvpora8tEsRFw==} + cpu: [arm64] + os: [linux] + + turbo-windows-64@2.7.2: + resolution: {integrity: sha512-rPjqQXVnI6A6oxgzNEE8DNb6Vdj2Wwyhfv3oDc+YM3U9P7CAcBIlKv/868mKl4vsBtz4ouWpTQNXG8vljgJO+w==} + cpu: [x64] + os: [win32] + + turbo-windows-arm64@2.7.2: + resolution: {integrity: sha512-tcnHvBhO515OheIFWdxA+qUvZzNqqcHbLVFc1+n+TJ1rrp8prYicQtbtmsiKgMvr/54jb9jOabU62URAobnB7g==} + cpu: [arm64] + os: [win32] + + turbo@2.7.2: + resolution: {integrity: sha512-5JIA5aYBAJSAhrhbyag1ZuMSgUZnHtI+Sq3H8D3an4fL8PeF+L1yYvbEJg47akP1PFfATMf5ehkqFnxfkmuwZQ==} + hasBin: true + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.16.0: + resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-fest@5.3.1: + resolution: {integrity: sha512-VCn+LMHbd4t6sF3wfU/+HKT63C9OoyrSIf4b+vtWHpt2U7/4InZG467YDNMFMR70DdHjAdpPWmw2lzRdg0Xqqg==} + engines: {node: '>=20'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + unbuild@3.6.1: + resolution: {integrity: sha512-+U5CdtrdjfWkZhuO4N9l5UhyiccoeMEXIc2Lbs30Haxb+tRwB3VwB8AoZRxlAzORXunenSo+j6lh45jx+xkKgg==} + hasBin: true + peerDependencies: + typescript: ^5.9.2 + peerDependenciesMeta: + typescript: + optional: true + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + unctx@2.5.0: + resolution: {integrity: sha512-p+Rz9x0R7X+CYDkT+Xg8/GhpcShTlU8n+cf9OtOEf7zEQsNcCZO1dPKNRDqvUTaq+P32PMMkxWHwfrxkqfqAYg==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + undici@7.16.0: + resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unimport@5.6.0: + resolution: {integrity: sha512-8rqAmtJV8o60x46kBAJKtHpJDJWkA2xcBqWKPI14MgUb05o1pnpnCnXSxedUXyeq7p8fR5g3pTo2BaswZ9lD9A==} + engines: {node: '>=18.12.0'} + + unique-filename@5.0.0: + resolution: {integrity: sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==} + engines: {node: ^20.17.0 || >=22.9.0} + + unique-slug@6.0.0: + resolution: {integrity: sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==} + engines: {node: ^20.17.0 || >=22.9.0} + + unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + + unplugin@1.16.1: + resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} + engines: {node: '>=14.0.0'} + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + unstorage@1.17.3: + resolution: {integrity: sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + untun@0.1.3: + resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} + hasBin: true + + untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} + hasBin: true + + unwasm@0.3.11: + resolution: {integrity: sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==} + + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + update-notifier@7.3.1: + resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} + engines: {node: '>=18'} + + uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vee-validate@4.15.1: + resolution: {integrity: sha512-DkFsiTwEKau8VIxyZBGdO6tOudD+QoUBPuHj3e6QFqmbfCRj1ArmYWue9lEp6jLSWBIw4XPlDLjFIZNLdRAMSg==} + peerDependencies: + vue: ^3.5.24 + + vite-dev-rpc@1.1.0: + resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} + peerDependencies: + vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 + + vite-hot-client@2.1.0: + resolution: {integrity: sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==} + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite-plugin-compression@0.5.1: + resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-dts@4.5.4: + resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite-plugin-html@3.2.2: + resolution: {integrity: sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q==} + peerDependencies: + vite: '>=2.0.0' + + vite-plugin-inspect@11.3.3: + resolution: {integrity: sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': '*' + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + + vite-plugin-lazy-import@1.0.7: + resolution: {integrity: sha512-mE6oAObOb4wqso4AoUGi9cLjdR+4vay1RCaKJvziBuFPlziZl7J0aw2hsqRTokLVRx3bli0a0VyjMOwsNDv58A==} + + vite-plugin-pwa@1.2.0: + resolution: {integrity: sha512-a2xld+SJshT9Lgcv8Ji4+srFJL4k/1bVbd1x06JIkvecpQkwkvCncD1+gSzcdm3s+owWLpMJerG3aN5jupJEVw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@vite-pwa/assets-generator': ^1.0.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + workbox-build: ^7.4.0 + workbox-window: ^7.4.0 + peerDependenciesMeta: + '@vite-pwa/assets-generator': + optional: true + + vite-plugin-vue-devtools@8.0.5: + resolution: {integrity: sha512-p619BlKFOqQXJ6uDWS1vUPQzuJOD6xJTfftj57JXBGoBD/yeQCowR7pnWcr/FEX4/HVkFbreI6w2uuGBmQOh6A==} + engines: {node: '>=v14.21.3'} + peerDependencies: + vite: ^6.0.0 || ^7.0.0-0 + + vite-plugin-vue-inspector@5.3.2: + resolution: {integrity: sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q==} + peerDependencies: + vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 + + vite@7.3.0: + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: ^2.6.1 + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + vue-component-type-helpers@2.2.12: + resolution: {integrity: sha512-YbGqHZ5/eW4SnkPNR44mKVc6ZKQoRs/Rux1sxC6rdwXb4qpbOSYfDr9DsTHolOTGmIKgM9j141mZbBeg05R1pw==} + + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.5.24 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-eslint-parser@10.2.0: + resolution: {integrity: sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + vue-i18n@11.2.7: + resolution: {integrity: sha512-LPv8bAY5OA0UvFEXl4vBQOBqJzRrlExy92tWgRuwW7tbykHf7CH71G2Y4TM2OwGcIS4+hyqKHS2EVBqaYwPY9Q==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.5.24 + + vue-json-viewer@3.0.4: + resolution: {integrity: sha512-pnC080rTub6YjccthVSNQod2z9Sl5IUUq46srXtn6rxwhW8QM4rlYn+CTSLFKXWfw+N3xv77Cioxw7B4XUKIbQ==} + peerDependencies: + vue: ^3.5.24 + + vue-router@4.6.4: + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.24 + + vue-tippy@6.7.1: + resolution: {integrity: sha512-gdHbBV5/Vc8gH87hQHLA7TN1K4BlLco3MAPrTb70ZYGXxx+55rAU4a4mt0fIoP+gB3etu1khUZ6c29Br1n0CiA==} + peerDependencies: + vue: ^3.5.24 + + vue-tsc@3.2.1: + resolution: {integrity: sha512-I23Rk8dkQfmcSbxDO0dmg9ioMLjKA1pjlU3Lz6Jfk2pMGu3Uryu9810XkcZH24IzPbhzPCnkKo2rEMRX0skSrw==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue-types@3.0.2: + resolution: {integrity: sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==} + engines: {node: '>=10.15.0'} + peerDependencies: + vue: ^3.5.24 + + vue@3.5.26: + resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + vxe-pc-ui@4.11.17: + resolution: {integrity: sha512-ZPU434l0/rf+KqIEMJcKpCGqFkIzKu2n1aFa479f4kx9VgKABlbZHGhIG/mCQindjiAvhpcMGQgFGP0zFWILmg==} + + vxe-table@4.17.33: + resolution: {integrity: sha512-xdDHhHv+Uk8f79NJGwvyJZAEO/FJnb+87NhpyYpcyNSlB7SIMmVDuCzT3g8ac+8KvsScbKRFjxYfbUdNQNL8ZQ==} + + warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + + watermark-js-plus@1.6.3: + resolution: {integrity: sha512-iCLOGf70KacIwjGF9MDViYxQcRiVwOH7l42qDHLeE2HeUsQD1EQuUC9cKRG/4SErTUmdqV3yf5WnKk2dRARHPQ==} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + + when-exit@2.1.5: + resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + widest-line@5.0.0: + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + workbox-background-sync@7.4.0: + resolution: {integrity: sha512-8CB9OxKAgKZKyNMwfGZ1XESx89GryWTfI+V5yEj8sHjFH8MFelUwYXEyldEK6M6oKMmn807GoJFUEA1sC4XS9w==} + + workbox-broadcast-update@7.4.0: + resolution: {integrity: sha512-+eZQwoktlvo62cI0b+QBr40v5XjighxPq3Fzo9AWMiAosmpG5gxRHgTbGGhaJv/q/MFVxwFNGh/UwHZ/8K88lA==} + + workbox-build@7.4.0: + resolution: {integrity: sha512-Ntk1pWb0caOFIvwz/hfgrov/OJ45wPEhI5PbTywQcYjyZiVhT3UrwwUPl6TRYbTm4moaFYithYnl1lvZ8UjxcA==} + engines: {node: '>=20.0.0'} + + workbox-cacheable-response@7.4.0: + resolution: {integrity: sha512-0Fb8795zg/x23ISFkAc7lbWes6vbw34DGFIMw31cwuHPgDEC/5EYm6m/ZkylLX0EnEbbOyOCLjKgFS/Z5g0HeQ==} + + workbox-core@7.4.0: + resolution: {integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==} + + workbox-expiration@7.4.0: + resolution: {integrity: sha512-V50p4BxYhtA80eOvulu8xVfPBgZbkxJ1Jr8UUn0rvqjGhLDqKNtfrDfjJKnLz2U8fO2xGQJTx/SKXNTzHOjnHw==} + + workbox-google-analytics@7.4.0: + resolution: {integrity: sha512-MVPXQslRF6YHkzGoFw1A4GIB8GrKym/A5+jYDUSL+AeJw4ytQGrozYdiZqUW1TPQHW8isBCBtyFJergUXyNoWQ==} + + workbox-navigation-preload@7.4.0: + resolution: {integrity: sha512-etzftSgdQfjMcfPgbfaZCfM2QuR1P+4o8uCA2s4rf3chtKTq/Om7g/qvEOcZkG6v7JZOSOxVYQiOu6PbAZgU6w==} + + workbox-precaching@7.4.0: + resolution: {integrity: sha512-VQs37T6jDqf1rTxUJZXRl3yjZMf5JX/vDPhmx2CPgDDKXATzEoqyRqhYnRoxl6Kr0rqaQlp32i9rtG5zTzIlNg==} + + workbox-range-requests@7.4.0: + resolution: {integrity: sha512-3Vq854ZNuP6Y0KZOQWLaLC9FfM7ZaE+iuQl4VhADXybwzr4z/sMmnLgTeUZLq5PaDlcJBxYXQ3U91V7dwAIfvw==} + + workbox-recipes@7.4.0: + resolution: {integrity: sha512-kOkWvsAn4H8GvAkwfJTbwINdv4voFoiE9hbezgB1sb/0NLyTG4rE7l6LvS8lLk5QIRIto+DjXLuAuG3Vmt3cxQ==} + + workbox-routing@7.4.0: + resolution: {integrity: sha512-C/ooj5uBWYAhAqwmU8HYQJdOjjDKBp9MzTQ+otpMmd+q0eF59K+NuXUek34wbL0RFrIXe/KKT+tUWcZcBqxbHQ==} + + workbox-strategies@7.4.0: + resolution: {integrity: sha512-T4hVqIi5A4mHi92+5EppMX3cLaVywDp8nsyUgJhOZxcfSV/eQofcOA6/EMo5rnTNmNTpw0rUgjAI6LaVullPpg==} + + workbox-streams@7.4.0: + resolution: {integrity: sha512-QHPBQrey7hQbnTs5GrEVoWz7RhHJXnPT+12qqWM378orDMo5VMJLCkCM1cnCk+8Eq92lccx/VgRZ7WAzZWbSLg==} + + workbox-sw@7.4.0: + resolution: {integrity: sha512-ltU+Kr3qWR6BtbdlMnCjobZKzeV1hN+S6UvDywBrwM19TTyqA03X66dzw1tEIdJvQ4lYKkBFox6IAEhoSEZ8Xw==} + + workbox-window@7.4.0: + resolution: {integrity: sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + xdg-basedir@5.1.0: + resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} + engines: {node: '>=12'} + + xe-utils@3.8.0: + resolution: {integrity: sha512-eziNd3IyxzUBAZByQhNuxcd9UUKN2yqR0w2zjPMtXWzzM3GFg6ztjRH76aSfxIZCco1o53TX3uJ7EY3jNpVo/A==} + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml-eslint-parser@1.3.2: + resolution: {integrity: sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==} + engines: {node: ^14.17.0 || >=16.0.0} + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.13: + resolution: {integrity: sha512-3+AG1Xvt+R7M7PSDudhbfbwiyveW6B8PLBIwTyEC598biEYIjHhC89i6DBEvR0EZUjGY3uGSnC429HpIa2Z09g==} + + zip-stream@6.0.1: + resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} + engines: {node: '>= 14'} + + zod-defaults@0.1.3: + resolution: {integrity: sha512-Cp4UjuVfXqwaOx8A5LlM0IRBZs8B7AXgF+XOZWF8CjMDhsY/Jki+y7VS4adVtQj9NNSsAPwylUlJp9INuxPEnA==} + peerDependencies: + zod: ^3.23.8 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zrender@6.0.0: + resolution: {integrity: sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==} + + zx@8.8.5: + resolution: {integrity: sha512-SNgDF5L0gfN7FwVOdEFguY3orU5AkfFZm9B5YSHog/UDHv+lvmd82ZAsOenOkQixigwH2+yyH198AwNdKhj+RA==} + engines: {node: '>= 12.17.0'} + hasBin: true + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@ant-design/colors@6.0.0': + dependencies: + '@ctrl/tinycolor': 4.2.0 + + '@ant-design/icons-svg@4.4.2': {} + + '@ant-design/icons-vue@7.0.1(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-svg': 4.4.2 + vue: 3.5.26(typescript@5.9.3) + + '@apideck/better-ajv-errors@0.3.6(ajv@8.17.1)': + dependencies: + ajv: 8.17.1 + json-schema: 0.4.0 + jsonpointer: 5.0.1 + leven: 3.1.0 + + '@ast-grep/napi-darwin-arm64@0.39.9': + optional: true + + '@ast-grep/napi-darwin-x64@0.39.9': + optional: true + + '@ast-grep/napi-linux-arm64-gnu@0.39.9': + optional: true + + '@ast-grep/napi-linux-arm64-musl@0.39.9': + optional: true + + '@ast-grep/napi-linux-x64-gnu@0.39.9': + optional: true + + '@ast-grep/napi-linux-x64-musl@0.39.9': + optional: true + + '@ast-grep/napi-win32-arm64-msvc@0.39.9': + optional: true + + '@ast-grep/napi-win32-ia32-msvc@0.39.9': + optional: true + + '@ast-grep/napi-win32-x64-msvc@0.39.9': + optional: true + + '@ast-grep/napi@0.39.9': + optionalDependencies: + '@ast-grep/napi-darwin-arm64': 0.39.9 + '@ast-grep/napi-darwin-x64': 0.39.9 + '@ast-grep/napi-linux-arm64-gnu': 0.39.9 + '@ast-grep/napi-linux-arm64-musl': 0.39.9 + '@ast-grep/napi-linux-x64-gnu': 0.39.9 + '@ast-grep/napi-linux-x64-musl': 0.39.9 + '@ast-grep/napi-win32-arm64-msvc': 0.39.9 + '@ast-grep/napi-win32-ia32-msvc': 0.39.9 + '@ast-grep/napi-win32-x64-msvc': 0.39.9 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.28.5 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.5 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.28.5 + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.3 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helper-wrap-function@7.28.3': + dependencies: + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-decorators': 7.27.1(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@babel/plugin-syntax-decorators@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/preset-env@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/core': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) + '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) + '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) + '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) + '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) + babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) + babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) + core-js-compat: 3.47.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.5 + esutils: 2.0.3 + + '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@borewit/text-codec@0.2.1': {} + + '@cacheable/memory@2.0.6': + dependencies: + '@cacheable/utils': 2.3.2 + '@keyv/bigmap': 1.3.0(keyv@5.5.5) + hookified: 1.14.0 + keyv: 5.5.5 + + '@cacheable/utils@2.3.2': + dependencies: + hashery: 1.3.0 + keyv: 5.5.5 + + '@changesets/apply-release-plan@7.0.14': + dependencies: + '@changesets/config': 3.1.2 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.3 + + '@changesets/assemble-release-plan@6.0.9': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.3 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/changelog-github@0.5.2': + dependencies: + '@changesets/get-github-info': 0.7.0 + '@changesets/types': 6.1.0 + dotenv: 8.6.0 + transitivePeerDependencies: + - encoding + + '@changesets/cli@2.29.8(@types/node@24.10.4)': + dependencies: + '@changesets/apply-release-plan': 7.0.14 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.2 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.14 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.6 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@24.10.4) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.3 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.3': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.3 + + '@changesets/get-github-info@0.7.0': + dependencies: + dataloader: 1.4.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + '@changesets/get-release-plan@4.0.14': + dependencies: + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.2 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.6 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.2': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 4.1.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.6': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.2 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.3 + prettier: 2.8.8 + + '@clack/core@0.5.0': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.11.0': + dependencies: + '@clack/core': 0.5.0 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@cloudflare/kv-asset-handler@0.4.1': + dependencies: + mime: 3.0.0 + + '@commitlint/cli@19.8.1(@types/node@25.0.3)(typescript@5.9.3)': + dependencies: + '@commitlint/format': 19.8.1 + '@commitlint/lint': 19.8.1 + '@commitlint/load': 19.8.1(@types/node@25.0.3)(typescript@5.9.3) + '@commitlint/read': 19.8.1 + '@commitlint/types': 19.8.1 + tinyexec: 1.0.2 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/config-conventional@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + conventional-changelog-conventionalcommits: 7.0.2 + + '@commitlint/config-validator@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + ajv: 8.17.1 + + '@commitlint/ensure@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + '@commitlint/execute-rule@19.8.1': {} + + '@commitlint/format@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + chalk: 5.6.2 + + '@commitlint/is-ignored@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + semver: 7.7.3 + + '@commitlint/lint@19.8.1': + dependencies: + '@commitlint/is-ignored': 19.8.1 + '@commitlint/parse': 19.8.1 + '@commitlint/rules': 19.8.1 + '@commitlint/types': 19.8.1 + + '@commitlint/load@19.8.1(@types/node@25.0.3)(typescript@5.9.3)': + dependencies: + '@commitlint/config-validator': 19.8.1 + '@commitlint/execute-rule': 19.8.1 + '@commitlint/resolve-extends': 19.8.1 + '@commitlint/types': 19.8.1 + chalk: 5.6.2 + cosmiconfig: 9.0.0(typescript@5.9.3) + cosmiconfig-typescript-loader: 6.2.0(@types/node@25.0.3)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3) + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + lodash.uniq: 4.5.0 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/message@19.8.1': {} + + '@commitlint/parse@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + conventional-changelog-angular: 7.0.0 + conventional-commits-parser: 5.0.0 + + '@commitlint/read@19.8.1': + dependencies: + '@commitlint/top-level': 19.8.1 + '@commitlint/types': 19.8.1 + git-raw-commits: 4.0.0 + minimist: 1.2.8 + tinyexec: 1.0.2 + + '@commitlint/resolve-extends@19.8.1': + dependencies: + '@commitlint/config-validator': 19.8.1 + '@commitlint/types': 19.8.1 + global-directory: 4.0.1 + import-meta-resolve: 4.2.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + + '@commitlint/rules@19.8.1': + dependencies: + '@commitlint/ensure': 19.8.1 + '@commitlint/message': 19.8.1 + '@commitlint/to-lines': 19.8.1 + '@commitlint/types': 19.8.1 + + '@commitlint/to-lines@19.8.1': {} + + '@commitlint/top-level@19.8.1': + dependencies: + find-up: 7.0.0 + + '@commitlint/types@19.8.1': + dependencies: + '@types/conventional-commits-parser': 5.0.2 + chalk: 5.6.2 + + '@cspell/cspell-bundled-dicts@8.19.4': + dependencies: + '@cspell/dict-ada': 4.1.1 + '@cspell/dict-al': 1.1.1 + '@cspell/dict-aws': 4.0.17 + '@cspell/dict-bash': 4.2.2 + '@cspell/dict-companies': 3.2.9 + '@cspell/dict-cpp': 6.0.15 + '@cspell/dict-cryptocurrencies': 5.0.5 + '@cspell/dict-csharp': 4.0.8 + '@cspell/dict-css': 4.0.19 + '@cspell/dict-dart': 2.3.2 + '@cspell/dict-data-science': 2.0.13 + '@cspell/dict-django': 4.1.6 + '@cspell/dict-docker': 1.1.17 + '@cspell/dict-dotnet': 5.0.10 + '@cspell/dict-elixir': 4.0.8 + '@cspell/dict-en-common-misspellings': 2.1.10 + '@cspell/dict-en-gb': 1.1.33 + '@cspell/dict-en_us': 4.4.26 + '@cspell/dict-filetypes': 3.0.15 + '@cspell/dict-flutter': 1.1.1 + '@cspell/dict-fonts': 4.0.5 + '@cspell/dict-fsharp': 1.1.1 + '@cspell/dict-fullstack': 3.2.7 + '@cspell/dict-gaming-terms': 1.1.2 + '@cspell/dict-git': 3.0.7 + '@cspell/dict-golang': 6.0.25 + '@cspell/dict-google': 1.0.9 + '@cspell/dict-haskell': 4.0.6 + '@cspell/dict-html': 4.0.14 + '@cspell/dict-html-symbol-entities': 4.0.5 + '@cspell/dict-java': 5.0.12 + '@cspell/dict-julia': 1.1.1 + '@cspell/dict-k8s': 1.0.12 + '@cspell/dict-kotlin': 1.1.1 + '@cspell/dict-latex': 4.0.4 + '@cspell/dict-lorem-ipsum': 4.0.5 + '@cspell/dict-lua': 4.0.8 + '@cspell/dict-makefile': 1.0.5 + '@cspell/dict-markdown': 2.0.14(@cspell/dict-css@4.0.19)(@cspell/dict-html-symbol-entities@4.0.5)(@cspell/dict-html@4.0.14)(@cspell/dict-typescript@3.2.3) + '@cspell/dict-monkeyc': 1.0.12 + '@cspell/dict-node': 5.0.8 + '@cspell/dict-npm': 5.2.27 + '@cspell/dict-php': 4.1.0 + '@cspell/dict-powershell': 5.0.15 + '@cspell/dict-public-licenses': 2.0.15 + '@cspell/dict-python': 4.2.24 + '@cspell/dict-r': 2.1.1 + '@cspell/dict-ruby': 5.0.9 + '@cspell/dict-rust': 4.1.0 + '@cspell/dict-scala': 5.0.8 + '@cspell/dict-shell': 1.1.2 + '@cspell/dict-software-terms': 5.1.18 + '@cspell/dict-sql': 2.2.1 + '@cspell/dict-svelte': 1.0.7 + '@cspell/dict-swift': 2.0.6 + '@cspell/dict-terraform': 1.1.3 + '@cspell/dict-typescript': 3.2.3 + '@cspell/dict-vue': 3.0.5 + + '@cspell/cspell-json-reporter@8.19.4': + dependencies: + '@cspell/cspell-types': 8.19.4 + + '@cspell/cspell-pipe@8.19.4': {} + + '@cspell/cspell-resolver@8.19.4': + dependencies: + global-directory: 4.0.1 + + '@cspell/cspell-service-bus@8.19.4': {} + + '@cspell/cspell-types@8.19.4': {} + + '@cspell/dict-ada@4.1.1': {} + + '@cspell/dict-al@1.1.1': {} + + '@cspell/dict-aws@4.0.17': {} + + '@cspell/dict-bash@4.2.2': + dependencies: + '@cspell/dict-shell': 1.1.2 + + '@cspell/dict-companies@3.2.9': {} + + '@cspell/dict-cpp@6.0.15': {} + + '@cspell/dict-cryptocurrencies@5.0.5': {} + + '@cspell/dict-csharp@4.0.8': {} + + '@cspell/dict-css@4.0.19': {} + + '@cspell/dict-dart@2.3.2': {} + + '@cspell/dict-data-science@2.0.13': {} + + '@cspell/dict-django@4.1.6': {} + + '@cspell/dict-docker@1.1.17': {} + + '@cspell/dict-dotnet@5.0.10': {} + + '@cspell/dict-elixir@4.0.8': {} + + '@cspell/dict-en-common-misspellings@2.1.10': {} + + '@cspell/dict-en-gb@1.1.33': {} + + '@cspell/dict-en_us@4.4.26': {} + + '@cspell/dict-filetypes@3.0.15': {} + + '@cspell/dict-flutter@1.1.1': {} + + '@cspell/dict-fonts@4.0.5': {} + + '@cspell/dict-fsharp@1.1.1': {} + + '@cspell/dict-fullstack@3.2.7': {} + + '@cspell/dict-gaming-terms@1.1.2': {} + + '@cspell/dict-git@3.0.7': {} + + '@cspell/dict-golang@6.0.25': {} + + '@cspell/dict-google@1.0.9': {} + + '@cspell/dict-haskell@4.0.6': {} + + '@cspell/dict-html-symbol-entities@4.0.5': {} + + '@cspell/dict-html@4.0.14': {} + + '@cspell/dict-java@5.0.12': {} + + '@cspell/dict-julia@1.1.1': {} + + '@cspell/dict-k8s@1.0.12': {} + + '@cspell/dict-kotlin@1.1.1': {} + + '@cspell/dict-latex@4.0.4': {} + + '@cspell/dict-lorem-ipsum@4.0.5': {} + + '@cspell/dict-lua@4.0.8': {} + + '@cspell/dict-makefile@1.0.5': {} + + '@cspell/dict-markdown@2.0.14(@cspell/dict-css@4.0.19)(@cspell/dict-html-symbol-entities@4.0.5)(@cspell/dict-html@4.0.14)(@cspell/dict-typescript@3.2.3)': + dependencies: + '@cspell/dict-css': 4.0.19 + '@cspell/dict-html': 4.0.14 + '@cspell/dict-html-symbol-entities': 4.0.5 + '@cspell/dict-typescript': 3.2.3 + + '@cspell/dict-monkeyc@1.0.12': {} + + '@cspell/dict-node@5.0.8': {} + + '@cspell/dict-npm@5.2.27': {} + + '@cspell/dict-php@4.1.0': {} + + '@cspell/dict-powershell@5.0.15': {} + + '@cspell/dict-public-licenses@2.0.15': {} + + '@cspell/dict-python@4.2.24': + dependencies: + '@cspell/dict-data-science': 2.0.13 + + '@cspell/dict-r@2.1.1': {} + + '@cspell/dict-ruby@5.0.9': {} + + '@cspell/dict-rust@4.1.0': {} + + '@cspell/dict-scala@5.0.8': {} + + '@cspell/dict-shell@1.1.2': {} + + '@cspell/dict-software-terms@5.1.18': {} + + '@cspell/dict-sql@2.2.1': {} + + '@cspell/dict-svelte@1.0.7': {} + + '@cspell/dict-swift@2.0.6': {} + + '@cspell/dict-terraform@1.1.3': {} + + '@cspell/dict-typescript@3.2.3': {} + + '@cspell/dict-vue@3.0.5': {} + + '@cspell/dynamic-import@8.19.4': + dependencies: + '@cspell/url': 8.19.4 + import-meta-resolve: 4.2.0 + + '@cspell/filetypes@8.19.4': {} + + '@cspell/strong-weak-map@8.19.4': {} + + '@cspell/url@8.19.4': {} + + '@csstools/cascade-layer-name-parser@2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-syntax-patches-for-csstree@1.0.22': {} + + '@csstools/css-tokenizer@3.0.4': {} + + '@csstools/media-query-list-parser@3.0.1(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/postcss-alpha-function@1.0.1(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.6)': + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/postcss-color-function-display-p3-linear@1.0.1(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-color-function@4.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-color-mix-function@3.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-color-mix-variadic-function-arguments@1.0.2(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-content-alt-text@2.0.8(postcss@8.5.6)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-contrast-color-function@2.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-exponential-functions@2.0.9(postcss@8.5.6)': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-font-format-keywords@4.0.0(postcss@8.5.6)': + dependencies: + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-gamut-mapping@2.0.11(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-gradients-interpolation-method@5.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-hwb-function@4.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-ic-unit@4.0.4(postcss@8.5.6)': + dependencies: + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-initial@2.0.1(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@csstools/postcss-is-pseudo-class@5.0.3(postcss@8.5.6)': + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/postcss-light-dark-function@2.0.11(postcss@8.5.6)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-logical-float-and-clear@3.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@csstools/postcss-logical-overflow@2.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@csstools/postcss-logical-overscroll-behavior@2.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@csstools/postcss-logical-resize@3.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-logical-viewport-units@3.0.4(postcss@8.5.6)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-media-minmax@2.0.9(postcss@8.5.6)': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + postcss: 8.5.6 + + '@csstools/postcss-media-queries-aspect-ratio-number-values@3.0.5(postcss@8.5.6)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + postcss: 8.5.6 + + '@csstools/postcss-nested-calc@4.0.0(postcss@8.5.6)': + dependencies: + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-normalize-display-values@4.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-oklab-function@4.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-position-area-property@1.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@csstools/postcss-progressive-custom-properties@4.2.1(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-random-function@2.0.1(postcss@8.5.6)': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-relative-color-syntax@3.0.12(postcss@8.5.6)': + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + '@csstools/postcss-scope-pseudo-class@4.0.1(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/postcss-sign-functions@1.1.4(postcss@8.5.6)': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-stepped-value-functions@4.0.9(postcss@8.5.6)': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-system-ui-font-family@1.0.0(postcss@8.5.6)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-text-decoration-shorthand@4.0.3(postcss@8.5.6)': + dependencies: + '@csstools/color-helpers': 5.1.0 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + '@csstools/postcss-trigonometric-functions@4.0.9(postcss@8.5.6)': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + + '@csstools/postcss-unset-value@4.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@csstools/selector-resolve-nested@3.1.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + + '@csstools/utilities@2.0.0(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + + '@ctrl/tinycolor@4.2.0': {} + + '@dual-bundle/import-meta-resolve@4.2.1': {} + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/hash@0.9.2': {} + + '@emotion/unitless@0.8.1': {} + + '@es-joy/jsdoccomment@0.76.0': + dependencies: + '@types/estree': 1.0.8 + '@typescript-eslint/types': 8.50.1 + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 6.10.0 + + '@es-joy/jsdoccomment@0.78.0': + dependencies: + '@types/estree': 1.0.8 + '@typescript-eslint/types': 8.50.1 + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 7.0.0 + + '@es-joy/resolve.exports@1.2.0': {} + + '@esbuild/aix-ppc64@0.25.3': + optional: true + + '@esbuild/android-arm64@0.25.3': + optional: true + + '@esbuild/android-arm@0.25.3': + optional: true + + '@esbuild/android-x64@0.25.3': + optional: true + + '@esbuild/darwin-arm64@0.25.3': + optional: true + + '@esbuild/darwin-x64@0.25.3': + optional: true + + '@esbuild/freebsd-arm64@0.25.3': + optional: true + + '@esbuild/freebsd-x64@0.25.3': + optional: true + + '@esbuild/linux-arm64@0.25.3': + optional: true + + '@esbuild/linux-arm@0.25.3': + optional: true + + '@esbuild/linux-ia32@0.25.3': + optional: true + + '@esbuild/linux-loong64@0.25.3': + optional: true + + '@esbuild/linux-mips64el@0.25.3': + optional: true + + '@esbuild/linux-ppc64@0.25.3': + optional: true + + '@esbuild/linux-riscv64@0.25.3': + optional: true + + '@esbuild/linux-s390x@0.25.3': + optional: true + + '@esbuild/linux-x64@0.25.3': + optional: true + + '@esbuild/netbsd-arm64@0.25.3': + optional: true + + '@esbuild/netbsd-x64@0.25.3': + optional: true + + '@esbuild/openbsd-arm64@0.25.3': + optional: true + + '@esbuild/openbsd-x64@0.25.3': + optional: true + + '@esbuild/sunos-x64@0.25.3': + optional: true + + '@esbuild/win32-arm64@0.25.3': + optional: true + + '@esbuild/win32-ia32@0.25.3': + optional: true + + '@esbuild/win32-x64@0.25.3': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': + dependencies: + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.2': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/utils@0.2.10': {} + + '@floating-ui/vue@1.1.9(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.4 + '@floating-ui/utils': 0.2.10 + vue-demi: 0.14.10(vue@3.5.26(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@highlightjs/vue-plugin@2.1.0(highlight.js@11.11.1)(vue@3.5.26(typescript@5.9.3))': + dependencies: + highlight.js: 11.11.1 + vue: 3.5.26(typescript@5.9.3) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@iconify/icons-ant-design@1.2.7': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-arcticons@1.2.77': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-fa-brands@1.2.4': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-flat-color-icons@1.2.5': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-la@1.2.3': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-logos@1.2.36': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-ri@1.2.10': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-simple-icons@1.2.74': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/icons-uiw@1.2.6': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/json@2.2.417': + dependencies: + '@iconify/types': 2.0.0 + pathe: 2.0.3 + + '@iconify/tailwind@1.2.0': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + + '@iconify/vue@5.0.0(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@iconify/types': 2.0.0 + vue: 3.5.26(typescript@5.9.3) + + '@inquirer/external-editor@1.0.3(@types/node@24.10.4)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.1 + optionalDependencies: + '@types/node': 24.10.4 + + '@internationalized/date@3.10.1': + dependencies: + '@swc/helpers': 0.5.17 + + '@internationalized/number@3.6.5': + dependencies: + '@swc/helpers': 0.5.17 + + '@intlify/bundle-utils@10.0.1(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))': + dependencies: + '@intlify/message-compiler': 11.2.7 + '@intlify/shared': 11.2.7 + acorn: 8.15.0 + escodegen: 2.1.0 + estree-walker: 2.0.2 + jsonc-eslint-parser: 2.4.2 + mlly: 1.8.0 + source-map-js: 1.2.1 + yaml-eslint-parser: 1.3.2 + optionalDependencies: + vue-i18n: 11.2.7(vue@3.5.26(typescript@5.9.3)) + + '@intlify/core-base@11.2.7': + dependencies: + '@intlify/message-compiler': 11.2.7 + '@intlify/shared': 11.2.7 + + '@intlify/message-compiler@11.2.7': + dependencies: + '@intlify/shared': 11.2.7 + source-map-js: 1.2.1 + + '@intlify/shared@11.2.7': {} + + '@intlify/unplugin-vue-i18n@6.0.8(@vue/compiler-dom@3.5.26)(eslint@9.39.2(jiti@2.6.1))(rollup@4.54.0)(typescript@5.9.3)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@intlify/bundle-utils': 10.0.1(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3))) + '@intlify/shared': 11.2.7 + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.7)(@vue/compiler-dom@3.5.26)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + debug: 4.4.3 + fast-glob: 3.3.3 + js-yaml: 4.1.1 + json5: 2.2.3 + pathe: 1.1.2 + picocolors: 1.1.1 + source-map-js: 1.2.1 + unplugin: 1.16.1 + vue: 3.5.26(typescript@5.9.3) + optionalDependencies: + vue-i18n: 11.2.7(vue@3.5.26(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/compiler-dom' + - eslint + - rollup + - supports-color + - typescript + + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.7)(@vue/compiler-dom@3.5.26)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@babel/parser': 7.28.5 + optionalDependencies: + '@intlify/shared': 11.2.7 + '@vue/compiler-dom': 3.5.26 + vue: 3.5.26(typescript@5.9.3) + vue-i18n: 11.2.7(vue@3.5.26(typescript@5.9.3)) + + '@ioredis/commands@1.4.0': {} + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jspm/generator@2.8.0': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + '@jspm/import-map': 1.2.2 + es-module-lexer: 1.7.0 + minimatch: 10.1.1 + node-fetch-cache: 5.1.0 + pako: 2.1.0 + sver: 1.8.4 + tar-stream: 3.1.7 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + - supports-color + + '@jspm/import-map@1.2.2': {} + + '@keyv/bigmap@1.3.0(keyv@5.5.5)': + dependencies: + hashery: 1.3.0 + hookified: 1.14.0 + keyv: 5.5.5 + + '@keyv/serialize@1.1.1': {} + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.28.4 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/find-root@3.1.0': + dependencies: + '@manypkg/tools': 2.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.28.4 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@manypkg/get-packages@3.1.0': + dependencies: + '@manypkg/find-root': 3.1.0 + '@manypkg/tools': 2.1.0 + + '@manypkg/tools@2.1.0': + dependencies: + jju: 1.4.0 + js-yaml: 4.1.1 + tinyglobby: 0.2.15 + + '@mapbox/node-pre-gyp@2.0.3': + dependencies: + consola: 3.4.2 + detect-libc: 2.1.2 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.3 + tar: 7.5.2 + transitivePeerDependencies: + - encoding + - supports-color + + '@microsoft/api-extractor-model@7.32.2(@types/node@25.0.3)': + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@rushstack/node-core-library': 5.19.1(@types/node@25.0.3) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.55.2(@types/node@25.0.3)': + dependencies: + '@microsoft/api-extractor-model': 7.32.2(@types/node@25.0.3) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.0 + '@rushstack/node-core-library': 5.19.1(@types/node@25.0.3) + '@rushstack/rig-package': 0.6.0 + '@rushstack/terminal': 0.19.5(@types/node@25.0.3) + '@rushstack/ts-command-line': 5.1.5(@types/node@25.0.3) + diff: 8.0.2 + lodash: 4.17.21 + minimatch: 10.0.3 + resolve: 1.22.11 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.18.0': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.11 + + '@microsoft/tsdoc@0.16.0': {} + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@npmcli/fs@5.0.0': + dependencies: + semver: 7.7.3 + + '@nuxt/kit@3.20.2(magicast@0.5.1)': + dependencies: + c12: 3.3.3(magicast@0.5.1) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unctx: 2.5.0 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + optional: true + + '@nuxt/kit@4.2.2(magicast@0.5.1)': + dependencies: + c12: 3.3.3(magicast@0.5.1) + consola: 3.4.2 + defu: 6.1.4 + destr: 2.0.5 + errx: 0.1.0 + exsolve: 1.0.8 + ignore: 7.0.5 + jiti: 2.6.1 + klona: 2.0.6 + mlly: 1.8.0 + ohash: 2.0.11 + pathe: 2.0.3 + pkg-types: 2.3.0 + rc9: 2.1.2 + scule: 1.3.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + ufo: 1.6.1 + unctx: 2.5.0 + untyped: 2.0.0 + transitivePeerDependencies: + - magicast + optional: true + + '@one-ini/wasm@0.1.1': {} + + '@parcel/watcher-android-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.1': + optional: true + + '@parcel/watcher-darwin-x64@2.5.1': + optional: true + + '@parcel/watcher-freebsd-x64@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-arm64-musl@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-glibc@2.5.1': + optional: true + + '@parcel/watcher-linux-x64-musl@2.5.1': + optional: true + + '@parcel/watcher-wasm@2.5.1': + dependencies: + is-glob: 4.0.3 + micromatch: 4.0.8 + + '@parcel/watcher-win32-arm64@2.5.1': + optional: true + + '@parcel/watcher-win32-ia32@2.5.1': + optional: true + + '@parcel/watcher-win32-x64@2.5.1': + optional: true + + '@parcel/watcher@2.5.1': + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.5.1 + '@parcel/watcher-darwin-arm64': 2.5.1 + '@parcel/watcher-darwin-x64': 2.5.1 + '@parcel/watcher-freebsd-x64': 2.5.1 + '@parcel/watcher-linux-arm-glibc': 2.5.1 + '@parcel/watcher-linux-arm-musl': 2.5.1 + '@parcel/watcher-linux-arm64-glibc': 2.5.1 + '@parcel/watcher-linux-arm64-musl': 2.5.1 + '@parcel/watcher-linux-x64-glibc': 2.5.1 + '@parcel/watcher-linux-x64-musl': 2.5.1 + '@parcel/watcher-win32-arm64': 2.5.1 + '@parcel/watcher-win32-ia32': 2.5.1 + '@parcel/watcher-win32-x64': 2.5.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@playwright/test@1.57.0': + dependencies: + playwright: 1.57.0 + + '@pnpm/config.env-replace@1.1.0': {} + + '@pnpm/constants@1001.3.1': {} + + '@pnpm/error@1000.0.5': + dependencies: + '@pnpm/constants': 1001.3.1 + + '@pnpm/network.ca-file@1.0.2': + dependencies: + graceful-fs: 4.2.10 + + '@pnpm/npm-conf@2.3.1': + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + + '@pnpm/types@1001.2.0': {} + + '@pnpm/workspace.read-manifest@1000.2.9': + dependencies: + '@pnpm/constants': 1001.3.1 + '@pnpm/error': 1000.0.5 + '@pnpm/types': 1001.2.0 + read-yaml-file: 2.1.0 + + '@polka/url@1.0.0-next.29': {} + + '@popperjs/core@2.11.8': {} + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.1.1 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@publint/pack@0.1.2': {} + + '@rolldown/pluginutils@1.0.0-beta.53': {} + + '@rolldown/pluginutils@1.0.0-beta.57': {} + + '@rollup/plugin-alias@5.1.1(rollup@4.54.0)': + optionalDependencies: + rollup: 4.54.0 + + '@rollup/plugin-babel@5.3.1(@babel/core@7.28.5)(rollup@2.79.2)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@rollup/pluginutils': 3.1.0(rollup@2.79.2) + rollup: 2.79.2 + transitivePeerDependencies: + - supports-color + + '@rollup/plugin-commonjs@28.0.9(rollup@4.54.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.5.0(picomatch@4.0.3) + is-reference: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/plugin-inject@5.0.5(rollup@4.54.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + estree-walker: 2.0.2 + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/plugin-json@6.1.0(rollup@4.54.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + optionalDependencies: + rollup: 4.54.0 + + '@rollup/plugin-node-resolve@15.3.1(rollup@2.79.2)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@2.79.2) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + optionalDependencies: + rollup: 2.79.2 + + '@rollup/plugin-node-resolve@16.0.3(rollup@4.54.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/plugin-replace@2.4.2(rollup@2.79.2)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.79.2) + magic-string: 0.25.9 + rollup: 2.79.2 + + '@rollup/plugin-replace@6.0.3(rollup@4.54.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/plugin-terser@0.4.4(rollup@2.79.2)': + dependencies: + serialize-javascript: 6.0.2 + smob: 1.5.0 + terser: 5.44.1 + optionalDependencies: + rollup: 2.79.2 + + '@rollup/plugin-terser@0.4.4(rollup@4.54.0)': + dependencies: + serialize-javascript: 6.0.2 + smob: 1.5.0 + terser: 5.44.1 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/pluginutils@3.1.0(rollup@2.79.2)': + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.79.2 + + '@rollup/pluginutils@4.2.1': + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + + '@rollup/pluginutils@5.3.0(rollup@2.79.2)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 2.79.2 + + '@rollup/pluginutils@5.3.0(rollup@4.54.0)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.54.0 + + '@rollup/rollup-android-arm-eabi@4.54.0': + optional: true + + '@rollup/rollup-android-arm64@4.54.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.54.0': + optional: true + + '@rollup/rollup-darwin-x64@4.54.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.54.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.54.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.54.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.54.0': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.54.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.54.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.54.0': + optional: true + + '@rollup/rollup-openharmony-arm64@4.54.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.54.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.54.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.54.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.54.0': + optional: true + + '@rushstack/node-core-library@5.19.1(@types/node@25.0.3)': + dependencies: + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 11.3.3 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.5.4 + optionalDependencies: + '@types/node': 25.0.3 + + '@rushstack/problem-matcher@0.1.1(@types/node@25.0.3)': + optionalDependencies: + '@types/node': 25.0.3 + + '@rushstack/rig-package@0.6.0': + dependencies: + resolve: 1.22.11 + strip-json-comments: 3.1.1 + + '@rushstack/terminal@0.19.5(@types/node@25.0.3)': + dependencies: + '@rushstack/node-core-library': 5.19.1(@types/node@25.0.3) + '@rushstack/problem-matcher': 0.1.1(@types/node@25.0.3) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 25.0.3 + + '@rushstack/ts-command-line@5.1.5(@types/node@25.0.3)': + dependencies: + '@rushstack/terminal': 0.19.5(@types/node@25.0.3) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@sec-ant/readable-stream@0.4.1': {} + + '@simonwep/pickr@1.8.2': + dependencies: + core-js: 3.47.0 + nanopop: 2.4.2 + + '@sindresorhus/base62@1.0.0': {} + + '@sindresorhus/is@7.1.1': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@speed-highlight/core@1.2.12': {} + + '@stylistic/stylelint-plugin@3.1.3(stylelint@16.26.1(typescript@5.9.3))': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 3.0.1(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + is-plain-object: 5.0.0 + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + postcss-value-parser: 4.2.0 + style-search: 0.1.0 + stylelint: 16.26.1(typescript@5.9.3) + + '@surma/rollup-plugin-off-main-thread@2.2.3': + dependencies: + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.25.9 + string.prototype.matchall: 4.0.12 + + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/nesting@0.0.0-insiders.565cd3e(postcss@8.5.6)': + dependencies: + postcss: 8.5.6 + postcss-nested: 5.0.6(postcss@8.5.6) + + '@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(yaml@2.8.2))': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.19(yaml@2.8.2) + + '@tanstack/store@0.8.0': {} + + '@tanstack/virtual-core@3.13.13': {} + + '@tanstack/vue-store@0.8.0(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@tanstack/store': 0.8.0 + vue: 3.5.26(typescript@5.9.3) + vue-demi: 0.14.10(vue@3.5.26(typescript@5.9.3)) + + '@tanstack/vue-virtual@3.13.13(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@tanstack/virtual-core': 3.13.13 + vue: 3.5.26(typescript@5.9.3) + + '@tinymce/tinymce-vue@6.3.0(tinymce@7.9.1)(vue@3.5.26(typescript@5.9.3))': + dependencies: + vue: 3.5.26(typescript@5.9.3) + optionalDependencies: + tinymce: 7.9.1 + + '@tokenizer/token@0.3.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/archiver@6.0.4': + dependencies: + '@types/readdir-glob': 1.1.5 + + '@types/argparse@1.0.38': {} + + '@types/bintrees@1.0.6': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/conventional-commits-parser@5.0.2': + dependencies: + '@types/node': 25.0.3 + + '@types/deep-eql@4.0.2': {} + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + + '@types/estree@0.0.39': {} + + '@types/estree@1.0.8': {} + + '@types/html-minifier-terser@7.0.2': {} + + '@types/json-schema@7.0.15': {} + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.21 + + '@types/lodash.clonedeep@4.5.9': + dependencies: + '@types/lodash': 4.17.21 + + '@types/lodash.get@4.4.9': + dependencies: + '@types/lodash': 4.17.21 + + '@types/lodash.isequal@4.5.8': + dependencies: + '@types/lodash': 4.17.21 + + '@types/lodash.set@4.3.9': + dependencies: + '@types/lodash': 4.17.21 + + '@types/lodash@4.17.21': {} + + '@types/minimatch@3.0.5': {} + + '@types/node@12.20.55': {} + + '@types/node@24.10.4': + dependencies: + undici-types: 7.16.0 + + '@types/node@25.0.3': + dependencies: + undici-types: 7.16.0 + + '@types/nprogress@0.2.3': {} + + '@types/parse-json@4.0.2': {} + + '@types/postcss-import@14.0.3': + dependencies: + postcss: 8.5.6 + + '@types/qrcode@1.5.6': + dependencies: + '@types/node': 25.0.3 + + '@types/qs@6.14.0': {} + + '@types/readdir-glob@1.1.5': + dependencies: + '@types/node': 25.0.3 + + '@types/resolve@1.20.2': {} + + '@types/sortablejs@1.15.9': {} + + '@types/trusted-types@2.0.7': {} + + '@types/web-bluetooth@0.0.21': {} + + '@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/type-utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.1 + eslint: 9.39.2(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.1 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.50.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@7.18.0': + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + + '@typescript-eslint/scope-manager@8.50.1': + dependencies: + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/visitor-keys': 8.50.1 + + '@typescript-eslint/tsconfig-utils@8.50.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@7.18.0': {} + + '@typescript-eslint/types@8.50.1': {} + + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.3 + ts-api-utils: 1.4.3(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.50.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.50.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.50.1(typescript@5.9.3) + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/visitor-keys': 8.50.1 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@7.18.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.50.1 + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/typescript-estree': 8.50.1(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@7.18.0': + dependencies: + '@typescript-eslint/types': 7.18.0 + eslint-visitor-keys: 3.4.3 + + '@typescript-eslint/visitor-keys@8.50.1': + dependencies: + '@typescript-eslint/types': 8.50.1 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vee-validate/zod@4.15.1(vue@3.5.26(typescript@5.9.3))(zod@3.25.76)': + dependencies: + type-fest: 4.41.0 + vee-validate: 4.15.1(vue@3.5.26(typescript@5.9.3)) + zod: 3.25.76 + transitivePeerDependencies: + - vue + + '@vercel/nft@0.30.4(rollup@4.54.0)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 10.5.0 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.4 + picomatch: 4.0.3 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vitejs/plugin-vue-jsx@5.1.3(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.57 + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.5) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vue: 3.5.26(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue-jsx@5.1.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.57 + '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.5) + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vue: 3.5.26(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@rolldown/pluginutils': 1.0.0-beta.53 + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vue: 3.5.26(typescript@5.9.3) + + '@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@rolldown/pluginutils': 1.0.0-beta.53 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vue: 3.5.26(typescript@5.9.3) + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + '@volar/language-core@2.4.27': + dependencies: + '@volar/source-map': 2.4.27 + + '@volar/source-map@2.4.27': {} + + '@volar/typescript@2.4.27': + dependencies: + '@volar/language-core': 2.4.27 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/babel-helper-vue-transform-on@1.5.0': {} + + '@vue/babel-helper-vue-transform-on@2.0.1': {} + + '@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.5)': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@vue/babel-helper-vue-transform-on': 1.5.0 + '@vue/babel-plugin-resolve-type': 1.5.0(@babel/core@7.28.5) + '@vue/shared': 3.5.26 + optionalDependencies: + '@babel/core': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.28.5)': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@vue/babel-helper-vue-transform-on': 2.0.1 + '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.28.5) + '@vue/shared': 3.5.26 + optionalDependencies: + '@babel/core': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.28.5)': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.28.5 + '@vue/compiler-sfc': 3.5.26 + transitivePeerDependencies: + - supports-color + + '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.28.5)': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.28.5 + '@vue/compiler-sfc': 3.5.26 + transitivePeerDependencies: + - supports-color + + '@vue/compiler-core@3.5.26': + dependencies: + '@babel/parser': 7.28.5 + '@vue/shared': 3.5.26 + entities: 7.0.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.26': + dependencies: + '@vue/compiler-core': 3.5.26 + '@vue/shared': 3.5.26 + + '@vue/compiler-sfc@3.5.26': + dependencies: + '@babel/parser': 7.28.5 + '@vue/compiler-core': 3.5.26 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.6 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.26': + dependencies: + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/devtools-api@6.6.4': {} + + '@vue/devtools-api@7.7.9': + dependencies: + '@vue/devtools-kit': 7.7.9 + + '@vue/devtools-core@8.0.5(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@vue/devtools-kit': 8.0.5 + '@vue/devtools-shared': 8.0.5 + mitt: 3.0.1 + nanoid: 5.1.6 + pathe: 2.0.3 + vite-hot-client: 2.1.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + vue: 3.5.26(typescript@5.9.3) + transitivePeerDependencies: + - vite + + '@vue/devtools-kit@7.7.9': + dependencies: + '@vue/devtools-shared': 7.7.9 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + + '@vue/devtools-kit@8.0.5': + dependencies: + '@vue/devtools-shared': 8.0.5 + birpc: 2.9.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 2.0.0 + speakingurl: 14.0.1 + superjson: 2.2.6 + + '@vue/devtools-shared@7.7.9': + dependencies: + rfdc: 1.4.1 + + '@vue/devtools-shared@8.0.5': + dependencies: + rfdc: 1.4.1 + + '@vue/language-core@2.2.0(typescript@5.9.3)': + dependencies: + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.26 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.9.3 + + '@vue/language-core@3.2.1': + dependencies: + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 + alien-signals: 3.1.1 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.3 + + '@vue/reactivity@3.5.26': + dependencies: + '@vue/shared': 3.5.26 + + '@vue/runtime-core@3.5.26': + dependencies: + '@vue/reactivity': 3.5.26 + '@vue/shared': 3.5.26 + + '@vue/runtime-dom@3.5.26': + dependencies: + '@vue/reactivity': 3.5.26 + '@vue/runtime-core': 3.5.26 + '@vue/shared': 3.5.26 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.26(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 + vue: 3.5.26(typescript@5.9.3) + + '@vue/shared@3.5.26': {} + + '@vue/test-utils@2.4.6': + dependencies: + js-beautify: 1.15.4 + vue-component-type-helpers: 2.2.12 + + '@vueuse/core@12.8.2(typescript@5.9.3)': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 12.8.2 + '@vueuse/shared': 12.8.2(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@vueuse/core@13.9.0(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.9.0 + '@vueuse/shared': 13.9.0(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) + + '@vueuse/core@14.1.0(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.1.0 + '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) + + '@vueuse/integrations@14.1.0(async-validator@4.2.5)(axios@1.13.2)(change-case@5.4.4)(focus-trap@7.7.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@vueuse/core': 14.1.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) + optionalDependencies: + async-validator: 4.2.5 + axios: 1.13.2 + change-case: 5.4.4 + focus-trap: 7.7.0 + nprogress: 0.2.0 + qrcode: 1.5.4 + sortablejs: 1.15.6 + + '@vueuse/metadata@12.8.2': {} + + '@vueuse/metadata@13.9.0': {} + + '@vueuse/metadata@14.1.0': {} + + '@vueuse/motion@3.0.3(magicast@0.5.1)(vue@3.5.26(typescript@5.9.3))': + dependencies: + '@vueuse/core': 13.9.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/shared': 13.9.0(vue@3.5.26(typescript@5.9.3)) + defu: 6.1.4 + framesync: 6.1.2 + popmotion: 11.0.5 + style-value-types: 5.1.2 + vue: 3.5.26(typescript@5.9.3) + optionalDependencies: + '@nuxt/kit': 3.20.2(magicast@0.5.1) + transitivePeerDependencies: + - magicast + + '@vueuse/shared@12.8.2(typescript@5.9.3)': + dependencies: + vue: 3.5.26(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@vueuse/shared@13.9.0(vue@3.5.26(typescript@5.9.3))': + dependencies: + vue: 3.5.26(typescript@5.9.3) + + '@vueuse/shared@14.1.0(vue@3.5.26(typescript@5.9.3))': + dependencies: + vue: 3.5.26(typescript@5.9.3) + + '@vxe-ui/core@4.2.16(vue@3.5.26(typescript@5.9.3))': + dependencies: + dom-zindex: 1.0.6 + vue: 3.5.26(typescript@5.9.3) + xe-utils: 3.8.0 + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + abbrev@2.0.0: {} + + abbrev@3.0.1: {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn-import-attributes@1.9.5(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agent-base@7.1.4: {} + + ajv-draft-04@1.0.0(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv-formats@3.0.1(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ajv@8.13.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + alien-signals@0.4.14: {} + + alien-signals@3.1.1: {} + + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + + ansi-colors@4.1.3: {} + + ansi-escapes@7.2.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + ansis@4.2.0: {} + + ant-design-vue@4.2.6(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@ant-design/colors': 6.0.0 + '@ant-design/icons-vue': 7.0.1(vue@3.5.26(typescript@5.9.3)) + '@babel/runtime': 7.28.4 + '@ctrl/tinycolor': 4.2.0 + '@emotion/hash': 0.9.2 + '@emotion/unitless': 0.8.1 + '@simonwep/pickr': 1.8.2 + array-tree-filter: 2.1.0 + async-validator: 4.2.5 + csstype: 3.2.3 + dayjs: 1.11.19 + dom-align: 1.12.4 + dom-scroll-into-view: 2.0.1 + lodash: 4.17.21 + lodash-es: 4.17.22 + resize-observer-polyfill: 1.5.1 + scroll-into-view-if-needed: 2.2.31 + shallow-equal: 1.2.1 + stylis: 4.3.6 + throttle-debounce: 5.0.2 + vue: 3.5.26(typescript@5.9.3) + vue-types: 3.0.2(vue@3.5.26(typescript@5.9.3)) + warning: 4.0.3 + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + archiver-utils@5.0.2: + dependencies: + glob: 10.5.0 + graceful-fs: 4.2.11 + is-stream: 2.0.1 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + archiver@7.0.1: + dependencies: + archiver-utils: 5.0.2 + async: 3.2.6 + buffer-crc32: 1.0.0 + readable-stream: 4.7.0 + readdir-glob: 1.1.3 + tar-stream: 3.1.7 + zip-stream: 6.0.1 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + are-docs-informative@0.0.2: {} + + arg@5.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-differ@3.0.0: {} + + array-ify@1.0.0: {} + + array-timsort@1.0.3: {} + + array-tree-filter@2.1.0: {} + + array-union@2.1.0: {} + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + arrify@2.0.1: {} + + assertion-error@2.0.1: {} + + astral-regex@2.0.0: {} + + async-function@1.0.0: {} + + async-sema@3.1.1: {} + + async-validator@4.2.5: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + atomically@2.1.0: + dependencies: + stubborn-fs: 2.0.0 + when-exit: 2.1.5 + + autoprefixer@10.4.23(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001761 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axios-mock-adapter@2.1.0(axios@1.13.2): + dependencies: + axios: 1.13.2 + fast-deep-equal: 3.1.3 + is-buffer: 2.0.5 + + axios@1.13.2: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + b4a@1.7.3: {} + + babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/core': 7.28.5 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + core-js-compat: 3.47.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + balanced-match@1.0.2: {} + + balanced-match@2.0.0: {} + + bare-events@2.8.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.9.11: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + bignumber.js@9.3.1: {} + + binary-extensions@2.3.0: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bintrees@1.0.2: {} + + birpc@2.9.0: {} + + boolbase@1.0.0: {} + + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.2 + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.11 + caniuse-lite: 1.0.30001761 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + buffer-crc32@1.0.0: {} + + buffer-from@1.1.2: {} + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + builtin-modules@5.0.0: {} + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + c12@3.3.3(magicast@0.5.1): + dependencies: + chokidar: 5.0.0 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 17.2.3 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + rc9: 2.1.2 + optionalDependencies: + magicast: 0.5.1 + + cac@6.7.14: {} + + cacache@20.0.3: + dependencies: + '@npmcli/fs': 5.0.0 + fs-minipass: 3.0.3 + glob: 13.0.0 + lru-cache: 11.2.4 + minipass: 7.1.2 + minipass-collect: 2.0.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + p-map: 7.0.4 + ssri: 13.0.0 + unique-filename: 5.0.0 + + cacheable@2.3.1: + dependencies: + '@cacheable/memory': 2.0.6 + '@cacheable/utils': 2.3.2 + hookified: 1.14.0 + keyv: 5.5.5 + qified: 0.5.3 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsite@1.0.0: {} + + callsites@3.1.0: {} + + camel-case@4.1.2: + dependencies: + pascal-case: 3.1.2 + tslib: 2.8.1 + + camelcase-css@2.0.1: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + camelcase@8.0.0: {} + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001761 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001761: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk-template@1.1.2: + dependencies: + chalk: 5.6.2 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + change-case@5.4.4: {} + + chardet@2.1.1: {} + + check-error@2.1.1: {} + + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.1.2: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.0.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.16.0 + whatwg-mimetype: 4.0.0 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + chownr@3.0.0: {} + + ci-info@3.9.0: {} + + ci-info@4.3.1: {} + + circular-dependency-scanner@2.3.0: + dependencies: + '@ast-grep/napi': 0.39.9 + '@vue/compiler-sfc': 3.5.26 + commander: 12.1.0 + get-tsconfig: 4.13.0 + graph-cycles: 3.0.0 + listr2: 8.3.3 + minimatch: 9.0.5 + node-cleanup: 2.1.2 + typescript: 5.9.3 + update-notifier: 7.3.1 + zx: 8.8.5 + + citty@0.1.6: + dependencies: + consola: 3.4.2 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clean-css@5.3.3: + dependencies: + source-map: 0.6.1 + + clean-regexp@1.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + clear-module@4.1.2: + dependencies: + parent-module: 2.0.0 + resolve-from: 5.0.0 + + cli-boxes@3.0.0: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-spinners@2.9.2: {} + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + clipboard@2.0.11: + dependencies: + good-listener: 1.2.2 + select: 1.1.2 + tiny-emitter: 2.1.0 + + clipboardy@4.0.0: + dependencies: + execa: 8.0.1 + is-wsl: 3.1.0 + is64bit: 2.0.0 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + cluster-key-slot@1.1.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colord@2.9.3: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@10.0.1: {} + + commander@11.1.0: {} + + commander@12.1.0: {} + + commander@13.1.0: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + commander@8.3.0: {} + + comment-json@4.5.0: + dependencies: + array-timsort: 1.0.3 + core-util-is: 1.0.3 + esprima: 4.0.1 + + comment-parser@1.4.1: {} + + commitlint-plugin-function-rules@4.2.0(@commitlint/lint@19.8.1): + dependencies: + '@commitlint/lint': 19.8.1 + + common-tags@1.8.2: {} + + commondir@1.0.1: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + compare-versions@6.1.1: {} + + compatx@0.2.0: {} + + compress-commons@6.0.2: + dependencies: + crc-32: 1.2.2 + crc32-stream: 6.0.0 + is-stream: 2.0.1 + normalize-path: 3.0.0 + readable-stream: 4.7.0 + + compute-scroll-into-view@1.0.20: {} + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + confbox@0.2.2: {} + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + configstore@7.1.0: + dependencies: + atomically: 2.1.0 + dot-prop: 9.0.0 + graceful-fs: 4.2.11 + xdg-basedir: 5.1.0 + + connect-history-api-fallback@1.6.0: {} + + consola@2.15.3: {} + + consola@3.4.2: {} + + conventional-changelog-angular@7.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@7.0.2: + dependencies: + compare-func: 2.0.0 + + conventional-commits-parser@5.0.0: + dependencies: + JSONStream: 1.3.5 + is-text-path: 2.0.0 + meow: 12.1.1 + split2: 4.2.0 + + convert-source-map@2.0.0: {} + + cookie-es@1.2.2: {} + + cookie-es@2.0.0: {} + + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + optional: true + + copy-anything@4.0.5: + dependencies: + is-what: 5.5.0 + + core-js-compat@3.47.0: + dependencies: + browserslist: 4.28.1 + + core-js@3.47.0: {} + + core-util-is@1.0.3: {} + + cosmiconfig-typescript-loader@6.2.0(@types/node@25.0.3)(cosmiconfig@9.0.0(typescript@5.9.3))(typescript@5.9.3): + dependencies: + '@types/node': 25.0.3 + cosmiconfig: 9.0.0(typescript@5.9.3) + jiti: 2.6.1 + typescript: 5.9.3 + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + cosmiconfig@9.0.0(typescript@5.9.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.9.3 + + crc-32@1.2.2: {} + + crc32-stream@6.0.0: + dependencies: + crc-32: 1.2.2 + readable-stream: 4.7.0 + + croner@9.1.0: {} + + cropperjs@1.6.2: {} + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + crypto-js@4.2.0: {} + + crypto-random-string@2.0.0: {} + + cspell-config-lib@8.19.4: + dependencies: + '@cspell/cspell-types': 8.19.4 + comment-json: 4.5.0 + yaml: 2.8.2 + + cspell-dictionary@8.19.4: + dependencies: + '@cspell/cspell-pipe': 8.19.4 + '@cspell/cspell-types': 8.19.4 + cspell-trie-lib: 8.19.4 + fast-equals: 5.4.0 + + cspell-gitignore@8.19.4: + dependencies: + '@cspell/url': 8.19.4 + cspell-glob: 8.19.4 + cspell-io: 8.19.4 + + cspell-glob@8.19.4: + dependencies: + '@cspell/url': 8.19.4 + picomatch: 4.0.3 + + cspell-grammar@8.19.4: + dependencies: + '@cspell/cspell-pipe': 8.19.4 + '@cspell/cspell-types': 8.19.4 + + cspell-io@8.19.4: + dependencies: + '@cspell/cspell-service-bus': 8.19.4 + '@cspell/url': 8.19.4 + + cspell-lib@8.19.4: + dependencies: + '@cspell/cspell-bundled-dicts': 8.19.4 + '@cspell/cspell-pipe': 8.19.4 + '@cspell/cspell-resolver': 8.19.4 + '@cspell/cspell-types': 8.19.4 + '@cspell/dynamic-import': 8.19.4 + '@cspell/filetypes': 8.19.4 + '@cspell/strong-weak-map': 8.19.4 + '@cspell/url': 8.19.4 + clear-module: 4.1.2 + comment-json: 4.5.0 + cspell-config-lib: 8.19.4 + cspell-dictionary: 8.19.4 + cspell-glob: 8.19.4 + cspell-grammar: 8.19.4 + cspell-io: 8.19.4 + cspell-trie-lib: 8.19.4 + env-paths: 3.0.0 + fast-equals: 5.4.0 + gensequence: 7.0.0 + import-fresh: 3.3.1 + resolve-from: 5.0.0 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + xdg-basedir: 5.1.0 + + cspell-trie-lib@8.19.4: + dependencies: + '@cspell/cspell-pipe': 8.19.4 + '@cspell/cspell-types': 8.19.4 + gensequence: 7.0.0 + + cspell@8.19.4: + dependencies: + '@cspell/cspell-json-reporter': 8.19.4 + '@cspell/cspell-pipe': 8.19.4 + '@cspell/cspell-types': 8.19.4 + '@cspell/dynamic-import': 8.19.4 + '@cspell/url': 8.19.4 + chalk: 5.6.2 + chalk-template: 1.1.2 + commander: 13.1.0 + cspell-dictionary: 8.19.4 + cspell-gitignore: 8.19.4 + cspell-glob: 8.19.4 + cspell-io: 8.19.4 + cspell-lib: 8.19.4 + fast-json-stable-stringify: 2.1.0 + file-entry-cache: 9.1.0 + semver: 7.7.3 + tinyglobby: 0.2.15 + + css-blank-pseudo@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + css-declaration-sorter@7.3.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + css-functions-list@3.2.3: {} + + css-has-pseudo@7.0.3(postcss@8.5.6): + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + css-prefers-color-scheme@10.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + css-select@4.3.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssdb@8.5.2: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@7.0.10(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + css-declaration-sorter: 7.3.0(postcss@8.5.6) + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-calc: 10.1.1(postcss@8.5.6) + postcss-colormin: 7.0.5(postcss@8.5.6) + postcss-convert-values: 7.0.8(postcss@8.5.6) + postcss-discard-comments: 7.0.5(postcss@8.5.6) + postcss-discard-duplicates: 7.0.2(postcss@8.5.6) + postcss-discard-empty: 7.0.1(postcss@8.5.6) + postcss-discard-overridden: 7.0.1(postcss@8.5.6) + postcss-merge-longhand: 7.0.5(postcss@8.5.6) + postcss-merge-rules: 7.0.7(postcss@8.5.6) + postcss-minify-font-values: 7.0.1(postcss@8.5.6) + postcss-minify-gradients: 7.0.1(postcss@8.5.6) + postcss-minify-params: 7.0.5(postcss@8.5.6) + postcss-minify-selectors: 7.0.5(postcss@8.5.6) + postcss-normalize-charset: 7.0.1(postcss@8.5.6) + postcss-normalize-display-values: 7.0.1(postcss@8.5.6) + postcss-normalize-positions: 7.0.1(postcss@8.5.6) + postcss-normalize-repeat-style: 7.0.1(postcss@8.5.6) + postcss-normalize-string: 7.0.1(postcss@8.5.6) + postcss-normalize-timing-functions: 7.0.1(postcss@8.5.6) + postcss-normalize-unicode: 7.0.5(postcss@8.5.6) + postcss-normalize-url: 7.0.1(postcss@8.5.6) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.6) + postcss-ordered-values: 7.0.2(postcss@8.5.6) + postcss-reduce-initial: 7.0.5(postcss@8.5.6) + postcss-reduce-transforms: 7.0.1(postcss@8.5.6) + postcss-svgo: 7.1.0(postcss@8.5.6) + postcss-unique-selectors: 7.0.4(postcss@8.5.6) + + cssnano-utils@5.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + cssnano@7.1.2(postcss@8.5.6): + dependencies: + cssnano-preset-default: 7.0.10(postcss@8.5.6) + lilconfig: 3.1.3 + postcss: 8.5.6 + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + csstype@3.2.3: {} + + cz-git@1.12.0: {} + + czg@1.12.0: {} + + dargs@8.1.0: {} + + data-uri-to-buffer@4.0.1: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + dataloader@1.4.0: {} + + dayjs@1.11.19: {} + + db0@0.3.4: {} + + de-indent@1.0.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + deep-eql@5.0.2: {} + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.4.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-lazy-prop@2.0.0: {} + + define-lazy-prop@3.0.0: {} + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + delegate@3.2.0: {} + + denque@2.1.0: {} + + depcheck@1.4.7: + dependencies: + '@babel/parser': 7.28.5 + '@babel/traverse': 7.28.5 + '@vue/compiler-sfc': 3.5.26 + callsite: 1.0.0 + camelcase: 6.3.0 + cosmiconfig: 7.1.0 + debug: 4.4.3 + deps-regex: 0.2.0 + findup-sync: 5.0.0 + ignore: 5.3.2 + is-core-module: 2.16.1 + js-yaml: 3.14.2 + json5: 2.2.3 + lodash: 4.17.21 + minimatch: 7.4.6 + multimatch: 5.0.0 + please-upgrade-node: 3.2.0 + readdirp: 3.6.0 + require-package-name: 2.0.1 + resolve: 1.22.11 + resolve-from: 5.0.0 + semver: 7.7.3 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + + depd@2.0.0: {} + + deps-regex@0.2.0: {} + + destr@2.0.5: {} + + detect-file@1.0.0: {} + + detect-indent@6.1.0: {} + + detect-libc@1.0.3: {} + + detect-libc@2.1.2: {} + + didyoumean@1.2.2: {} + + diff-sequences@27.5.1: {} + + diff@8.0.2: {} + + dijkstrajs@1.0.3: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dlv@1.1.3: {} + + dom-align@1.12.4: {} + + dom-scroll-into-view@2.0.1: {} + + dom-serializer@1.4.1: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + dom-zindex@1.0.6: {} + + domelementtype@2.3.0: {} + + domhandler@4.3.1: + dependencies: + domelementtype: 2.3.0 + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@2.8.0: + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dot-prop@10.1.0: + dependencies: + type-fest: 5.3.1 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dot-prop@9.0.0: + dependencies: + type-fest: 4.41.0 + + dotenv-expand@8.0.3: {} + + dotenv@16.0.3: {} + + dotenv@16.6.1: {} + + dotenv@17.2.3: {} + + dotenv@8.6.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.2: {} + + eastasianwidth@0.2.0: {} + + echarts@6.0.0: + dependencies: + tslib: 2.3.0 + zrender: 6.0.0 + + editorconfig@1.0.4: + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.7.3 + + ee-first@1.1.1: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-to-chromium@1.5.267: {} + + emoji-regex@10.6.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + enhanced-resolve@5.18.4: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + entities@2.2.0: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + entities@7.0.0: {} + + env-paths@2.2.1: {} + + env-paths@3.0.0: {} + + environment@1.1.0: {} + + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser-es@1.0.5: {} + + errx@0.1.0: + optional: true + + es-abstract@1.24.1: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + es-toolkit@1.43.0: {} + + esbuild@0.25.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.3 + '@esbuild/android-arm': 0.25.3 + '@esbuild/android-arm64': 0.25.3 + '@esbuild/android-x64': 0.25.3 + '@esbuild/darwin-arm64': 0.25.3 + '@esbuild/darwin-x64': 0.25.3 + '@esbuild/freebsd-arm64': 0.25.3 + '@esbuild/freebsd-x64': 0.25.3 + '@esbuild/linux-arm': 0.25.3 + '@esbuild/linux-arm64': 0.25.3 + '@esbuild/linux-ia32': 0.25.3 + '@esbuild/linux-loong64': 0.25.3 + '@esbuild/linux-mips64el': 0.25.3 + '@esbuild/linux-ppc64': 0.25.3 + '@esbuild/linux-riscv64': 0.25.3 + '@esbuild/linux-s390x': 0.25.3 + '@esbuild/linux-x64': 0.25.3 + '@esbuild/netbsd-arm64': 0.25.3 + '@esbuild/netbsd-x64': 0.25.3 + '@esbuild/openbsd-arm64': 0.25.3 + '@esbuild/openbsd-x64': 0.25.3 + '@esbuild/sunos-x64': 0.25.3 + '@esbuild/win32-arm64': 0.25.3 + '@esbuild/win32-ia32': 0.25.3 + '@esbuild/win32-x64': 0.25.3 + + escalade@3.2.0: {} + + escape-goat@4.0.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + + eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + semver: 7.7.3 + + eslint-compat-utils@0.6.5(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + semver: 7.7.3 + + eslint-config-turbo@2.7.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.2): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-turbo: 2.7.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.2) + turbo: 2.7.2 + + eslint-import-context@0.1.9(unrs-resolver@1.11.1): + dependencies: + get-tsconfig: 4.13.0 + stable-hash-x: 0.2.0 + optionalDependencies: + unrs-resolver: 1.11.1 + + eslint-json-compat-utils@0.2.1(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + esquery: 1.6.0 + jsonc-eslint-parser: 2.4.2 + + eslint-plugin-command@3.4.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@es-joy/jsdoccomment': 0.78.0 + eslint: 9.39.2(jiti@2.6.1) + + eslint-plugin-es-x@7.8.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + eslint: 9.39.2(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) + + eslint-plugin-eslint-comments@3.2.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + escape-string-regexp: 1.0.5 + eslint: 9.39.2(jiti@2.6.1) + ignore: 5.3.2 + + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@typescript-eslint/types': 8.50.1 + comment-parser: 1.4.1 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + eslint-import-context: 0.1.9(unrs-resolver@1.11.1) + is-glob: 4.0.3 + minimatch: 10.1.1 + semver: 7.7.3 + stable-hash-x: 0.2.0 + unrs-resolver: 1.11.1 + optionalDependencies: + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-jsdoc@61.5.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@es-joy/jsdoccomment': 0.76.0 + '@es-joy/resolve.exports': 1.2.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint: 9.39.2(jiti@2.6.1) + espree: 10.4.0 + esquery: 1.6.0 + html-entities: 2.6.0 + object-deep-merge: 2.0.0 + parse-imports-exports: 0.2.4 + semver: 7.7.3 + spdx-expression-parse: 4.0.0 + to-valid-identifier: 1.0.0 + transitivePeerDependencies: + - supports-color + + eslint-plugin-jsonc@2.21.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + diff-sequences: 27.5.1 + eslint: 9.39.2(jiti@2.6.1) + eslint-compat-utils: 0.6.5(eslint@9.39.2(jiti@2.6.1)) + eslint-json-compat-utils: 0.2.1(eslint@9.39.2(jiti@2.6.1))(jsonc-eslint-parser@2.4.2) + espree: 10.4.0 + graphemer: 1.4.0 + jsonc-eslint-parser: 2.4.2 + natural-compare: 1.4.0 + synckit: 0.11.11 + transitivePeerDependencies: + - '@eslint/json' + + eslint-plugin-n@17.23.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + enhanced-resolve: 5.18.4 + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-es-x: 7.8.0(eslint@9.39.2(jiti@2.6.1)) + get-tsconfig: 4.13.0 + globals: 15.15.0 + globrex: 0.1.2 + ignore: 5.3.2 + semver: 7.7.3 + ts-declaration-location: 1.0.7(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + eslint-plugin-no-only-tests@3.3.0: {} + + eslint-plugin-perfectionist@4.15.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/types': 8.50.1 + '@typescript-eslint/utils': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + natural-orderby: 5.0.0 + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint@9.39.2(jiti@2.6.1))(prettier@3.7.4): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + prettier: 3.7.4 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + '@types/eslint': 9.6.1 + + eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + comment-parser: 1.4.1 + eslint: 9.39.2(jiti@2.6.1) + jsdoc-type-pratt-parser: 4.8.0 + refa: 0.12.1 + regexp-ast-analysis: 0.7.1 + scslre: 0.3.0 + + eslint-plugin-turbo@2.7.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.2): + dependencies: + dotenv: 16.0.3 + eslint: 9.39.2(jiti@2.6.1) + turbo: 2.7.2 + + eslint-plugin-unicorn@62.0.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint/plugin-kit': 0.4.1 + change-case: 5.4.4 + ci-info: 4.3.1 + clean-regexp: 1.0.0 + core-js-compat: 3.47.0 + eslint: 9.39.2(jiti@2.6.1) + esquery: 1.6.0 + find-up-simple: 1.0.1 + globals: 16.5.0 + indent-string: 5.0.0 + is-builtin-module: 5.0.0 + jsesc: 3.1.0 + pluralize: 8.0.0 + regexp-tree: 0.1.27 + regjsparser: 0.13.0 + semver: 7.7.3 + strip-indent: 4.1.1 + + eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + + eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)(vitest@3.2.4(@types/node@25.0.3)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + '@typescript-eslint/utils': 7.18.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.50.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + vitest: 3.2.4(@types/node@25.0.3)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + - typescript + + eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1))): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + eslint: 9.39.2(jiti@2.6.1) + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 7.1.1 + semver: 7.7.3 + vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + xml-name-validator: 4.0.0 + optionalDependencies: + '@typescript-eslint/parser': 8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.2 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + espree@9.6.1: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 3.4.3 + + esprima@4.0.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@1.0.1: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + eventemitter3@5.0.1: {} + + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + + events@3.3.0: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 + + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + + expect-type@1.3.0: {} + + exsolve@1.0.8: {} + + extendable-error@0.1.7: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-equals@5.4.0: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-string-compare@3.0.0: {} + + fast-uri@3.1.0: {} + + fastest-levenshtein@1.0.16: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + + file-entry-cache@11.1.1: + dependencies: + flat-cache: 6.1.19 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-entry-cache@9.1.0: + dependencies: + flat-cache: 5.0.0 + + file-type@19.6.0: + dependencies: + get-stream: 9.0.1 + strtok3: 9.1.1 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + + file-uri-to-path@1.0.0: {} + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up-simple@1.0.1: {} + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@7.0.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 + + findup-sync@5.0.0: + dependencies: + detect-file: 1.0.0 + is-glob: 4.0.3 + micromatch: 4.0.8 + resolve-dir: 1.0.1 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.0 + rollup: 4.54.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flat-cache@5.0.0: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flat-cache@6.1.19: + dependencies: + cacheable: 2.3.1 + flatted: 3.3.3 + hookified: 1.14.0 + + flatted@3.3.3: {} + + focus-trap@7.7.0: + dependencies: + tabbable: 6.3.0 + optional: true + + follow-redirects@1.15.11: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formdata-node@6.0.3: {} + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + fraction.js@5.3.4: {} + + framesync@6.1.2: + dependencies: + tslib: 2.4.0 + + fresh@2.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-minipass@3.0.3: + dependencies: + minipass: 7.1.2 + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensequence@7.0.0: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.4.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-own-enumerable-property-symbols@3.0.2: {} + + get-port-please@3.2.0: {} + + get-port@7.1.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@8.0.1: {} + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.7 + nypm: 0.6.2 + pathe: 2.0.3 + + git-raw-commits@4.0.0: + dependencies: + dargs: 8.1.0 + meow: 12.1.1 + split2: 4.2.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@11.1.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.1.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.1 + + glob@13.0.0: + dependencies: + minimatch: 10.1.1 + minipass: 7.1.2 + path-scurry: 2.0.1 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + global-modules@1.0.0: + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + + global-prefix@1.0.2: + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + + globals@14.0.0: {} + + globals@15.15.0: {} + + globals@16.5.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globby@15.0.0: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + + globjoin@0.1.4: {} + + globrex@0.1.2: {} + + good-listener@1.2.2: + dependencies: + delegate: 3.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.10: {} + + graceful-fs@4.2.11: {} + + graph-cycles@3.0.0: + dependencies: + fast-string-compare: 3.0.0 + rotated-array-set: 3.0.0 + short-tree: 3.0.0 + + graphemer@1.4.0: {} + + gzip-size@7.0.0: + dependencies: + duplexer: 0.1.2 + + h3@1.15.4: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.1 + uncrypto: 0.1.3 + + happy-dom@17.6.3: + dependencies: + webidl-conversions: 7.0.0 + whatwg-mimetype: 3.0.0 + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hashery@1.3.0: + dependencies: + hookified: 1.14.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hey-listen@1.0.8: {} + + highlight.js@11.11.1: {} + + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + + hookable@5.5.3: {} + + hookified@1.14.0: {} + + html-entities@2.6.0: {} + + html-minifier-terser@6.1.0: + dependencies: + camel-case: 4.1.2 + clean-css: 5.3.3 + commander: 8.3.0 + he: 1.2.0 + param-case: 3.0.4 + relateurl: 0.2.7 + terser: 5.44.1 + + html-minifier-terser@7.2.0: + dependencies: + camel-case: 4.1.2 + clean-css: 5.3.3 + commander: 10.0.1 + entities: 4.5.0 + param-case: 3.0.4 + relateurl: 0.2.7 + terser: 5.44.1 + + html-tags@3.3.1: {} + + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-shutdown@1.2.2: {} + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + httpxy@0.1.7: {} + + human-id@4.1.3: {} + + human-signals@5.0.0: {} + + human-signals@8.0.1: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.1: + dependencies: + safer-buffer: 2.1.2 + + idb@7.1.1: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + image-size@0.5.5: + optional: true + + immutable@5.1.4: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-lazy@4.0.0: {} + + import-meta-resolve@4.2.0: {} + + imurmurhash@0.1.4: {} + + indent-string@5.0.0: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + ini@4.1.1: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + ioredis@5.8.2: + dependencies: + '@ioredis/commands': 1.4.0 + cluster-key-slot: 1.1.2 + debug: 4.4.3 + denque: 2.1.0 + lodash.defaults: 4.2.0 + lodash.isarguments: 3.1.0 + redis-errors: 1.2.0 + redis-parser: 3.0.0 + standard-as-callback: 2.1.0 + transitivePeerDependencies: + - supports-color + + iron-webcrypto@1.2.1: {} + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-buffer@2.0.5: {} + + is-builtin-module@5.0.0: + dependencies: + builtin-modules: 5.0.0 + + is-callable@1.2.7: {} + + is-ci@4.1.0: + dependencies: + ci-info: 4.3.1 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-docker@2.2.1: {} + + is-docker@3.0.0: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.4.0 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-in-ci@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-installed-globally@1.0.0: + dependencies: + global-directory: 4.0.1 + is-path-inside: 4.0.0 + + is-interactive@2.0.0: {} + + is-map@2.0.3: {} + + is-module@1.0.0: {} + + is-negative-zero@2.0.3: {} + + is-npm@6.1.0: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-obj@1.0.1: {} + + is-obj@2.0.0: {} + + is-path-inside@4.0.0: {} + + is-plain-obj@4.1.0: {} + + is-plain-object@3.0.1: {} + + is-plain-object@5.0.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.8 + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-regexp@1.0.0: {} + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-stream@4.0.1: {} + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-text-path@2.0.0: + dependencies: + text-extensions: 2.4.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-what@3.14.1: + optional: true + + is-what@5.5.0: {} + + is-windows@1.0.2: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + + is64bit@2.0.0: + dependencies: + system-architecture: 0.1.0 + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.4 + picocolors: 1.1.1 + + jiti@2.6.1: {} + + jju@1.4.0: {} + + js-beautify@1.15.4: + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.5.0 + js-cookie: 3.0.5 + nopt: 7.2.1 + + js-cookie@3.0.5: {} + + js-md5@0.8.3: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsdoc-type-pratt-parser@4.8.0: {} + + jsdoc-type-pratt-parser@6.10.0: {} + + jsdoc-type-pratt-parser@7.0.0: {} + + jsesc@3.1.0: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema@0.4.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonc-eslint-parser@2.4.2: + dependencies: + acorn: 8.15.0 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + semver: 7.7.3 + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonparse@1.3.1: {} + + jsonpointer@5.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + keyv@5.5.5: + dependencies: + '@keyv/serialize': 1.1.1 + + kind-of@6.0.3: {} + + kleur@4.1.5: {} + + klona@2.0.6: {} + + knitwork@1.3.0: {} + + known-css-properties@0.37.0: {} + + kolorist@1.8.0: {} + + ky@1.14.1: {} + + latest-version@9.0.0: + dependencies: + package-json: 10.0.1 + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + lefthook-darwin-arm64@1.13.6: + optional: true + + lefthook-darwin-x64@1.13.6: + optional: true + + lefthook-freebsd-arm64@1.13.6: + optional: true + + lefthook-freebsd-x64@1.13.6: + optional: true + + lefthook-linux-arm64@1.13.6: + optional: true + + lefthook-linux-x64@1.13.6: + optional: true + + lefthook-openbsd-arm64@1.13.6: + optional: true + + lefthook-openbsd-x64@1.13.6: + optional: true + + lefthook-windows-arm64@1.13.6: + optional: true + + lefthook-windows-x64@1.13.6: + optional: true + + lefthook@1.13.6: + optionalDependencies: + lefthook-darwin-arm64: 1.13.6 + lefthook-darwin-x64: 1.13.6 + lefthook-freebsd-arm64: 1.13.6 + lefthook-freebsd-x64: 1.13.6 + lefthook-linux-arm64: 1.13.6 + lefthook-linux-x64: 1.13.6 + lefthook-openbsd-arm64: 1.13.6 + lefthook-openbsd-x64: 1.13.6 + lefthook-windows-arm64: 1.13.6 + lefthook-windows-x64: 1.13.6 + + less@4.5.1: + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.8.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.3.1 + source-map: 0.6.1 + optional: true + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + listhen@1.9.0: + dependencies: + '@parcel/watcher': 2.5.1 + '@parcel/watcher-wasm': 2.5.1 + citty: 0.1.6 + clipboardy: 4.0.0 + consola: 3.4.2 + crossws: 0.3.5 + defu: 6.1.4 + get-port-please: 3.2.0 + h3: 1.15.4 + http-shutdown: 1.2.2 + jiti: 2.6.1 + mlly: 1.8.0 + node-forge: 1.3.3 + pathe: 1.1.2 + std-env: 3.10.0 + ufo: 1.6.1 + untun: 0.1.3 + uqr: 0.1.2 + + listr2@8.3.3: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.0 + pkg-types: 2.3.0 + quansync: 0.2.11 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + locko@1.1.0: {} + + lodash-es@4.17.22: {} + + lodash.camelcase@4.3.0: {} + + lodash.clonedeep@4.5.0: {} + + lodash.debounce@4.0.8: {} + + lodash.defaults@4.2.0: {} + + lodash.isarguments@3.1.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.kebabcase@4.1.1: {} + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.sortby@4.7.0: {} + + lodash.startcase@4.4.0: {} + + lodash.truncate@4.4.2: {} + + lodash.uniq@4.5.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.21: {} + + log-symbols@6.0.0: + dependencies: + chalk: 5.6.2 + is-unicode-supported: 1.3.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.2.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + loupe@3.2.1: {} + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lru-cache@10.4.3: {} + + lru-cache@11.2.4: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lucide-vue-next@0.553.0(vue@3.5.26(typescript@5.9.3)): + dependencies: + vue: 3.5.26(typescript@5.9.3) + + lz-string@1.5.0: {} + + magic-string@0.25.9: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.1: + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + source-map-js: 1.2.1 + + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + optional: true + + math-intrinsics@1.1.0: {} + + mathml-tag-names@2.1.3: {} + + mdn-data@2.0.28: {} + + mdn-data@2.12.2: {} + + mdn-data@2.25.0: {} + + meow@12.1.1: {} + + meow@13.2.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@1.6.0: + optional: true + + mime@3.0.0: {} + + mime@4.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@7.4.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.1: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass-collect@2.0.1: + dependencies: + minipass: 7.1.2 + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@7.1.2: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.2 + + mitt@3.0.1: {} + + mkdist@2.4.1(sass@1.97.1)(typescript@5.9.3)(vue-tsc@3.2.1(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3)): + dependencies: + autoprefixer: 10.4.23(postcss@8.5.6) + citty: 0.1.6 + cssnano: 7.1.2(postcss@8.5.6) + defu: 6.1.4 + esbuild: 0.25.3 + jiti: 2.6.1 + mlly: 1.8.0 + pathe: 2.0.3 + pkg-types: 2.3.0 + postcss: 8.5.6 + postcss-nested: 7.0.2(postcss@8.5.6) + semver: 7.7.3 + tinyglobby: 0.2.15 + optionalDependencies: + sass: 1.97.1 + typescript: 5.9.3 + vue: 3.5.26(typescript@5.9.3) + vue-tsc: 3.2.1(typescript@5.9.3) + + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + mri@1.2.0: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + multimatch@5.0.0: + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 3.0.0 + array-union: 2.1.0 + arrify: 2.0.1 + minimatch: 3.1.2 + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + nanoid@5.1.6: {} + + nanopop@2.4.2: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + natural-orderby@5.0.0: {} + + needle@3.3.1: + dependencies: + iconv-lite: 0.6.3 + sax: 1.4.3 + optional: true + + nitropack@2.12.9: + dependencies: + '@cloudflare/kv-asset-handler': 0.4.1 + '@rollup/plugin-alias': 5.1.1(rollup@4.54.0) + '@rollup/plugin-commonjs': 28.0.9(rollup@4.54.0) + '@rollup/plugin-inject': 5.0.5(rollup@4.54.0) + '@rollup/plugin-json': 6.1.0(rollup@4.54.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.54.0) + '@rollup/plugin-replace': 6.0.3(rollup@4.54.0) + '@rollup/plugin-terser': 0.4.4(rollup@4.54.0) + '@vercel/nft': 0.30.4(rollup@4.54.0) + archiver: 7.0.1 + c12: 3.3.3(magicast@0.5.1) + chokidar: 4.0.3 + citty: 0.1.6 + compatx: 0.2.0 + confbox: 0.2.2 + consola: 3.4.2 + cookie-es: 2.0.0 + croner: 9.1.0 + crossws: 0.3.5 + db0: 0.3.4 + defu: 6.1.4 + destr: 2.0.5 + dot-prop: 10.1.0 + esbuild: 0.25.3 + escape-string-regexp: 5.0.0 + etag: 1.8.1 + exsolve: 1.0.8 + globby: 15.0.0 + gzip-size: 7.0.0 + h3: 1.15.4 + hookable: 5.5.3 + httpxy: 0.1.7 + ioredis: 5.8.2 + jiti: 2.6.1 + klona: 2.0.6 + knitwork: 1.3.0 + listhen: 1.9.0 + magic-string: 0.30.21 + magicast: 0.5.1 + mime: 4.1.0 + mlly: 1.8.0 + node-fetch-native: 1.6.7 + node-mock-http: 1.0.4 + ofetch: 1.5.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.0.0 + pkg-types: 2.3.0 + pretty-bytes: 7.1.0 + radix3: 1.1.2 + rollup: 4.54.0 + rollup-plugin-visualizer: 6.0.5(rollup@4.54.0) + scule: 1.3.0 + semver: 7.7.3 + serve-placeholder: 2.0.2 + serve-static: 2.2.1 + source-map: 0.7.6 + std-env: 3.10.0 + ufo: 1.6.1 + ultrahtml: 1.6.0 + uncrypto: 0.1.3 + unctx: 2.5.0 + unenv: 2.0.0-rc.24 + unimport: 5.6.0 + unplugin-utils: 0.3.1 + unstorage: 1.17.3(db0@0.3.4)(ioredis@5.8.2) + untyped: 2.0.0 + unwasm: 0.3.11 + youch: 4.1.0-beta.13 + youch-core: 0.3.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@electric-sql/pglite' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bare-abort-controller + - better-sqlite3 + - drizzle-orm + - encoding + - idb-keyval + - mysql2 + - react-native-b4a + - rolldown + - sqlite3 + - supports-color + - uploadthing + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-addon-api@7.1.1: {} + + node-cleanup@2.1.2: {} + + node-domexception@1.0.0: {} + + node-fetch-cache@5.1.0: + dependencies: + cacache: 20.0.3 + formdata-node: 6.0.3 + locko: 1.1.0 + node-fetch: 3.3.2 + + node-fetch-native@1.6.7: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-forge@1.3.3: {} + + node-gyp-build@4.8.4: {} + + node-html-parser@5.4.2: + dependencies: + css-select: 4.3.0 + he: 1.2.0 + + node-mock-http@1.0.4: {} + + node-releases@2.0.27: {} + + nopt@7.2.1: + dependencies: + abbrev: 2.0.0 + + nopt@8.1.0: + dependencies: + abbrev: 3.0.1 + + normalize-path@3.0.0: {} + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + + nprogress@0.2.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nypm@0.6.2: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 2.3.0 + tinyexec: 1.0.2 + + object-assign@4.1.1: {} + + object-deep-merge@2.0.0: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.1 + + ohash@2.0.11: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@10.2.0: + dependencies: + default-browser: 5.4.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@8.2.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + outdent@0.5.0: {} + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + p-map@2.1.0: {} + + p-map@7.0.4: {} + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + package-json@10.0.1: + dependencies: + ky: 1.14.1 + registry-auth-token: 5.1.0 + registry-url: 6.0.1 + semver: 7.7.3 + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + + package-manager-detector@1.6.0: {} + + pako@2.1.0: {} + + param-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parent-module@2.0.0: + dependencies: + callsites: 3.1.0 + + parse-imports-exports@0.2.4: + dependencies: + parse-statements: 1.0.11 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-ms@4.0.0: {} + + parse-node-version@1.0.1: + optional: true + + parse-passwd@1.0.0: {} + + parse-statements@1.0.11: {} + + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + parseurl@1.3.3: {} + + pascal-case@3.1.2: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.1: + dependencies: + lru-cache: 11.2.4 + minipass: 7.1.2 + + path-type@4.0.0: {} + + path-type@6.0.0: {} + + pathe@0.2.0: {} + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + peek-readable@5.4.2: {} + + perfect-debounce@1.0.0: {} + + perfect-debounce@2.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@2.3.0: {} + + pify@4.0.1: {} + + pinia-plugin-persistedstate@4.7.1(@nuxt/kit@4.2.2(magicast@0.5.1))(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3))): + dependencies: + defu: 6.1.4 + optionalDependencies: + '@nuxt/kit': 4.2.2(magicast@0.5.1) + pinia: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) + + pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 7.7.9 + vue: 3.5.26(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + pirates@4.0.7: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.8 + pathe: 2.0.3 + + playwright-core@1.57.0: {} + + playwright@1.57.0: + dependencies: + playwright-core: 1.57.0 + optionalDependencies: + fsevents: 2.3.2 + + please-upgrade-node@3.2.0: + dependencies: + semver-compare: 1.0.0 + + pluralize@8.0.0: {} + + pngjs@5.0.0: {} + + popmotion@11.0.5: + dependencies: + framesync: 6.1.2 + hey-listen: 1.0.8 + style-value-types: 5.1.2 + tslib: 2.4.0 + + possible-typed-array-names@1.1.0: {} + + postcss-antd-fixes@0.2.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-attribute-case-insensitive@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-calc@10.1.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + postcss-clamp@4.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-color-functional-notation@7.0.12(postcss@8.5.6): + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + postcss-color-hex-alpha@10.0.0(postcss@8.5.6): + dependencies: + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-color-rebeccapurple@10.0.0(postcss@8.5.6): + dependencies: + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-colormin@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-convert-values@7.0.8(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-custom-media@11.0.6(postcss@8.5.6): + dependencies: + '@csstools/cascade-layer-name-parser': 2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + postcss: 8.5.6 + + postcss-custom-properties@14.0.6(postcss@8.5.6): + dependencies: + '@csstools/cascade-layer-name-parser': 2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-custom-selectors@8.0.5(postcss@8.5.6): + dependencies: + '@csstools/cascade-layer-name-parser': 2.0.5(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-dir-pseudo-class@9.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-discard-comments@7.0.5(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-discard-duplicates@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-empty@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-overridden@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-double-position-gradients@6.0.4(postcss@8.5.6): + dependencies: + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-focus-visible@10.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-focus-within@9.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-font-variant@5.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-gap-properties@6.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-html@1.8.0: + dependencies: + htmlparser2: 8.0.2 + js-tokens: 9.0.1 + postcss: 8.5.6 + postcss-safe-parser: 6.0.0(postcss@8.5.6) + + postcss-image-set-function@7.0.0(postcss@8.5.6): + dependencies: + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-import@15.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-import@16.1.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.6): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.6 + + postcss-lab-function@7.0.12(postcss@8.5.6): + dependencies: + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/utilities': 2.0.0(postcss@8.5.6) + postcss: 8.5.6 + + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(yaml@2.8.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.6.1 + postcss: 8.5.6 + yaml: 2.8.2 + + postcss-logical@8.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-media-query-parser@0.2.3: {} + + postcss-merge-longhand@7.0.5(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + stylehacks: 7.0.7(postcss@8.5.6) + + postcss-merge-rules@7.0.7(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-minify-font-values@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-minify-gradients@7.0.1(postcss@8.5.6): + dependencies: + colord: 2.9.3 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-minify-params@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-minify-selectors@7.0.5(postcss@8.5.6): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-nested@5.0.6(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + + postcss-nested@6.2.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + + postcss-nested@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-nesting@13.0.2(postcss@8.5.6): + dependencies: + '@csstools/selector-resolve-nested': 3.1.0(postcss-selector-parser@7.1.1) + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-normalize-charset@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-normalize-display-values@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-positions@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-repeat-style@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-string@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-unicode@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-url@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-normalize-whitespace@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-opacity-percentage@3.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-ordered-values@7.0.2(postcss@8.5.6): + dependencies: + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-overflow-shorthand@6.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-page-break@3.0.4(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-place@10.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-preset-env@10.5.0(postcss@8.5.6): + dependencies: + '@csstools/postcss-alpha-function': 1.0.1(postcss@8.5.6) + '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.6) + '@csstools/postcss-color-function': 4.0.12(postcss@8.5.6) + '@csstools/postcss-color-function-display-p3-linear': 1.0.1(postcss@8.5.6) + '@csstools/postcss-color-mix-function': 3.0.12(postcss@8.5.6) + '@csstools/postcss-color-mix-variadic-function-arguments': 1.0.2(postcss@8.5.6) + '@csstools/postcss-content-alt-text': 2.0.8(postcss@8.5.6) + '@csstools/postcss-contrast-color-function': 2.0.12(postcss@8.5.6) + '@csstools/postcss-exponential-functions': 2.0.9(postcss@8.5.6) + '@csstools/postcss-font-format-keywords': 4.0.0(postcss@8.5.6) + '@csstools/postcss-gamut-mapping': 2.0.11(postcss@8.5.6) + '@csstools/postcss-gradients-interpolation-method': 5.0.12(postcss@8.5.6) + '@csstools/postcss-hwb-function': 4.0.12(postcss@8.5.6) + '@csstools/postcss-ic-unit': 4.0.4(postcss@8.5.6) + '@csstools/postcss-initial': 2.0.1(postcss@8.5.6) + '@csstools/postcss-is-pseudo-class': 5.0.3(postcss@8.5.6) + '@csstools/postcss-light-dark-function': 2.0.11(postcss@8.5.6) + '@csstools/postcss-logical-float-and-clear': 3.0.0(postcss@8.5.6) + '@csstools/postcss-logical-overflow': 2.0.0(postcss@8.5.6) + '@csstools/postcss-logical-overscroll-behavior': 2.0.0(postcss@8.5.6) + '@csstools/postcss-logical-resize': 3.0.0(postcss@8.5.6) + '@csstools/postcss-logical-viewport-units': 3.0.4(postcss@8.5.6) + '@csstools/postcss-media-minmax': 2.0.9(postcss@8.5.6) + '@csstools/postcss-media-queries-aspect-ratio-number-values': 3.0.5(postcss@8.5.6) + '@csstools/postcss-nested-calc': 4.0.0(postcss@8.5.6) + '@csstools/postcss-normalize-display-values': 4.0.0(postcss@8.5.6) + '@csstools/postcss-oklab-function': 4.0.12(postcss@8.5.6) + '@csstools/postcss-position-area-property': 1.0.0(postcss@8.5.6) + '@csstools/postcss-progressive-custom-properties': 4.2.1(postcss@8.5.6) + '@csstools/postcss-random-function': 2.0.1(postcss@8.5.6) + '@csstools/postcss-relative-color-syntax': 3.0.12(postcss@8.5.6) + '@csstools/postcss-scope-pseudo-class': 4.0.1(postcss@8.5.6) + '@csstools/postcss-sign-functions': 1.1.4(postcss@8.5.6) + '@csstools/postcss-stepped-value-functions': 4.0.9(postcss@8.5.6) + '@csstools/postcss-system-ui-font-family': 1.0.0(postcss@8.5.6) + '@csstools/postcss-text-decoration-shorthand': 4.0.3(postcss@8.5.6) + '@csstools/postcss-trigonometric-functions': 4.0.9(postcss@8.5.6) + '@csstools/postcss-unset-value': 4.0.0(postcss@8.5.6) + autoprefixer: 10.4.23(postcss@8.5.6) + browserslist: 4.28.1 + css-blank-pseudo: 7.0.1(postcss@8.5.6) + css-has-pseudo: 7.0.3(postcss@8.5.6) + css-prefers-color-scheme: 10.0.0(postcss@8.5.6) + cssdb: 8.5.2 + postcss: 8.5.6 + postcss-attribute-case-insensitive: 7.0.1(postcss@8.5.6) + postcss-clamp: 4.1.0(postcss@8.5.6) + postcss-color-functional-notation: 7.0.12(postcss@8.5.6) + postcss-color-hex-alpha: 10.0.0(postcss@8.5.6) + postcss-color-rebeccapurple: 10.0.0(postcss@8.5.6) + postcss-custom-media: 11.0.6(postcss@8.5.6) + postcss-custom-properties: 14.0.6(postcss@8.5.6) + postcss-custom-selectors: 8.0.5(postcss@8.5.6) + postcss-dir-pseudo-class: 9.0.1(postcss@8.5.6) + postcss-double-position-gradients: 6.0.4(postcss@8.5.6) + postcss-focus-visible: 10.0.1(postcss@8.5.6) + postcss-focus-within: 9.0.1(postcss@8.5.6) + postcss-font-variant: 5.0.0(postcss@8.5.6) + postcss-gap-properties: 6.0.0(postcss@8.5.6) + postcss-image-set-function: 7.0.0(postcss@8.5.6) + postcss-lab-function: 7.0.12(postcss@8.5.6) + postcss-logical: 8.1.0(postcss@8.5.6) + postcss-nesting: 13.0.2(postcss@8.5.6) + postcss-opacity-percentage: 3.0.0(postcss@8.5.6) + postcss-overflow-shorthand: 6.0.0(postcss@8.5.6) + postcss-page-break: 3.0.4(postcss@8.5.6) + postcss-place: 10.0.0(postcss@8.5.6) + postcss-pseudo-class-any-link: 10.0.1(postcss@8.5.6) + postcss-replace-overflow-wrap: 4.0.0(postcss@8.5.6) + postcss-selector-not: 8.0.1(postcss@8.5.6) + + postcss-pseudo-class-any-link@10.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-reduce-initial@7.0.5(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + postcss: 8.5.6 + + postcss-reduce-transforms@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-replace-overflow-wrap@4.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-resolve-nested-selector@0.1.6: {} + + postcss-safe-parser@6.0.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-safe-parser@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-scss@4.0.9(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-selector-not@8.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-selector-parser@6.0.10: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-sorting@8.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-sorting@9.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-svgo@7.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + svgo: 4.0.0 + + postcss-unique-selectors@7.0.4(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier-plugin-tailwindcss@0.7.2(prettier@3.7.4): + dependencies: + prettier: 3.7.4 + + prettier@2.8.8: {} + + prettier@3.7.4: {} + + pretty-bytes@5.6.0: {} + + pretty-bytes@6.1.1: {} + + pretty-bytes@7.1.0: {} + + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + + proto-list@1.2.4: {} + + proxy-from-env@1.1.0: {} + + prr@1.0.1: + optional: true + + publint@0.3.16: + dependencies: + '@publint/pack': 0.1.2 + package-manager-detector: 1.6.0 + picocolors: 1.1.1 + sade: 1.8.1 + + punycode@2.3.1: {} + + pupa@3.3.0: + dependencies: + escape-goat: 4.0.0 + + qified@0.5.3: + dependencies: + hookified: 1.14.0 + + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + radix3@1.1.2: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + range-parser@1.2.1: {} + + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.2 + pify: 4.0.1 + strip-bom: 3.0.0 + + read-yaml-file@2.1.0: + dependencies: + js-yaml: 4.1.1 + strip-bom: 4.0.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.1.2: {} + + readdirp@5.0.0: {} + + redis-errors@1.2.0: {} + + redis-parser@3.0.0: + dependencies: + redis-errors: 1.2.0 + + refa@0.12.1: + dependencies: + '@eslint-community/regexpp': 4.12.2 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regexp-ast-analysis@0.7.1: + dependencies: + '@eslint-community/regexpp': 4.12.2 + refa: 0.12.1 + + regexp-tree@0.1.27: {} + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + registry-auth-token@5.1.0: + dependencies: + '@pnpm/npm-conf': 2.3.1 + + registry-url@6.0.1: + dependencies: + rc: 1.2.8 + + regjsgen@0.8.0: {} + + regjsparser@0.13.0: + dependencies: + jsesc: 3.1.0 + + reka-ui@2.7.0(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@floating-ui/dom': 1.7.4 + '@floating-ui/vue': 1.1.9(vue@3.5.26(typescript@5.9.3)) + '@internationalized/date': 3.10.1 + '@internationalized/number': 3.6.5 + '@tanstack/vue-virtual': 3.13.13(vue@3.5.26(typescript@5.9.3)) + '@vueuse/core': 12.8.2(typescript@5.9.3) + '@vueuse/shared': 12.8.2(typescript@5.9.3) + aria-hidden: 1.2.6 + defu: 6.1.4 + ohash: 2.0.11 + vue: 3.5.26(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + - typescript + + relateurl@0.2.7: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + require-main-filename@2.0.0: {} + + require-package-name@2.0.1: {} + + reserved-identifiers@1.2.0: {} + + resize-observer-polyfill@1.5.1: {} + + resolve-dir@1.0.1: + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve.exports@2.0.3: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rimraf@6.1.2: + dependencies: + glob: 13.0.0 + package-json-from-dist: 1.0.1 + + rollup-plugin-dts@6.3.0(rollup@4.54.0)(typescript@5.9.3): + dependencies: + magic-string: 0.30.21 + rollup: 4.54.0 + typescript: 5.9.3 + optionalDependencies: + '@babel/code-frame': 7.27.1 + + rollup-plugin-visualizer@5.14.0(rollup@4.54.0): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.54.0 + + rollup-plugin-visualizer@6.0.5(rollup@4.54.0): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.54.0 + + rollup@2.79.2: + optionalDependencies: + fsevents: 2.3.3 + + rollup@4.54.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.54.0 + '@rollup/rollup-android-arm64': 4.54.0 + '@rollup/rollup-darwin-arm64': 4.54.0 + '@rollup/rollup-darwin-x64': 4.54.0 + '@rollup/rollup-freebsd-arm64': 4.54.0 + '@rollup/rollup-freebsd-x64': 4.54.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 + '@rollup/rollup-linux-arm-musleabihf': 4.54.0 + '@rollup/rollup-linux-arm64-gnu': 4.54.0 + '@rollup/rollup-linux-arm64-musl': 4.54.0 + '@rollup/rollup-linux-loong64-gnu': 4.54.0 + '@rollup/rollup-linux-ppc64-gnu': 4.54.0 + '@rollup/rollup-linux-riscv64-gnu': 4.54.0 + '@rollup/rollup-linux-riscv64-musl': 4.54.0 + '@rollup/rollup-linux-s390x-gnu': 4.54.0 + '@rollup/rollup-linux-x64-gnu': 4.54.0 + '@rollup/rollup-linux-x64-musl': 4.54.0 + '@rollup/rollup-openharmony-arm64': 4.54.0 + '@rollup/rollup-win32-arm64-msvc': 4.54.0 + '@rollup/rollup-win32-ia32-msvc': 4.54.0 + '@rollup/rollup-win32-x64-gnu': 4.54.0 + '@rollup/rollup-win32-x64-msvc': 4.54.0 + fsevents: 2.3.3 + + rotated-array-set@3.0.0: {} + + run-applescript@7.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + sass@1.97.1: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.4 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.1 + + sax@1.4.3: {} + + scroll-into-view-if-needed@2.2.31: + dependencies: + compute-scroll-into-view: 1.0.20 + + scslre@0.3.0: + dependencies: + '@eslint-community/regexpp': 4.12.2 + refa: 0.12.1 + regexp-ast-analysis: 0.7.1 + + scule@1.3.0: {} + + secure-ls@2.0.0: + dependencies: + crypto-js: 4.2.0 + lz-string: 1.5.0 + + select@1.1.2: {} + + semver-compare@1.0.0: {} + + semver@5.7.2: + optional: true + + semver@6.3.1: {} + + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + + semver@7.7.3: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + serve-placeholder@2.0.2: + dependencies: + defu: 6.1.4 + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + setprototypeof@1.2.0: {} + + shallow-equal@1.2.1: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + short-tree@3.0.0: + dependencies: + '@types/bintrees': 1.0.6 + bintrees: 1.0.2 + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + sirv@3.0.2: + dependencies: + '@polka/url': 1.0.0-next.29 + mrmime: 2.0.1 + totalist: 3.0.1 + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + slash@5.1.0: {} + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + smob@1.5.0: {} + + sortablejs@1.15.6: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + + sourcemap-codec@1.4.8: {} + + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.22 + + spdx-license-ids@3.0.22: {} + + speakingurl@14.0.1: {} + + split2@4.2.0: {} + + sprintf-js@1.0.3: {} + + ssri@13.0.0: + dependencies: + minipass: 7.1.2 + + stable-hash-x@0.2.0: {} + + stackback@0.0.2: {} + + standard-as-callback@2.1.0: {} + + statuses@2.0.2: {} + + std-env@3.10.0: {} + + stdin-discarder@0.2.2: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + streamx@2.23.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.3 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-object@3.3.0: + dependencies: + get-own-enumerable-property-symbols: 3.0.2 + is-obj: 1.0.1 + is-regexp: 1.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-comments@2.0.1: {} + + strip-final-newline@3.0.0: {} + + strip-final-newline@4.0.0: {} + + strip-indent@4.1.1: {} + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + strtok3@9.1.1: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.4.2 + + stubborn-fs@2.0.0: + dependencies: + stubborn-utils: 1.0.2 + + stubborn-utils@1.0.2: {} + + style-search@0.1.0: {} + + style-value-types@5.1.2: + dependencies: + hey-listen: 1.0.8 + tslib: 2.4.0 + + stylehacks@7.0.7(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + stylelint-config-html@1.1.0(postcss-html@1.8.0)(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + postcss-html: 1.8.0 + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-config-recess-order@6.1.0(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + stylelint: 16.26.1(typescript@5.9.3) + stylelint-order: 6.0.4(stylelint@16.26.1(typescript@5.9.3)) + + stylelint-config-recommended-scss@14.1.0(postcss@8.5.6)(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + postcss-scss: 4.0.9(postcss@8.5.6) + stylelint: 16.26.1(typescript@5.9.3) + stylelint-config-recommended: 14.0.1(stylelint@16.26.1(typescript@5.9.3)) + stylelint-scss: 6.13.0(stylelint@16.26.1(typescript@5.9.3)) + optionalDependencies: + postcss: 8.5.6 + + stylelint-config-recommended-vue@1.6.1(postcss-html@1.8.0)(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + postcss-html: 1.8.0 + semver: 7.7.3 + stylelint: 16.26.1(typescript@5.9.3) + stylelint-config-html: 1.1.0(postcss-html@1.8.0)(stylelint@16.26.1(typescript@5.9.3)) + stylelint-config-recommended: 17.0.0(stylelint@16.26.1(typescript@5.9.3)) + + stylelint-config-recommended@14.0.1(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-config-recommended@16.0.0(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-config-recommended@17.0.0(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-config-standard@38.0.0(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + stylelint: 16.26.1(typescript@5.9.3) + stylelint-config-recommended: 16.0.0(stylelint@16.26.1(typescript@5.9.3)) + + stylelint-order@6.0.4(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + postcss: 8.5.6 + postcss-sorting: 8.0.2(postcss@8.5.6) + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-order@7.0.0(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + postcss: 8.5.6 + postcss-sorting: 9.1.0(postcss@8.5.6) + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-prettier@5.0.3(prettier@3.7.4)(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + prettier: 3.7.4 + prettier-linter-helpers: 1.0.0 + stylelint: 16.26.1(typescript@5.9.3) + + stylelint-scss@6.13.0(stylelint@16.26.1(typescript@5.9.3)): + dependencies: + css-tree: 3.1.0 + is-plain-object: 5.0.0 + known-css-properties: 0.37.0 + mdn-data: 2.25.0 + postcss-media-query-parser: 0.2.3 + postcss-resolve-nested-selector: 0.1.6 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + stylelint: 16.26.1(typescript@5.9.3) + + stylelint@16.26.1(typescript@5.9.3): + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-syntax-patches-for-csstree': 1.0.22 + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + '@dual-bundle/import-meta-resolve': 4.2.1 + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 9.0.0(typescript@5.9.3) + css-functions-list: 3.2.3 + css-tree: 3.1.0 + debug: 4.4.3 + fast-glob: 3.3.3 + fastest-levenshtein: 1.0.16 + file-entry-cache: 11.1.1 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 7.0.5 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.37.0 + mathml-tag-names: 2.1.3 + meow: 13.2.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-resolve-nested-selector: 0.1.6 + postcss-safe-parser: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + supports-hyperlinks: 3.2.0 + svg-tags: 1.0.0 + table: 6.9.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + - typescript + + stylis@4.3.6: {} + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + + superjson@2.2.6: + dependencies: + copy-anything: 4.0.5 + + supports-color@10.2.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + sver@1.8.4: + optionalDependencies: + semver: 6.3.1 + + svg-tags@1.0.0: {} + + svgo@4.0.0: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.1.0 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.4.3 + + synckit@0.11.11: + dependencies: + '@pkgr/core': 0.2.9 + + system-architecture@0.1.0: {} + + tabbable@6.3.0: + optional: true + + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + tagged-tag@1.0.0: {} + + tailwind-merge@2.6.0: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(yaml@2.8.2)): + dependencies: + tailwindcss: 3.4.19(yaml@2.8.2) + + tailwindcss@3.4.19(yaml@2.8.2): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 2.6.1 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(yaml@2.8.2) + postcss-nested: 6.2.0(postcss@8.5.6) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + tapable@2.3.0: {} + + tar-stream@3.1.7: + dependencies: + b4a: 1.7.3 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + tar@7.5.2: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + + temp-dir@2.0.0: {} + + tempy@0.6.0: + dependencies: + is-stream: 2.0.1 + temp-dir: 2.0.0 + type-fest: 0.16.0 + unique-string: 2.0.0 + + term-size@2.2.1: {} + + terser@5.44.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + text-decoder@1.2.3: + dependencies: + b4a: 1.7.3 + transitivePeerDependencies: + - react-native-b4a + + text-extensions@2.4.0: {} + + theme-colors@0.1.0: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + throttle-debounce@5.0.2: {} + + through@2.3.8: {} + + tiny-emitter@2.1.0: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinymce@7.9.1: {} + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + tippy.js@6.3.7: + dependencies: + '@popperjs/core': 2.11.8 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + to-valid-identifier@1.0.0: + dependencies: + '@sindresorhus/base62': 1.0.0 + reserved-identifiers: 1.2.0 + + toidentifier@1.0.1: {} + + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + totalist@3.0.1: {} + + tr46@0.0.3: {} + + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + + ts-api-utils@1.4.3(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-declaration-location@1.0.7(typescript@5.9.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.3 + + ts-interface-checker@0.1.13: {} + + tslib@2.3.0: {} + + tslib@2.4.0: {} + + tslib@2.8.1: {} + + turbo-darwin-64@2.7.2: + optional: true + + turbo-darwin-arm64@2.7.2: + optional: true + + turbo-linux-64@2.7.2: + optional: true + + turbo-linux-arm64@2.7.2: + optional: true + + turbo-windows-64@2.7.2: + optional: true + + turbo-windows-arm64@2.7.2: + optional: true + + turbo@2.7.2: + optionalDependencies: + turbo-darwin-64: 2.7.2 + turbo-darwin-arm64: 2.7.2 + turbo-linux-64: 2.7.2 + turbo-linux-arm64: 2.7.2 + turbo-windows-64: 2.7.2 + turbo-windows-arm64: 2.7.2 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.16.0: {} + + type-fest@4.41.0: {} + + type-fest@5.3.1: + dependencies: + tagged-tag: 1.0.0 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript@5.8.2: {} + + typescript@5.9.3: {} + + ufo@1.6.1: {} + + uint8array-extras@1.5.0: {} + + ultrahtml@1.6.0: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + unbuild@3.6.1(sass@1.97.1)(typescript@5.9.3)(vue-tsc@3.2.1(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@rollup/plugin-alias': 5.1.1(rollup@4.54.0) + '@rollup/plugin-commonjs': 28.0.9(rollup@4.54.0) + '@rollup/plugin-json': 6.1.0(rollup@4.54.0) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.54.0) + '@rollup/plugin-replace': 6.0.3(rollup@4.54.0) + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + esbuild: 0.25.3 + fix-dts-default-cjs-exports: 1.0.1 + hookable: 5.5.3 + jiti: 2.6.1 + magic-string: 0.30.21 + mkdist: 2.4.1(sass@1.97.1)(typescript@5.9.3)(vue-tsc@3.2.1(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3)) + mlly: 1.8.0 + pathe: 2.0.3 + pkg-types: 2.3.0 + pretty-bytes: 7.1.0 + rollup: 4.54.0 + rollup-plugin-dts: 6.3.0(rollup@4.54.0)(typescript@5.9.3) + scule: 1.3.0 + tinyglobby: 0.2.15 + untyped: 2.0.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - sass + - vue + - vue-sfc-transformer + - vue-tsc + + uncrypto@0.1.3: {} + + unctx@2.5.0: + dependencies: + acorn: 8.15.0 + estree-walker: 3.0.3 + magic-string: 0.30.21 + unplugin: 2.3.11 + + undici-types@7.16.0: {} + + undici@7.16.0: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.2.0: {} + + unicorn-magic@0.1.0: {} + + unicorn-magic@0.3.0: {} + + unimport@5.6.0: + dependencies: + acorn: 8.15.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.1.2 + magic-string: 0.30.21 + mlly: 1.8.0 + pathe: 2.0.3 + picomatch: 4.0.3 + pkg-types: 2.3.0 + scule: 1.3.0 + strip-literal: 3.1.0 + tinyglobby: 0.2.15 + unplugin: 2.3.11 + unplugin-utils: 0.3.1 + + unique-filename@5.0.0: + dependencies: + unique-slug: 6.0.0 + + unique-slug@6.0.0: + dependencies: + imurmurhash: 0.1.4 + + unique-string@2.0.0: + dependencies: + crypto-random-string: 2.0.0 + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + + unplugin@1.16.1: + dependencies: + acorn: 8.15.0 + webpack-virtual-modules: 0.6.2 + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + unstorage@1.17.3(db0@0.3.4)(ioredis@5.8.2): + dependencies: + anymatch: 3.1.3 + chokidar: 4.0.3 + destr: 2.0.5 + h3: 1.15.4 + lru-cache: 10.4.3 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.1 + optionalDependencies: + db0: 0.3.4 + ioredis: 5.8.2 + + untun@0.1.3: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 1.1.2 + + untyped@2.0.0: + dependencies: + citty: 0.1.6 + defu: 6.1.4 + jiti: 2.6.1 + knitwork: 1.3.0 + scule: 1.3.0 + + unwasm@0.3.11: + dependencies: + knitwork: 1.3.0 + magic-string: 0.30.21 + mlly: 1.8.0 + pathe: 2.0.3 + pkg-types: 2.3.0 + unplugin: 2.3.11 + + upath@1.2.0: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + update-notifier@7.3.1: + dependencies: + boxen: 8.0.1 + chalk: 5.6.2 + configstore: 7.1.0 + is-in-ci: 1.0.0 + is-installed-globally: 1.0.0 + is-npm: 6.1.0 + latest-version: 9.0.0 + pupa: 3.3.0 + semver: 7.7.3 + xdg-basedir: 5.1.0 + + uqr@0.1.2: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + vee-validate@4.15.1(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 7.7.9 + type-fest: 4.41.0 + vue: 3.5.26(typescript@5.9.3) + + vite-dev-rpc@1.1.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + birpc: 2.9.0 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vite-hot-client: 2.1.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + + vite-hot-client@2.1.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + + vite-node@3.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite-node@3.2.4(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + optional: true + + vite-plugin-compression@0.5.1(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + chalk: 4.1.2 + debug: 4.4.3 + fs-extra: 10.1.0 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + + vite-plugin-dts@4.5.4(@types/node@25.0.3)(rollup@4.54.0)(typescript@5.9.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + '@microsoft/api-extractor': 7.55.2(@types/node@25.0.3) + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + '@volar/typescript': 2.4.27 + '@vue/language-core': 2.2.0(typescript@5.9.3) + compare-versions: 6.1.1 + debug: 4.4.3 + kolorist: 1.8.0 + local-pkg: 1.1.2 + magic-string: 0.30.21 + typescript: 5.9.3 + optionalDependencies: + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + + vite-plugin-html@3.2.2(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + '@rollup/pluginutils': 4.2.1 + colorette: 2.0.20 + connect-history-api-fallback: 1.6.0 + consola: 2.15.3 + dotenv: 16.6.1 + dotenv-expand: 8.0.3 + ejs: 3.1.10 + fast-glob: 3.3.3 + fs-extra: 10.1.0 + html-minifier-terser: 6.1.0 + node-html-parser: 5.4.2 + pathe: 0.2.0 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + + vite-plugin-inspect@11.3.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + ansis: 4.2.0 + debug: 4.4.3 + error-stack-parser-es: 1.0.5 + ohash: 2.0.11 + open: 10.2.0 + perfect-debounce: 2.0.0 + sirv: 3.0.2 + unplugin-utils: 0.3.1 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vite-dev-rpc: 1.1.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + transitivePeerDependencies: + - supports-color + + vite-plugin-lazy-import@1.0.7: + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) + es-module-lexer: 1.7.0 + rollup: 4.54.0 + xe-utils: 3.8.0 + + vite-plugin-pwa@1.2.0(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(workbox-build@7.4.0)(workbox-window@7.4.0): + dependencies: + debug: 4.4.3 + pretty-bytes: 6.1.1 + tinyglobby: 0.2.15 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + workbox-build: 7.4.0 + workbox-window: 7.4.0 + transitivePeerDependencies: + - supports-color + + vite-plugin-vue-devtools@8.0.5(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@vue/devtools-core': 8.0.5(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) + '@vue/devtools-kit': 8.0.5 + '@vue/devtools-shared': 8.0.5 + sirv: 3.0.2 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vite-plugin-inspect: 11.3.3(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + vite-plugin-vue-inspector: 5.3.2(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + transitivePeerDependencies: + - '@nuxt/kit' + - supports-color + - vue + + vite-plugin-vue-inspector@5.3.2(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)): + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.5) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + '@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5) + '@vue/compiler-dom': 3.5.26 + kolorist: 1.8.0 + magic-string: 0.30.21 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + + vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2): + dependencies: + esbuild: 0.25.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.54.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 24.10.4 + fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.5.1 + sass: 1.97.1 + terser: 5.44.1 + yaml: 2.8.2 + + vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2): + dependencies: + esbuild: 0.25.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.54.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.0.3 + fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.5.1 + sass: 1.97.1 + terser: 5.44.1 + yaml: 2.8.2 + + vitest@3.2.4(@types/node@24.10.4)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.10.4 + happy-dom: 17.6.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vitest@3.2.4(@types/node@25.0.3)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@25.0.3)(jiti@2.6.1)(less@4.5.1)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.0.3 + happy-dom: 17.6.3 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + optional: true + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-uri@3.1.0: {} + + vue-component-type-helpers@2.2.12: {} + + vue-demi@0.14.10(vue@3.5.26(typescript@5.9.3)): + dependencies: + vue: 3.5.26(typescript@5.9.3) + + vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + + vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@intlify/core-base': 11.2.7 + '@intlify/shared': 11.2.7 + '@vue/devtools-api': 6.6.4 + vue: 3.5.26(typescript@5.9.3) + + vue-json-viewer@3.0.4(vue@3.5.26(typescript@5.9.3)): + dependencies: + clipboard: 2.0.11 + vue: 3.5.26(typescript@5.9.3) + + vue-router@4.6.4(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.26(typescript@5.9.3) + + vue-tippy@6.7.1(vue@3.5.26(typescript@5.9.3)): + dependencies: + tippy.js: 6.3.7 + vue: 3.5.26(typescript@5.9.3) + + vue-tsc@3.2.1(typescript@5.9.3): + dependencies: + '@volar/typescript': 2.4.27 + '@vue/language-core': 3.2.1 + typescript: 5.9.3 + + vue-types@3.0.2(vue@3.5.26(typescript@5.9.3)): + dependencies: + is-plain-object: 3.0.1 + vue: 3.5.26(typescript@5.9.3) + + vue@3.5.26(typescript@5.9.3): + dependencies: + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-sfc': 3.5.26 + '@vue/runtime-dom': 3.5.26 + '@vue/server-renderer': 3.5.26(vue@3.5.26(typescript@5.9.3)) + '@vue/shared': 3.5.26 + optionalDependencies: + typescript: 5.9.3 + + vxe-pc-ui@4.11.17(vue@3.5.26(typescript@5.9.3)): + dependencies: + '@vxe-ui/core': 4.2.16(vue@3.5.26(typescript@5.9.3)) + transitivePeerDependencies: + - vue + + vxe-table@4.17.33(vue@3.5.26(typescript@5.9.3)): + dependencies: + vxe-pc-ui: 4.11.17(vue@3.5.26(typescript@5.9.3)) + transitivePeerDependencies: + - vue + + warning@4.0.3: + dependencies: + loose-envify: 1.4.0 + + watermark-js-plus@1.6.3: {} + + web-streams-polyfill@3.3.3: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@4.0.2: {} + + webidl-conversions@7.0.0: {} + + webpack-virtual-modules@0.6.2: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@3.0.0: {} + + whatwg-mimetype@4.0.0: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + when-exit@2.1.5: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-module@2.0.1: {} + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + + word-wrap@1.2.5: {} + + workbox-background-sync@7.4.0: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.0 + + workbox-broadcast-update@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-build@7.4.0: + dependencies: + '@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1) + '@babel/core': 7.28.5 + '@babel/preset-env': 7.28.5(@babel/core@7.28.5) + '@babel/runtime': 7.28.4 + '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.5)(rollup@2.79.2) + '@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2) + '@rollup/plugin-replace': 2.4.2(rollup@2.79.2) + '@rollup/plugin-terser': 0.4.4(rollup@2.79.2) + '@surma/rollup-plugin-off-main-thread': 2.2.3 + ajv: 8.17.1 + common-tags: 1.8.2 + fast-json-stable-stringify: 2.1.0 + fs-extra: 9.1.0 + glob: 11.1.0 + lodash: 4.17.21 + pretty-bytes: 5.6.0 + rollup: 2.79.2 + source-map: 0.8.0-beta.0 + stringify-object: 3.3.0 + strip-comments: 2.0.1 + tempy: 0.6.0 + upath: 1.2.0 + workbox-background-sync: 7.4.0 + workbox-broadcast-update: 7.4.0 + workbox-cacheable-response: 7.4.0 + workbox-core: 7.4.0 + workbox-expiration: 7.4.0 + workbox-google-analytics: 7.4.0 + workbox-navigation-preload: 7.4.0 + workbox-precaching: 7.4.0 + workbox-range-requests: 7.4.0 + workbox-recipes: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + workbox-streams: 7.4.0 + workbox-sw: 7.4.0 + workbox-window: 7.4.0 + transitivePeerDependencies: + - '@types/babel__core' + - supports-color + + workbox-cacheable-response@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-core@7.4.0: {} + + workbox-expiration@7.4.0: + dependencies: + idb: 7.1.1 + workbox-core: 7.4.0 + + workbox-google-analytics@7.4.0: + dependencies: + workbox-background-sync: 7.4.0 + workbox-core: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + + workbox-navigation-preload@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-precaching@7.4.0: + dependencies: + workbox-core: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + + workbox-range-requests@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-recipes@7.4.0: + dependencies: + workbox-cacheable-response: 7.4.0 + workbox-core: 7.4.0 + workbox-expiration: 7.4.0 + workbox-precaching: 7.4.0 + workbox-routing: 7.4.0 + workbox-strategies: 7.4.0 + + workbox-routing@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-strategies@7.4.0: + dependencies: + workbox-core: 7.4.0 + + workbox-streams@7.4.0: + dependencies: + workbox-core: 7.4.0 + workbox-routing: 7.4.0 + + workbox-sw@7.4.0: {} + + workbox-window@7.4.0: + dependencies: + '@types/trusted-types': 2.0.7 + workbox-core: 7.4.0 + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.0 + + xdg-basedir@5.1.0: {} + + xe-utils@3.8.0: {} + + xml-name-validator@4.0.0: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yallist@5.0.0: {} + + yaml-eslint-parser@1.3.2: + dependencies: + eslint-visitor-keys: 3.4.3 + yaml: 2.8.2 + + yaml@1.10.2: {} + + yaml@2.8.2: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@20.2.9: {} + + yargs-parser@21.1.1: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.2: {} + + yoctocolors@2.1.2: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.13: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.12 + cookie-es: 2.0.0 + youch-core: 0.3.3 + + zip-stream@6.0.1: + dependencies: + archiver-utils: 5.0.2 + compress-commons: 6.0.2 + readable-stream: 4.7.0 + + zod-defaults@0.1.3(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + + zrender@6.0.0: + dependencies: + tslib: 2.3.0 + + zx@8.8.5: {} diff --git a/admin-ui/vue/pnpm-workspace.yaml b/admin-ui/vue/pnpm-workspace.yaml new file mode 100644 index 0000000..0e5d00e --- /dev/null +++ b/admin-ui/vue/pnpm-workspace.yaml @@ -0,0 +1,197 @@ +packages: + - internal/* + - internal/lint-configs/* + - packages/* + - packages/@core/base/* + - packages/@core/ui-kit/* + - packages/@core/forward/* + - packages/@core/* + - packages/effects/* + - packages/business/* + - apps/* + - scripts/* + - docs + - playground + +catalog: + '@ast-grep/napi': ^0.39.9 + '@changesets/changelog-github': ^0.5.1 + '@changesets/cli': ^2.29.7 + '@changesets/git': ^3.0.4 + '@clack/prompts': ^0.11.0 + '@commitlint/cli': ^19.8.1 + '@commitlint/config-conventional': ^19.8.1 + '@ctrl/tinycolor': ^4.1.0 + '@eslint/js': ^9.39.1 + '@faker-js/faker': ^9.9.0 + '@iconify/json': ^2.2.406 + '@iconify/tailwind': ^1.2.0 + '@iconify/vue': ^5.0.0 + '@intlify/core-base': ^11.1.7 + '@intlify/unplugin-vue-i18n': ^6.0.8 + '@jspm/generator': ^2.6.2 + '@manypkg/get-packages': ^3.0.0 + '@nolebase/vitepress-plugin-git-changelog': ^2.18.0 + '@playwright/test': ^1.56.1 + '@pnpm/workspace.read-manifest': ^1000.2.6 + '@stylistic/stylelint-plugin': ^3.1.3 + '@tailwindcss/nesting': 0.0.0-insiders.565cd3e + '@tailwindcss/typography': ^0.5.16 + '@tanstack/vue-query': ^5.91.0 + '@tanstack/vue-store': ^0.8.0 + '@types/archiver': ^6.0.3 + '@types/eslint': ^9.6.1 + '@types/html-minifier-terser': ^7.0.2 + '@types/json-bigint': ^1.0.4 + '@types/jsonwebtoken': ^9.0.10 + '@types/lodash.clonedeep': ^4.5.9 + '@types/lodash.get': ^4.4.9 + '@types/lodash.isequal': ^4.5.8 + '@types/lodash.set': ^4.3.9 + '@types/node': ^24.10.1 + '@types/nprogress': ^0.2.3 + '@types/postcss-import': ^14.0.3 + '@types/qrcode': ^1.5.5 + '@types/qs': ^6.14.0 + '@types/sortablejs': ^1.15.8 + '@typescript-eslint/eslint-plugin': ^8.46.4 + '@typescript-eslint/parser': ^8.46.4 + '@vee-validate/zod': ^4.15.1 + '@vite-pwa/vitepress': ^1.0.0 + '@vitejs/plugin-vue': ^6.0.1 + '@vitejs/plugin-vue-jsx': ^5.1.1 + '@vue/reactivity': ^3.5.17 + '@vue/shared': ^3.5.24 + '@vue/test-utils': ^2.4.6 + '@vueuse/core': ^13.4.0 + '@vueuse/integrations': ^14.0.0 + '@vueuse/motion': ^3.0.3 + ant-design-vue: ^4.2.6 + archiver: ^7.0.1 + autoprefixer: ^10.4.22 + axios: ^1.10.0 + axios-mock-adapter: ^2.1.0 + cac: ^6.7.14 + chalk: ^5.4.1 + cheerio: ^1.1.0 + circular-dependency-scanner: ^2.3.0 + class-variance-authority: ^0.7.1 + clsx: ^2.1.1 + commitlint-plugin-function-rules: ^4.1.1 + consola: ^3.4.2 + cross-env: ^7.0.3 + cspell: ^8.19.4 + cssnano: ^7.0.7 + cz-git: ^1.11.2 + czg: ^1.11.1 + dayjs: ^1.11.13 + defu: ^6.1.4 + depcheck: ^1.4.7 + dotenv: ^16.6.1 + echarts: ^6.0.0 + element-plus: ^2.10.2 + eslint: ^9.39.1 + eslint-config-turbo: ^2.6.1 + eslint-plugin-command: ^3.3.1 + eslint-plugin-eslint-comments: ^3.2.0 + eslint-plugin-import-x: ^4.16.1 + eslint-plugin-jsdoc: ^61.2.1 + eslint-plugin-jsonc: ^2.21.0 + eslint-plugin-n: ^17.23.1 + eslint-plugin-no-only-tests: ^3.3.0 + eslint-plugin-perfectionist: ^4.15.1 + eslint-plugin-prettier: ^5.5.4 + eslint-plugin-regexp: ^2.10.0 + eslint-plugin-unicorn: ^62.0.0 + eslint-plugin-unused-imports: ^4.3.0 + eslint-plugin-vitest: ^0.5.4 + eslint-plugin-vue: ^10.5.1 + execa: ^9.6.0 + find-up: ^7.0.0 + get-port: ^7.1.0 + globals: ^16.3.0 + h3: ^1.15.3 + happy-dom: ^17.6.3 + html-minifier-terser: ^7.2.0 + is-ci: ^4.1.0 + jiti: ^2.6.1 + json-bigint: ^1.0.0 + jsonc-eslint-parser: ^2.4.1 + jsonwebtoken: ^9.0.2 + lefthook: ^1.13.6 + lodash.clonedeep: ^4.5.0 + lodash.get: ^4.4.2 + lodash.isequal: ^4.5.0 + lodash.set: ^4.3.2 + lucide-vue-next: ^0.553.0 + medium-zoom: ^1.1.0 + naive-ui: ^2.42.0 + nitropack: ^2.11.13 + nprogress: ^0.2.0 + ora: ^8.2.0 + pinia: ^3.0.3 + pinia-plugin-persistedstate: ^4.4.1 + pkg-types: ^2.2.0 + playwright: ^1.56.1 + postcss: ^8.5.6 + postcss-antd-fixes: ^0.2.0 + postcss-html: ^1.8.0 + postcss-import: ^16.1.1 + postcss-preset-env: ^10.2.4 + postcss-scss: ^4.0.9 + prettier: ^3.6.2 + prettier-plugin-tailwindcss: ^0.7.1 + publint: ^0.3.12 + qrcode: ^1.5.4 + qs: ^6.14.0 + reka-ui: ^2.6.0 + resolve.exports: ^2.0.3 + rimraf: ^6.1.0 + rollup: ^4.44.1 + rollup-plugin-visualizer: ^5.14.0 + sass: ^1.94.0 + secure-ls: ^2.0.0 + sortablejs: ^1.15.6 + stylelint: ^16.21.0 + stylelint-config-recess-order: ^6.1.0 + stylelint-config-recommended: ^17.0.0 + stylelint-config-recommended-scss: ^14.1.0 + stylelint-config-recommended-vue: ^1.6.1 + stylelint-config-standard: ^38.0.0 + stylelint-order: ^7.0.0 + stylelint-prettier: ^5.0.3 + stylelint-scss: ^6.12.1 + tailwind-merge: ^2.6.0 + tailwindcss: ^3.4.18 + tailwindcss-animate: ^1.0.7 + tdesign-vue-next: ^1.17.1 + theme-colors: ^0.1.0 + tippy.js: ^6.3.7 + turbo: ^2.6.1 + typescript: ^5.9.3 + unbuild: ^3.6.1 + unplugin-element-plus: ^0.11.1 + vee-validate: ^4.15.1 + vite: ^7.2.2 + vite-plugin-compression: ^0.5.1 + vite-plugin-dts: ^4.5.4 + vite-plugin-html: ^3.2.2 + vite-plugin-lazy-import: ^1.0.7 + vite-plugin-pwa: ^1.0.1 + vite-plugin-vue-devtools: ^8.0.3 + vitepress: ^1.6.3 + vitepress-plugin-group-icons: ^1.6.1 + vitest: ^3.2.4 + vue: ^3.5.24 + vue-eslint-parser: ^10.2.0 + vue-i18n: ^11.1.7 + vue-json-viewer: ^3.0.4 + vue-router: ^4.5.1 + vue-tippy: ^6.7.1 + vue-tsc: ^3.1.4 + vxe-pc-ui: ^4.10.22 + vxe-table: ^4.17.14 + watermark-js-plus: ^1.6.2 + zod: ^3.25.67 + zod-defaults: 0.1.3 + es-toolkit: ^1.41.0 diff --git a/admin-ui/vue/private-folder-alias.json b/admin-ui/vue/private-folder-alias.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/admin-ui/vue/private-folder-alias.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/admin-ui/vue/scripts/clean.mjs b/admin-ui/vue/scripts/clean.mjs new file mode 100644 index 0000000..2049e45 --- /dev/null +++ b/admin-ui/vue/scripts/clean.mjs @@ -0,0 +1,141 @@ +import { promises as fs } from 'node:fs'; +import { join, normalize } from 'node:path'; + +const rootDir = process.cwd(); + +// 控制并发数量,避免创建过多的并发任务 +const CONCURRENCY_LIMIT = 10; + +// 需要跳过的目录,避免进入这些目录进行清理 +const SKIP_DIRS = new Set(['.DS_Store', '.git', '.idea', '.vscode']); + +/** + * 处理单个文件/目录项 + * @param {string} currentDir - 当前目录路径 + * @param {string} item - 文件/目录名 + * @param {string[]} targets - 要删除的目标列表 + * @param {number} _depth - 当前递归深度 + * @returns {Promise} - 是否需要进一步递归处理 + */ +async function processItem(currentDir, item, targets, _depth) { + // 跳过特殊目录 + if (SKIP_DIRS.has(item)) { + return false; + } + + try { + const itemPath = normalize(join(currentDir, item)); + + if (targets.includes(item)) { + // 匹配到目标目录或文件时直接删除 + await fs.rm(itemPath, { force: true, recursive: true }); + console.log(`✅ Deleted: ${itemPath}`); + return false; // 已删除,无需递归 + } + + // 使用 readdir 的 withFileTypes 选项,避免额外的 lstat 调用 + return true; // 可能需要递归,由调用方决定 + } catch (error) { + // 更详细的错误信息 + if (error.code === 'ENOENT') { + // 文件不存在,可能已被删除,这是正常情况 + return false; + } else if (error.code === 'EPERM' || error.code === 'EACCES') { + console.error(`❌ Permission denied: ${item} in ${currentDir}`); + } else { + console.error( + `❌ Error handling item ${item} in ${currentDir}: ${error.message}`, + ); + } + return false; + } +} + +/** + * 递归查找并删除目标目录(并发优化版本) + * @param {string} currentDir - 当前遍历的目录路径 + * @param {string[]} targets - 要删除的目标列表 + * @param {number} depth - 当前递归深度,避免过深递归 + */ +async function cleanTargetsRecursively(currentDir, targets, depth = 0) { + // 限制递归深度,避免无限递归 + if (depth > 10) { + console.warn(`Max recursion depth reached at: ${currentDir}`); + return; + } + + let dirents; + try { + // 使用 withFileTypes 选项,一次性获取文件类型信息,避免后续 lstat 调用 + dirents = await fs.readdir(currentDir, { withFileTypes: true }); + } catch (error) { + // 如果无法读取目录,可能已被删除或权限不足 + console.warn(`Cannot read directory ${currentDir}: ${error.message}`); + return; + } + + // 分批处理,控制并发数量 + for (let i = 0; i < dirents.length; i += CONCURRENCY_LIMIT) { + const batch = dirents.slice(i, i + CONCURRENCY_LIMIT); + + const tasks = batch.map(async (dirent) => { + const item = dirent.name; + const shouldRecurse = await processItem(currentDir, item, targets, depth); + + // 如果是目录且没有被删除,则递归处理 + if (shouldRecurse && dirent.isDirectory()) { + const itemPath = normalize(join(currentDir, item)); + return cleanTargetsRecursively(itemPath, targets, depth + 1); + } + + return null; + }); + + // 并发执行当前批次的任务 + const results = await Promise.allSettled(tasks); + + // 检查是否有失败的任务(可选:用于调试) + const failedTasks = results.filter( + (result) => result.status === 'rejected', + ); + if (failedTasks.length > 0) { + console.warn( + `${failedTasks.length} tasks failed in batch starting at index ${i} in directory: ${currentDir}`, + ); + } + } +} + +(async function startCleanup() { + // 要删除的目录及文件名称 + const targets = ['node_modules', 'dist', '.turbo', 'dist.zip']; + const deleteLockFile = process.argv.includes('--del-lock'); + const cleanupTargets = [...targets]; + + if (deleteLockFile) { + cleanupTargets.push('pnpm-lock.yaml'); + } + + console.log( + `🚀 Starting cleanup of targets: ${cleanupTargets.join(', ')} from root: ${rootDir}`, + ); + + const startTime = Date.now(); + + try { + // 先统计要删除的目标数量 + console.log('📊 Scanning for cleanup targets...'); + + await cleanTargetsRecursively(rootDir, cleanupTargets); + + const endTime = Date.now(); + const duration = (endTime - startTime) / 1000; + + console.log( + `✨ Cleanup process completed successfully in ${duration.toFixed(2)}s`, + ); + } catch (error) { + console.error(`💥 Unexpected error during cleanup: ${error.message}`); + process.exit(1); + } +})(); diff --git a/admin-ui/vue/scripts/deploy/Dockerfile b/admin-ui/vue/scripts/deploy/Dockerfile new file mode 100644 index 0000000..86f439f --- /dev/null +++ b/admin-ui/vue/scripts/deploy/Dockerfile @@ -0,0 +1,37 @@ +FROM node:22-slim AS builder + +# --max-old-space-size +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +ENV NODE_OPTIONS=--max-old-space-size=8192 +ENV TZ=Asia/Shanghai + +RUN npm i -g corepack + +WORKDIR /app + +# copy package.json and pnpm-lock.yaml to workspace +COPY . /app + +# 安装依赖 +RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile +RUN pnpm run build --filter=\!./docs + +RUN echo "Builder Success 🎉" + +FROM nginx:stable-alpine AS production + +# 配置 nginx +RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf \ + && rm -rf /etc/nginx/conf.d/default.conf + +# 复制构建产物 +COPY --from=builder /app/playground/dist /usr/share/nginx/html + +# 复制 nginx 配置 +COPY --from=builder /app/scripts/deploy/nginx.conf /etc/nginx/nginx.conf + +EXPOSE 8080 + +# 启动 nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/admin-ui/vue/scripts/deploy/build-local-docker-image.sh b/admin-ui/vue/scripts/deploy/build-local-docker-image.sh new file mode 100755 index 0000000..4881487 --- /dev/null +++ b/admin-ui/vue/scripts/deploy/build-local-docker-image.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log +ERROR="" +IMAGE_NAME="vben-admin-local" + +function stop_and_remove_container() { + # Stop and remove the existing container + docker stop ${IMAGE_NAME} >/dev/null 2>&1 + docker rm ${IMAGE_NAME} >/dev/null 2>&1 +} + +function remove_image() { + # Remove the existing image + docker rmi vben-admin-pro >/dev/null 2>&1 +} + +function install_dependencies() { + # Install all dependencies + cd ${SCRIPT_DIR} + pnpm install || ERROR="install_dependencies failed" +} + +function build_image() { + # build docker + docker build ../../ -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed" +} + +function log_message() { + if [[ ${ERROR} != "" ]]; + then + >&2 echo "build failed, Please check build-local-docker-image.log for more details" + >&2 echo "ERROR: ${ERROR}" + exit 1 + else + echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container" + echo "" + echo "docker run -d -p 8010:8080 --name ${IMAGE_NAME} ${IMAGE_NAME}" + fi +} + +echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE} +stop_and_remove_container +remove_image + +echo "Info: Installing dependencies" | tee -a ${LOG_FILE} +install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE} + +if [[ ${ERROR} == "" ]]; then + echo "Info: Building docker image" | tee -a ${LOG_FILE} + build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE} +fi + +log_message | tee -a ${LOG_FILE} diff --git a/admin-ui/vue/scripts/deploy/nginx.conf b/admin-ui/vue/scripts/deploy/nginx.conf new file mode 100644 index 0000000..8e6ab10 --- /dev/null +++ b/admin-ui/vue/scripts/deploy/nginx.conf @@ -0,0 +1,75 @@ + +#user nobody; +worker_processes 1; + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; + +#pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + types { + application/javascript js mjs; + text/css css; + text/html html; + } + + sendfile on; + # tcp_nopush on; + + #keepalive_timeout 0; + # keepalive_timeout 65; + + # gzip on; + # gzip_buffers 32 16k; + # gzip_comp_level 6; + # gzip_min_length 1k; + # gzip_static on; + # gzip_types text/plain + # text/css + # application/javascript + # application/json + # application/x-javascript + # text/xml + # application/xml + # application/xml+rss + # text/javascript; #设置压缩的文件类型 + # gzip_vary on; + + server { + listen 8080; + server_name localhost; + + location / { + root /usr/share/nginx/html; + try_files $uri $uri/ /index.html; + index index.html; + # Enable CORS + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + } + + error_page 500 502 503 504 /50x.html; + + location = /50x.html { + root /usr/share/nginx/html; + } + } +} diff --git a/admin-ui/vue/scripts/turbo-run/README.md b/admin-ui/vue/scripts/turbo-run/README.md new file mode 100644 index 0000000..4f90a59 --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/README.md @@ -0,0 +1,59 @@ +# @vben/turbo-run + +`turbo-run` 是一个命令行工具,允许你在多个包中并行运行命令。它提供了一个交互式的界面,让你可以选择要运行命令的包。 + +## 特性 + +- 🚀 交互式选择要运行的包 +- 📦 支持 monorepo 项目结构 +- 🔍 自动检测可用的命令 +- 🎯 精确过滤目标包 + +## 安装 + +```bash +pnpm add -D @vben/turbo-run +``` + +## 使用方法 + +基本语法: + +```bash +turbo-run [script] +``` + +例如,如果你想运行 `dev` 命令: + +```bash +turbo-run dev +``` + +工具会自动检测哪些包有 `dev` 命令,并提供一个交互式界面让你选择要运行的包。 + +## 示例 + +假设你的项目中有以下包: + +- `@vben/app` +- `@vben/admin` +- `@vben/website` + +当你运行: + +```bash +turbo-run dev +``` + +工具会: + +1. 检测哪些包有 `dev` 命令 +2. 显示一个交互式选择界面 +3. 让你选择要运行命令的包 +4. 使用 `pnpm --filter` 在选定的包中运行命令 + +## 注意事项 + +- 确保你的项目使用 pnpm 作为包管理器 +- 确保目标包在 `package.json` 中定义了相应的脚本命令 +- 该工具需要在 monorepo 项目的根目录下运行 diff --git a/admin-ui/vue/scripts/turbo-run/bin/turbo-run.mjs b/admin-ui/vue/scripts/turbo-run/bin/turbo-run.mjs new file mode 100755 index 0000000..407754d --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/bin/turbo-run.mjs @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +import('../dist/index.mjs'); diff --git a/admin-ui/vue/scripts/turbo-run/build.config.ts b/admin-ui/vue/scripts/turbo-run/build.config.ts new file mode 100644 index 0000000..97e572c --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/build.config.ts @@ -0,0 +1,7 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index'], +}); diff --git a/admin-ui/vue/scripts/turbo-run/package.json b/admin-ui/vue/scripts/turbo-run/package.json new file mode 100644 index 0000000..4db2313 --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/package.json @@ -0,0 +1,29 @@ +{ + "name": "@vben/turbo-run", + "version": "5.5.9", + "private": true, + "license": "MIT", + "type": "module", + "scripts": { + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "bin": { + "turbo-run": "./bin/turbo-run.mjs" + }, + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "exports": { + ".": { + "default": "./dist/index.mjs" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "@clack/prompts": "catalog:", + "@vben/node-utils": "workspace:*", + "cac": "catalog:" + } +} diff --git a/admin-ui/vue/scripts/turbo-run/src/index.ts b/admin-ui/vue/scripts/turbo-run/src/index.ts new file mode 100644 index 0000000..2f8dad0 --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/src/index.ts @@ -0,0 +1,29 @@ +import { colors, consola } from '@vben/node-utils'; + +import { cac } from 'cac'; + +import { run } from './run'; + +try { + const turboRun = cac('turbo-run'); + + turboRun + .command('[script]') + .usage(`Run turbo interactively.`) + .action(async (command: string) => { + run({ command }); + }); + + // Invalid command + turboRun.on('command:*', () => { + consola.error(colors.red('Invalid command!')); + process.exit(1); + }); + + turboRun.usage('turbo-run'); + turboRun.help(); + turboRun.parse(); +} catch (error) { + consola.error(error); + process.exit(1); +} diff --git a/admin-ui/vue/scripts/turbo-run/src/run.ts b/admin-ui/vue/scripts/turbo-run/src/run.ts new file mode 100644 index 0000000..31f9f52 --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/src/run.ts @@ -0,0 +1,67 @@ +import { execaCommand, getPackages } from '@vben/node-utils'; + +import { cancel, isCancel, select } from '@clack/prompts'; + +interface RunOptions { + command?: string; +} + +export async function run(options: RunOptions) { + const { command } = options; + if (!command) { + console.error('Please enter the command to run'); + process.exit(1); + } + const { packages } = await getPackages(); + // const appPkgs = await findApps(process.cwd(), packages); + // const websitePkg = packages.find( + // (item) => item.packageJson.name === '@vben/website', + // ); + + // 只显示有对应命令的包 + const selectPkgs = packages.filter((pkg) => { + return (pkg?.packageJson as Record)?.scripts?.[command]; + }); + + let selectPkg: string | symbol; + if (selectPkgs.length > 1) { + selectPkg = await select({ + message: `Select the app you need to run [${command}]:`, + options: selectPkgs.map((item) => ({ + label: item?.packageJson.name, + value: item?.packageJson.name, + })), + }); + + if (isCancel(selectPkg) || !selectPkg) { + cancel('👋 Has cancelled'); + process.exit(0); + } + } else { + selectPkg = selectPkgs[0]?.packageJson?.name ?? ''; + } + + if (!selectPkg) { + console.error('No app found'); + process.exit(1); + } + + execaCommand(`pnpm --filter=${selectPkg} run ${command}`, { + stdio: 'inherit', + }); +} + +/** + * 过滤app包 + * @param root + * @param packages + */ +// async function findApps(root: string, packages: Package[]) { +// // apps内的 +// const appPackages = packages.filter((pkg) => { +// const viteConfigExists = fs.existsSync(join(pkg.dir, 'vite.config.mts')); +// return pkg.dir.startsWith(join(root, 'apps')) && viteConfigExists; +// }); + +// return appPackages; +// } diff --git a/admin-ui/vue/scripts/turbo-run/tsconfig.json b/admin-ui/vue/scripts/turbo-run/tsconfig.json new file mode 100644 index 0000000..b2ec3b6 --- /dev/null +++ b/admin-ui/vue/scripts/turbo-run/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/scripts/vsh/README.md b/admin-ui/vue/scripts/vsh/README.md new file mode 100644 index 0000000..61140d6 --- /dev/null +++ b/admin-ui/vue/scripts/vsh/README.md @@ -0,0 +1,56 @@ +# @vben/vsh + +一个 Shell 脚本工具集合,用于 Vue Vben Admin 项目的开发和管理。 + +## 功能特性 + +- 🚀 基于 Node.js 的现代化 Shell 工具 +- 📦 支持模块化开发和按需加载 +- 🔍 提供依赖检查和分析功能 +- 🔄 支持循环依赖扫描 +- 📝 提供包发布检查功能 + +## 安装 + +```bash +# 使用 pnpm 安装 +pnpm add -D @vben/vsh + +# 或者使用 npm +npm install -D @vben/vsh + +# 或者使用 yarn +yarn add -D @vben/vsh +``` + +## 使用方法 + +### 全局安装 + +```bash +# 全局安装 +pnpm add -g @vben/vsh + +# 使用 vsh 命令 +vsh [command] +``` + +### 本地使用 + +```bash +# 在 package.json 中添加脚本 +{ + "scripts": { + "vsh": "vsh" + } +} + +# 运行命令 +pnpm vsh [command] +``` + +## 命令列表 + +- `vsh check-deps`: 检查项目依赖 +- `vsh scan-circular`: 扫描循环依赖 +- `vsh publish-check`: 检查包发布配置 diff --git a/admin-ui/vue/scripts/vsh/bin/vsh.mjs b/admin-ui/vue/scripts/vsh/bin/vsh.mjs new file mode 100755 index 0000000..407754d --- /dev/null +++ b/admin-ui/vue/scripts/vsh/bin/vsh.mjs @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +import('../dist/index.mjs'); diff --git a/admin-ui/vue/scripts/vsh/build.config.ts b/admin-ui/vue/scripts/vsh/build.config.ts new file mode 100644 index 0000000..97e572c --- /dev/null +++ b/admin-ui/vue/scripts/vsh/build.config.ts @@ -0,0 +1,7 @@ +import { defineBuildConfig } from 'unbuild'; + +export default defineBuildConfig({ + clean: true, + declaration: true, + entries: ['src/index'], +}); diff --git a/admin-ui/vue/scripts/vsh/package.json b/admin-ui/vue/scripts/vsh/package.json new file mode 100644 index 0000000..89f47ea --- /dev/null +++ b/admin-ui/vue/scripts/vsh/package.json @@ -0,0 +1,31 @@ +{ + "name": "@vben/vsh", + "version": "5.5.9", + "private": true, + "license": "MIT", + "type": "module", + "scripts": { + "stub": "pnpm unbuild --stub" + }, + "files": [ + "dist" + ], + "bin": { + "vsh": "./bin/vsh.mjs" + }, + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "exports": { + ".": { + "default": "./dist/index.mjs" + }, + "./package.json": "./package.json" + }, + "dependencies": { + "@vben/node-utils": "workspace:*", + "cac": "catalog:", + "circular-dependency-scanner": "catalog:", + "depcheck": "catalog:", + "publint": "catalog:" + } +} diff --git a/admin-ui/vue/scripts/vsh/src/check-circular/index.ts b/admin-ui/vue/scripts/vsh/src/check-circular/index.ts new file mode 100644 index 0000000..0642506 --- /dev/null +++ b/admin-ui/vue/scripts/vsh/src/check-circular/index.ts @@ -0,0 +1,170 @@ +import type { CAC } from 'cac'; + +import { extname } from 'node:path'; + +import { getStagedFiles } from '@vben/node-utils'; + +import { circularDepsDetect } from 'circular-dependency-scanner'; + +// 默认配置 +const DEFAULT_CONFIG = { + allowedExtensions: ['.cjs', '.js', '.jsx', '.mjs', '.ts', '.tsx', '.vue'], + ignoreDirs: [ + 'dist', + '.turbo', + 'output', + '.cache', + 'scripts', + 'internal', + 'packages/effects/request/src/', + 'packages/@core/ui-kit/menu-ui/src/', + 'packages/@core/ui-kit/popup-ui/src/', + ], + threshold: 0, // 循环依赖的阈值 +} as const; + +// 类型定义 +type CircularDependencyResult = string[]; + +interface CheckCircularConfig { + allowedExtensions?: string[]; + ignoreDirs?: string[]; + threshold?: number; +} + +interface CommandOptions { + config?: CheckCircularConfig; + staged: boolean; + verbose: boolean; +} + +// 缓存机制 +const cache = new Map(); + +/** + * 格式化循环依赖的输出 + * @param circles - 循环依赖结果 + */ +function formatCircles(circles: CircularDependencyResult[]): void { + if (circles.length === 0) { + console.log('✅ No circular dependencies found'); + return; + } + + console.log('⚠️ Circular dependencies found:'); + circles.forEach((circle, index) => { + console.log(`\nCircular dependency #${index + 1}:`); + circle.forEach((file) => console.log(` → ${file}`)); + }); +} + +/** + * 检查项目中的循环依赖 + * @param options - 检查选项 + * @param options.staged - 是否只检查暂存区文件 + * @param options.verbose - 是否显示详细信息 + * @param options.config - 自定义配置 + * @returns Promise + */ +async function checkCircular({ + config = {}, + staged, + verbose, +}: CommandOptions): Promise { + try { + // 合并配置 + const finalConfig = { + ...DEFAULT_CONFIG, + ...config, + }; + + // 生成忽略模式 + const ignorePattern = `**/{${finalConfig.ignoreDirs.join(',')}}/**`; + + // 检查缓存 + const cacheKey = `${staged}-${process.cwd()}-${ignorePattern}`; + if (cache.has(cacheKey)) { + const cachedResults = cache.get(cacheKey); + if (cachedResults) { + verbose && formatCircles(cachedResults); + } + return; + } + + // 检测循环依赖 + const results = await circularDepsDetect({ + absolute: staged, + cwd: process.cwd(), + ignore: [ignorePattern], + }); + + if (staged) { + let files = await getStagedFiles(); + const allowedExtensions = new Set(finalConfig.allowedExtensions); + + // 过滤文件列表 + files = files.filter((file) => allowedExtensions.has(extname(file))); + + const circularFiles: CircularDependencyResult[] = []; + + for (const file of files) { + for (const result of results) { + const resultFiles = result.flat(); + if (resultFiles.includes(file)) { + circularFiles.push(result); + } + } + } + + // 更新缓存 + cache.set(cacheKey, circularFiles); + verbose && formatCircles(circularFiles); + } else { + // 更新缓存 + cache.set(cacheKey, results); + verbose && formatCircles(results); + } + + // 如果发现循环依赖,只输出警告信息 + if (results.length > 0) { + console.log( + '\n⚠️ Warning: Circular dependencies found, please check and fix', + ); + } + } catch (error) { + console.error( + '❌ Error checking circular dependencies:', + error instanceof Error ? error.message : error, + ); + } +} + +/** + * 定义检查循环依赖的命令 + * @param cac - CAC实例 + */ +function defineCheckCircularCommand(cac: CAC): void { + cac + .command('check-circular') + .option('--staged', 'Only check staged files') + .option('--verbose', 'Show detailed information') + .option('--threshold ', 'Threshold for circular dependencies', { + default: 0, + }) + .option('--ignore-dirs ', 'Directories to ignore, comma separated') + .usage('Analyze project circular dependencies') + .action(async ({ ignoreDirs, staged, threshold, verbose }) => { + const config: CheckCircularConfig = { + threshold: Number(threshold), + ...(ignoreDirs && { ignoreDirs: ignoreDirs.split(',') }), + }; + + await checkCircular({ + config, + staged, + verbose: verbose ?? true, + }); + }); +} + +export { type CheckCircularConfig, defineCheckCircularCommand }; diff --git a/admin-ui/vue/scripts/vsh/src/check-dep/index.ts b/admin-ui/vue/scripts/vsh/src/check-dep/index.ts new file mode 100644 index 0000000..e600e1b --- /dev/null +++ b/admin-ui/vue/scripts/vsh/src/check-dep/index.ts @@ -0,0 +1,194 @@ +import type { CAC } from 'cac'; + +import { getPackages } from '@vben/node-utils'; + +import depcheck from 'depcheck'; + +// 默认配置 +const DEFAULT_CONFIG = { + // 需要忽略的依赖匹配 + ignoreMatches: [ + 'vite', + 'vitest', + 'unbuild', + '@vben/tsconfig', + '@vben/vite-config', + '@vben/tailwind-config', + '@types/*', + '@vben-core/design', + ], + // 需要忽略的包 + ignorePackages: [ + '@vben/backend-mock', + '@vben/commitlint-config', + '@vben/eslint-config', + '@vben/node-utils', + '@vben/prettier-config', + '@vben/stylelint-config', + '@vben/tailwind-config', + '@vben/tsconfig', + '@vben/vite-config', + '@vben/vsh', + ], + // 需要忽略的文件模式 + ignorePatterns: ['dist', 'node_modules', 'public'], +}; + +interface DepcheckResult { + dependencies: string[]; + devDependencies: string[]; + missing: Record; +} + +interface DepcheckConfig { + ignoreMatches?: string[]; + ignorePackages?: string[]; + ignorePatterns?: string[]; +} + +interface PackageInfo { + dir: string; + packageJson: { + name: string; + }; +} + +/** + * 清理依赖检查结果 + * @param unused - 依赖检查结果 + */ +function cleanDepcheckResult(unused: DepcheckResult): void { + // 删除file:前缀的依赖提示,该依赖是本地依赖 + Reflect.deleteProperty(unused.missing, 'file:'); + + // 清理路径依赖 + Object.keys(unused.missing).forEach((key) => { + unused.missing[key] = (unused.missing[key] || []).filter( + (item: string) => !item.startsWith('/'), + ); + if (unused.missing[key].length === 0) { + Reflect.deleteProperty(unused.missing, key); + } + }); +} + +/** + * 格式化依赖检查结果 + * @param pkgName - 包名 + * @param unused - 依赖检查结果 + */ +function formatDepcheckResult(pkgName: string, unused: DepcheckResult): void { + const hasIssues = + Object.keys(unused.missing).length > 0 || + unused.dependencies.length > 0 || + unused.devDependencies.length > 0; + + if (!hasIssues) { + return; + } + + console.log('\n📦 Package:', pkgName); + + if (Object.keys(unused.missing).length > 0) { + console.log('❌ Missing dependencies:'); + Object.entries(unused.missing).forEach(([dep, files]) => { + console.log(` - ${dep}:`); + files.forEach((file) => console.log(` → ${file}`)); + }); + } + + if (unused.dependencies.length > 0) { + console.log('⚠️ Unused dependencies:'); + unused.dependencies.forEach((dep) => console.log(` - ${dep}`)); + } + + if (unused.devDependencies.length > 0) { + console.log('⚠️ Unused devDependencies:'); + unused.devDependencies.forEach((dep) => console.log(` - ${dep}`)); + } +} + +/** + * 运行依赖检查 + * @param config - 配置选项 + */ +async function runDepcheck(config: DepcheckConfig = {}): Promise { + try { + const finalConfig = { + ...DEFAULT_CONFIG, + ...config, + }; + + const { packages } = await getPackages(); + + let hasIssues = false; + + await Promise.all( + packages.map(async (pkg: PackageInfo) => { + // 跳过需要忽略的包 + if (finalConfig.ignorePackages.includes(pkg.packageJson.name)) { + return; + } + + const unused = await depcheck(pkg.dir, { + ignoreMatches: finalConfig.ignoreMatches, + ignorePatterns: finalConfig.ignorePatterns, + }); + + cleanDepcheckResult(unused); + + const pkgHasIssues = + Object.keys(unused.missing).length > 0 || + unused.dependencies.length > 0 || + unused.devDependencies.length > 0; + + if (pkgHasIssues) { + hasIssues = true; + formatDepcheckResult(pkg.packageJson.name, unused); + } + }), + ); + + if (!hasIssues) { + console.log('\n✅ Dependency check completed, no issues found'); + } + } catch (error) { + console.error( + '❌ Dependency check failed:', + error instanceof Error ? error.message : error, + ); + } +} + +/** + * 定义依赖检查命令 + * @param cac - CAC实例 + */ +function defineDepcheckCommand(cac: CAC): void { + cac + .command('check-dep') + .option( + '--ignore-packages ', + 'Packages to ignore, comma separated', + ) + .option( + '--ignore-matches ', + 'Dependency patterns to ignore, comma separated', + ) + .option( + '--ignore-patterns ', + 'File patterns to ignore, comma separated', + ) + .usage('Analyze project dependencies') + .action(async ({ ignoreMatches, ignorePackages, ignorePatterns }) => { + const config: DepcheckConfig = { + ...(ignorePackages && { ignorePackages: ignorePackages.split(',') }), + ...(ignoreMatches && { ignoreMatches: ignoreMatches.split(',') }), + ...(ignorePatterns && { ignorePatterns: ignorePatterns.split(',') }), + }; + + await runDepcheck(config); + }); +} + +export { defineDepcheckCommand, type DepcheckConfig }; diff --git a/admin-ui/vue/scripts/vsh/src/code-workspace/index.ts b/admin-ui/vue/scripts/vsh/src/code-workspace/index.ts new file mode 100644 index 0000000..d5ec4ee --- /dev/null +++ b/admin-ui/vue/scripts/vsh/src/code-workspace/index.ts @@ -0,0 +1,78 @@ +import type { CAC } from 'cac'; + +import { join, relative } from 'node:path'; + +import { + colors, + consola, + findMonorepoRoot, + getPackages, + gitAdd, + outputJSON, + prettierFormat, + toPosixPath, +} from '@vben/node-utils'; + +const CODE_WORKSPACE_FILE = join('vben-admin.code-workspace'); + +interface CodeWorkspaceCommandOptions { + autoCommit?: boolean; + spaces?: number; +} + +async function createCodeWorkspace({ + autoCommit = false, + spaces = 2, +}: CodeWorkspaceCommandOptions) { + const { packages, rootDir } = await getPackages(); + + let folders = packages.map((pkg) => { + const { dir, packageJson } = pkg; + return { + name: packageJson.name, + path: toPosixPath(relative(rootDir, dir)), + }; + }); + + folders = folders.filter(Boolean); + + const monorepoRoot = findMonorepoRoot(); + const outputPath = join(monorepoRoot, CODE_WORKSPACE_FILE); + await outputJSON(outputPath, { folders }, spaces); + + await prettierFormat(outputPath); + if (autoCommit) { + await gitAdd(CODE_WORKSPACE_FILE, monorepoRoot); + } +} + +async function runCodeWorkspace({ + autoCommit, + spaces, +}: CodeWorkspaceCommandOptions) { + await createCodeWorkspace({ + autoCommit, + spaces, + }); + if (autoCommit) { + return; + } + consola.log(''); + consola.success(colors.green(`${CODE_WORKSPACE_FILE} is updated!`)); + consola.log(''); +} + +function defineCodeWorkspaceCommand(cac: CAC) { + cac + .command('code-workspace') + .usage('Update the `.code-workspace` file') + .option('--spaces [number]', '.code-workspace JSON file spaces.', { + default: 2, + }) + .option('--auto-commit', 'auto commit .code-workspace JSON file.', { + default: false, + }) + .action(runCodeWorkspace); +} + +export { defineCodeWorkspaceCommand }; diff --git a/admin-ui/vue/scripts/vsh/src/index.ts b/admin-ui/vue/scripts/vsh/src/index.ts new file mode 100644 index 0000000..4943425 --- /dev/null +++ b/admin-ui/vue/scripts/vsh/src/index.ts @@ -0,0 +1,74 @@ +import { colors, consola } from '@vben/node-utils'; + +import { cac } from 'cac'; + +import { version } from '../package.json'; +import { defineCheckCircularCommand } from './check-circular'; +import { defineDepcheckCommand } from './check-dep'; +import { defineCodeWorkspaceCommand } from './code-workspace'; +import { defineLintCommand } from './lint'; +import { definePubLintCommand } from './publint'; + +// 命令描述 +const COMMAND_DESCRIPTIONS = { + 'check-circular': 'Check for circular dependencies', + 'check-dep': 'Check for unused dependencies', + 'code-workspace': 'Manage VS Code workspace settings', + lint: 'Run linting on the project', + publint: 'Check package.json files for publishing standards', +} as const; + +/** + * Initialize and run the CLI + */ +async function main(): Promise { + try { + const vsh = cac('vsh'); + + // Register commands + defineLintCommand(vsh); + definePubLintCommand(vsh); + defineCodeWorkspaceCommand(vsh); + defineCheckCircularCommand(vsh); + defineDepcheckCommand(vsh); + + // Handle invalid commands + vsh.on('command:*', ([cmd]) => { + consola.error( + colors.red(`Invalid command: ${cmd}`), + '\n', + colors.yellow('Available commands:'), + '\n', + Object.entries(COMMAND_DESCRIPTIONS) + .map(([cmd, desc]) => ` ${colors.cyan(cmd)} - ${desc}`) + .join('\n'), + ); + process.exit(1); + }); + + // Set up CLI + vsh.usage('vsh [options]'); + vsh.help(); + vsh.version(version); + + // Parse arguments + vsh.parse(); + } catch (error) { + consola.error( + colors.red('An unexpected error occurred:'), + '\n', + error instanceof Error ? error.message : error, + ); + process.exit(1); + } +} + +// Run the CLI +main().catch((error) => { + consola.error( + colors.red('Failed to start CLI:'), + '\n', + error instanceof Error ? error.message : error, + ); + process.exit(1); +}); diff --git a/admin-ui/vue/scripts/vsh/src/lint/index.ts b/admin-ui/vue/scripts/vsh/src/lint/index.ts new file mode 100644 index 0000000..b95ead6 --- /dev/null +++ b/admin-ui/vue/scripts/vsh/src/lint/index.ts @@ -0,0 +1,48 @@ +import type { CAC } from 'cac'; + +import { execaCommand } from '@vben/node-utils'; + +interface LintCommandOptions { + /** + * Format lint problem. + */ + format?: boolean; +} + +async function runLint({ format }: LintCommandOptions) { + // process.env.FORCE_COLOR = '3'; + + if (format) { + await execaCommand(`stylelint "**/*.{vue,css,less,scss}" --cache --fix`, { + stdio: 'inherit', + }); + await execaCommand(`eslint . --cache --fix`, { + stdio: 'inherit', + }); + await execaCommand(`prettier . --write --cache --log-level warn`, { + stdio: 'inherit', + }); + return; + } + await Promise.all([ + execaCommand(`eslint . --cache`, { + stdio: 'inherit', + }), + execaCommand(`prettier . --ignore-unknown --check --cache`, { + stdio: 'inherit', + }), + execaCommand(`stylelint "**/*.{vue,css,less,scss}" --cache`, { + stdio: 'inherit', + }), + ]); +} + +function defineLintCommand(cac: CAC) { + cac + .command('lint') + .usage('Batch execute project lint check.') + .option('--format', 'Format lint problem.') + .action(runLint); +} + +export { defineLintCommand }; diff --git a/admin-ui/vue/scripts/vsh/src/publint/index.ts b/admin-ui/vue/scripts/vsh/src/publint/index.ts new file mode 100644 index 0000000..d078673 --- /dev/null +++ b/admin-ui/vue/scripts/vsh/src/publint/index.ts @@ -0,0 +1,185 @@ +import type { CAC } from 'cac'; +import type { Result } from 'publint'; + +import { basename, dirname, join } from 'node:path'; + +import { + colors, + consola, + ensureFile, + findMonorepoRoot, + generatorContentHash, + getPackages, + outputJSON, + readJSON, + UNICODE, +} from '@vben/node-utils'; + +import { publint } from 'publint'; +import { formatMessage } from 'publint/utils'; + +const CACHE_FILE = join( + 'node_modules', + '.cache', + 'publint', + '.pkglintcache.json', +); + +interface PubLintCommandOptions { + /** + * Only errors are checked, no program exit is performed + */ + check?: boolean; +} + +/** + * Get files that require lint + * @param files + */ +async function getLintFiles(files: string[] = []) { + const lintFiles: string[] = []; + + if (files?.length > 0) { + return files.filter((file) => basename(file) === 'package.json'); + } + + const { packages } = await getPackages(); + + for (const { dir } of packages) { + lintFiles.push(join(dir, 'package.json')); + } + return lintFiles; +} + +function getCacheFile() { + const root = findMonorepoRoot(); + return join(root, CACHE_FILE); +} + +async function readCache(cacheFile: string) { + try { + await ensureFile(cacheFile); + return await readJSON(cacheFile); + } catch { + return {}; + } +} + +async function runPublint(files: string[], { check }: PubLintCommandOptions) { + const lintFiles = await getLintFiles(files); + const cacheFile = getCacheFile(); + + const cacheData = await readCache(cacheFile); + const cache: Record = cacheData; + + const results = await Promise.all( + lintFiles.map(async (file) => { + try { + const pkgJson = await readJSON(file); + + if (pkgJson.private) { + return null; + } + + Reflect.deleteProperty(pkgJson, 'dependencies'); + Reflect.deleteProperty(pkgJson, 'devDependencies'); + Reflect.deleteProperty(pkgJson, 'peerDependencies'); + const content = JSON.stringify(pkgJson); + const hash = generatorContentHash(content); + + const publintResult: Result = + cache?.[file]?.hash === hash + ? (cache?.[file]?.result ?? []) + : await publint({ + level: 'suggestion', + pkgDir: dirname(file), + strict: true, + }); + + cache[file] = { + hash, + result: publintResult, + }; + + return { pkgJson, pkgPath: file, publintResult }; + } catch { + return null; + } + }), + ); + + await outputJSON(cacheFile, cache); + printResult(results, check); +} + +function printResult( + results: Array; + pkgPath: string; + publintResult: Result; + }>, + check?: boolean, +) { + let errorCount = 0; + let warningCount = 0; + let suggestionsCount = 0; + + for (const result of results) { + if (!result) { + continue; + } + const { pkgJson, pkgPath, publintResult } = result; + const messages = publintResult?.messages ?? []; + if (messages?.length < 1) { + continue; + } + + consola.log(''); + consola.log(pkgPath); + for (const message of messages) { + switch (message.type) { + case 'error': { + errorCount++; + + break; + } + case 'suggestion': { + suggestionsCount++; + break; + } + case 'warning': { + warningCount++; + + break; + } + // No default + } + const ruleUrl = `https://publint.dev/rules#${message.code.toLocaleLowerCase()}`; + consola.log( + ` ${formatMessage(message, pkgJson)}${colors.dim(` ${ruleUrl}`)}`, + ); + } + } + + const totalCount = warningCount + errorCount + suggestionsCount; + if (totalCount > 0) { + consola.error( + colors.red( + `${UNICODE.FAILURE} ${totalCount} problem (${errorCount} errors, ${warningCount} warnings, ${suggestionsCount} suggestions)`, + ), + ); + !check && process.exit(1); + } else { + consola.log(colors.green(`${UNICODE.SUCCESS} No problem`)); + } +} + +function definePubLintCommand(cac: CAC) { + cac + .command('publint [...files]') + .usage('Check if the monorepo package conforms to the publint standard.') + .option('--check', 'Only errors are checked, no program exit is performed.') + .action(runPublint); +} + +export { definePubLintCommand }; diff --git a/admin-ui/vue/scripts/vsh/tsconfig.json b/admin-ui/vue/scripts/vsh/tsconfig.json new file mode 100644 index 0000000..b2ec3b6 --- /dev/null +++ b/admin-ui/vue/scripts/vsh/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/node.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/admin-ui/vue/stylelint.config.mjs b/admin-ui/vue/stylelint.config.mjs new file mode 100644 index 0000000..e380674 --- /dev/null +++ b/admin-ui/vue/stylelint.config.mjs @@ -0,0 +1,4 @@ +export default { + extends: ['@vben/stylelint-config'], + root: true, +}; diff --git a/admin-ui/vue/tea.yaml b/admin-ui/vue/tea.yaml new file mode 100644 index 0000000..6e56d6f --- /dev/null +++ b/admin-ui/vue/tea.yaml @@ -0,0 +1,6 @@ +# https://tea.xyz/what-is-this-file +--- +version: 1.0.0 +codeOwners: + - '0xB33cc732DFc15Cd39eF50Fb165c876E24417E48f' +quorum: 1 diff --git a/admin-ui/vue/turbo.json b/admin-ui/vue/turbo.json new file mode 100644 index 0000000..3443e27 --- /dev/null +++ b/admin-ui/vue/turbo.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://turbo.build/schema.json", + "globalDependencies": [ + "pnpm-lock.yaml", + "**/.env.*local", + "**/tsconfig*.json", + "internal/node-utils/*.json", + "internal/node-utils/src/**/*.ts", + "internal/tailwind-config/src/**/*.ts", + "internal/vite-config/*.json", + "internal/vite-config/src/**/*.ts", + "scripts/*/src/**/*.ts", + "scripts/*/src/**/*.json" + ], + "globalEnv": ["NODE_ENV"], + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": [ + "dist/**", + "dist.zip", + ".vitepress/dist.zip", + ".vitepress/dist/**" + ] + }, + "preview": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "build:analyze": { + "dependsOn": ["^build"], + "outputs": ["dist/**"] + }, + "@vben/backend-mock#build": { + "dependsOn": ["^build"], + "outputs": [".nitro/**", ".output/**"] + }, + "test:e2e": {}, + "dev": { + "dependsOn": [], + "outputs": [], + "cache": false, + "persistent": true + }, + "typecheck": { + "outputs": [] + } + } +} diff --git a/admin-ui/vue/vben-admin.code-workspace b/admin-ui/vue/vben-admin.code-workspace new file mode 100644 index 0000000..aa8205b --- /dev/null +++ b/admin-ui/vue/vben-admin.code-workspace @@ -0,0 +1,172 @@ +{ + "folders": [ + { + "name": "@vben/backend-mock", + "path": "apps/backend-mock", + }, + { + "name": "@vben/web-antd", + "path": "apps/web-antd", + }, + { + "name": "@vben/web-ele", + "path": "apps/web-ele", + }, + { + "name": "@vben/web-naive", + "path": "apps/web-naive", + }, + { + "name": "@vben/docs", + "path": "docs", + }, + { + "name": "@vben/commitlint-config", + "path": "internal/lint-configs/commitlint-config", + }, + { + "name": "@vben/eslint-config", + "path": "internal/lint-configs/eslint-config", + }, + { + "name": "@vben/prettier-config", + "path": "internal/lint-configs/prettier-config", + }, + { + "name": "@vben/stylelint-config", + "path": "internal/lint-configs/stylelint-config", + }, + { + "name": "@vben/node-utils", + "path": "internal/node-utils", + }, + { + "name": "@vben/tailwind-config", + "path": "internal/tailwind-config", + }, + { + "name": "@vben/tsconfig", + "path": "internal/tsconfig", + }, + { + "name": "@vben/vite-config", + "path": "internal/vite-config", + }, + { + "name": "@vben-core/design", + "path": "packages/@core/base/design", + }, + { + "name": "@vben-core/icons", + "path": "packages/@core/base/icons", + }, + { + "name": "@vben-core/shared", + "path": "packages/@core/base/shared", + }, + { + "name": "@vben-core/typings", + "path": "packages/@core/base/typings", + }, + { + "name": "@vben-core/composables", + "path": "packages/@core/composables", + }, + { + "name": "@vben-core/preferences", + "path": "packages/@core/preferences", + }, + { + "name": "@vben-core/form-ui", + "path": "packages/@core/ui-kit/form-ui", + }, + { + "name": "@vben-core/layout-ui", + "path": "packages/@core/ui-kit/layout-ui", + }, + { + "name": "@vben-core/menu-ui", + "path": "packages/@core/ui-kit/menu-ui", + }, + { + "name": "@vben-core/popup-ui", + "path": "packages/@core/ui-kit/popup-ui", + }, + { + "name": "@vben-core/shadcn-ui", + "path": "packages/@core/ui-kit/shadcn-ui", + }, + { + "name": "@vben-core/tabs-ui", + "path": "packages/@core/ui-kit/tabs-ui", + }, + { + "name": "@vben/constants", + "path": "packages/constants", + }, + { + "name": "@vben/access", + "path": "packages/effects/access", + }, + { + "name": "@vben/common-ui", + "path": "packages/effects/common-ui", + }, + { + "name": "@vben/hooks", + "path": "packages/effects/hooks", + }, + { + "name": "@vben/layouts", + "path": "packages/effects/layouts", + }, + { + "name": "@vben/plugins", + "path": "packages/effects/plugins", + }, + { + "name": "@vben/request", + "path": "packages/effects/request", + }, + { + "name": "@vben/icons", + "path": "packages/icons", + }, + { + "name": "@vben/locales", + "path": "packages/locales", + }, + { + "name": "@vben/preferences", + "path": "packages/preferences", + }, + { + "name": "@vben/stores", + "path": "packages/stores", + }, + { + "name": "@vben/styles", + "path": "packages/styles", + }, + { + "name": "@vben/types", + "path": "packages/types", + }, + { + "name": "@vben/utils", + "path": "packages/utils", + }, + { + "name": "@vben/playground", + "path": "playground", + }, + { + "name": "@vben/turbo-run", + "path": "scripts/turbo-run", + }, + { + "name": "@vben/vsh", + "path": "scripts/vsh", + }, + ], +} diff --git a/admin-ui/vue/vitest.config.ts b/admin-ui/vue/vitest.config.ts new file mode 100644 index 0000000..a10b5fa --- /dev/null +++ b/admin-ui/vue/vitest.config.ts @@ -0,0 +1,11 @@ +import Vue from '@vitejs/plugin-vue'; +import VueJsx from '@vitejs/plugin-vue-jsx'; +import { configDefaults, defineConfig } from 'vitest/config'; + +export default defineConfig({ + plugins: [Vue(), VueJsx()], + test: { + environment: 'happy-dom', + exclude: [...configDefaults.exclude, '**/e2e/**'], + }, +}); diff --git a/admin-ui/vue/vitest.workspace.ts b/admin-ui/vue/vitest.workspace.ts new file mode 100644 index 0000000..f00d6f6 --- /dev/null +++ b/admin-ui/vue/vitest.workspace.ts @@ -0,0 +1,3 @@ +import { defineWorkspace } from 'vitest/config'; + +export default defineWorkspace(['vitest.config.ts']);