From 3106d96ac722bb554a70448f42cadf74539229d4 Mon Sep 17 00:00:00 2001 From: MiFaZhan Date: Mon, 26 Oct 2026 13:46:34 +0800 Subject: [PATCH 01/11] =?UTF-8?q?chore:=20=E5=88=9D=E5=A7=8B=E5=BC=80?= =?UTF-8?q?=E6=BA=90=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iotlcm-admin-ui:管理前端(基于 Vben Admin 5.5.9 二次开发)。 - 天地图 API Key → YOUR_TIANDITU_KEY - OAuth 客户端 ID → your-client-id,store 加密密钥 → 提示自行替换 - Makefile 移除明文 registry 登录口令,镜像地址改 - appIcon 指向内网图床的链接 → /favicon.ico - 真实手机号 → 合法 11 位编造号(保留号段前 3 位 + 后 4 位) - 真实邮箱 → example.com(署名头内的上游作者邮箱保留) - 移除 CI 触发器 - 补 MIT LICENSE(含 Vben Admin 上游声明)+ README - 统一 LF 行尾并加 .gitattributes 上游 Vben Admin 的版权与许可声明完整保留(各源文件 @Author/@Copyright 头 + LICENSE)。 --- .dockerignore | 7 + .gitattributes | 14 + .gitignore | 66 + LICENSE | 22 + Makefile | 21 + README.md | 90 + vue/.browserslistrc | 4 + vue/.commitlintrc.js | 1 + vue/.dockerignore | 7 + vue/.editorconfig | 18 + vue/.husky/commit-msg | 6 + vue/.husky/post-merge | 3 + vue/.husky/pre-commit | 7 + vue/.lintstagedrc.mjs | 20 + vue/.node-version | 1 + vue/.npmrc | 13 + vue/.prettierignore | 18 + vue/.prettierrc.mjs | 1 + vue/.stylelintignore | 4 + vue/.vscode/settings.json | 9 + vue/README.md | 152 + vue/README.zh-CN.md | 152 + vue/aaa.md | 269 + vue/apps/.gitignore | 1 + vue/apps/web-antd/.env | 9 + vue/apps/web-antd/.env.analyze | 7 + vue/apps/web-antd/.env.development | 19 + vue/apps/web-antd/.env.production | 22 + vue/apps/web-antd/index.html | 48 + vue/apps/web-antd/loading.html | 290 + vue/apps/web-antd/package.json | 60 + .../web-antd/plugins/api-type-generator.ts | 427 + vue/apps/web-antd/postcss.config.mjs | 1 + vue/apps/web-antd/public/config.json | 0 vue/apps/web-antd/public/favicon.ico | Bin 0 -> 16958 bytes vue/apps/web-antd/public/logo.png | Bin 0 -> 14333 bytes vue/apps/web-antd/public/menu-setting.json | 18 + .../web-antd/public/mini-program-code.png | Bin 0 -> 82600 bytes vue/apps/web-antd/public/setting.json | 14 + .../web-antd/src/adapter/component/antd.ts | 102 + .../src/adapter/component/helpers/message.ts | 20 + .../component/helpers/upload-preview.ts | 125 + .../helpers/with-default-placeholder.ts | 46 + .../component/helpers/with-preview-upload.ts | 114 + .../web-antd/src/adapter/component/index.ts | 136 + .../web-antd/src/adapter/component/props.ts | 19 + .../web-antd/src/adapter/component/types.ts | 61 + vue/apps/web-antd/src/adapter/form.ts | 68 + .../web-antd/src/adapter/highlightedit.ts | 124 + vue/apps/web-antd/src/adapter/vxe-table.ts | 70 + vue/apps/web-antd/src/api/agent/index.ts | 170 + .../web-antd/src/api/agent/tApiGroup/index.ts | 34 + .../src/api/agent/tApiResource/index.ts | 34 + .../src/api/common/tAgentBalance/index.ts | 70 + .../src/api/common/tBalanceDetail/index.ts | 33 + .../common/tConsumeAccountMonthBill/index.ts | 34 + .../src/api/common/tCreditDetail/index.ts | 29 + .../api/common/tFinCommissionDetail/index.ts | 49 + .../common/tFinWithdrawableChange/index.ts | 29 + .../src/api/common/tFinanceApply/index.ts | 38 + .../api/common/tFinanceAuditRecord/index.ts | 29 + .../src/api/common/tMessageLog/index.ts | 29 + .../src/api/common/tNotifyLog/index.ts | 29 + .../common/tProfitAccountMonthBill/index.ts | 63 + .../src/api/common/tWoCommunication/index.ts | 34 + .../web-antd/src/api/common/tWoMain/index.ts | 54 + .../src/api/common/tWoRecord/index.ts | 29 + vue/apps/web-antd/src/api/core/auth.ts | 185 + vue/apps/web-antd/src/api/core/captcha.ts | 21 + vue/apps/web-antd/src/api/core/index.ts | 14 + vue/apps/web-antd/src/api/core/menu.ts | 20 + vue/apps/web-antd/src/api/core/upload.ts | 57 + vue/apps/web-antd/src/api/core/user.ts | 20 + .../src/api/gen/testCategory/index.ts | 39 + .../web-antd/src/api/gen/testDemo/index.ts | 38 + .../web-antd/src/api/gen_codes/gen_table.ts | 325 + vue/apps/web-antd/src/api/index.ts | 11 + .../web-antd/src/api/iotlcm/tApi/index.ts | 47 + vue/apps/web-antd/src/api/iotlcm/tApi/type.ts | 105 + .../tChannel/tSimChannelTemplate/index.ts | 53 + .../tChannel/tSimChannelTemplate/type.ts | 141 + .../api/iotlcm/tChannel/tSimChannels/index.ts | 62 + .../api/iotlcm/tChannel/tSimChannels/type.ts | 306 + .../tCommunication/tSimCardAllocate/index.ts | 52 + .../tCommunication/tSimCardAllocate/type.ts | 49 + .../tCommunication/tSimCardBindPkg/index.ts | 94 + .../tCommunication/tSimCardBindPkg/type.ts | 119 + .../tCommunication/tSimCardCancel/index.ts | 31 + .../tCommunication/tSimCardCancel/type.ts | 39 + .../tSimCardChange/index.test.ts | 119 + .../tCommunication/tSimCardChange/index.ts | 77 + .../tCommunication/tSimCardChange/type.ts | 149 + .../tSimCardDataCut/index.test.ts | 56 + .../tCommunication/tSimCardDataCut/index.ts | 34 + .../tCommunication/tSimCardDataCut/type.ts | 16 + .../tSimCardDataStart/index.test.ts | 58 + .../tCommunication/tSimCardDataStart/index.ts | 33 + .../tSimCardDataStop/index.test.ts | 58 + .../tCommunication/tSimCardDataStop/index.ts | 33 + .../tCommunication/tSimCardInfo/index.test.ts | 39 + .../tCommunication/tSimCardInfo/index.ts | 71 + .../tCommunication/tSimCardInfo/type.ts | 395 + .../tCommunication/tSimCardLifecycle/type.ts | 20 + .../tSimCardRenew/index.test.ts | 88 + .../tCommunication/tSimCardRenew/index.ts | 52 + .../tCommunication/tSimCardRenew/type.ts | 127 + .../tSimCardRestart/index.test.ts | 61 + .../tCommunication/tSimCardRestart/index.ts | 33 + .../tSimCardStart/index.test.ts | 58 + .../tCommunication/tSimCardStart/index.ts | 33 + .../tCommunication/tSimCardStop/index.test.ts | 55 + .../tCommunication/tSimCardStop/index.ts | 33 + .../tSimCardTrafficCutoff/index.test.ts | 132 + .../tSimCardTrafficCutoff/index.ts | 67 + .../tSimCardTrafficCutoff/type.ts | 62 + .../tSimCardUnsub/index.test.ts | 126 + .../tCommunication/tSimCardUnsub/index.ts | 38 + .../tCommunication/tSimCardUnsub/type.ts | 58 + .../tSimPoolBindPackage/index.ts | 96 + .../tSimPoolBindPackage/type.ts | 119 + .../tCommunication/tSimWarningConfig/index.ts | 48 + .../tCommunication/tSimWarningConfig/type.ts | 47 + .../src/api/iotlcm/tDashboard/index.ts | 38 + .../src/api/iotlcm/tDashboard/type.ts | 64 + .../api/iotlcm/tFlowPackageConfig/index.ts | 56 + .../src/api/iotlcm/tLifeCycle/tBatch/index.ts | 67 + .../src/api/iotlcm/tLifeCycle/tBatch/type.ts | 268 + .../tLifeCycle/tSimCardCancellation/index.ts | 21 + .../tLifeCycle/tSimCardCancellation/type.ts | 45 + .../tLifeCycle/tSimCardInbound/index.test.ts | 89 + .../tLifeCycle/tSimCardInbound/index.ts | 137 + .../tLifeCycle/tSimCardOutbound/index.test.ts | 221 + .../tLifeCycle/tSimCardOutbound/index.ts | 197 + .../iotlcm/tLifeCycle/tSimCardStock/index.ts | 49 + .../iotlcm/tLifeCycle/tSimCardStock/type.ts | 125 + .../src/api/iotlcm/tOperationlog/index.ts | 40 + .../src/api/iotlcm/tOperationlog/type.ts | 197 + .../web-antd/src/api/iotlcm/tOrder/index.ts | 97 + .../tSimFlowPackageInfo/index.ts | 58 + .../tSimFlowPackageInfo/type.ts | 228 + .../tSimFlowPackagePrice/index.ts | 130 + .../tSimFlowPackagePrice/type.ts | 332 + .../tPricingPackage/tSimFlowPool/index.ts | 57 + .../tPricingPackage/tSimFlowPool/type.ts | 187 + .../tSimPackageCategory/index.ts | 53 + .../tSimPackageCategory/type.ts | 95 + .../tSimUpstreamPackage/index.ts | 53 + .../tSimUpstreamPackage/type.ts | 97 + .../src/api/iotlcm/tSimDiagnose/index.ts | 30 + .../src/api/iotlcm/tSimDiagnose/type.ts | 160 + .../tWarnCenter/simWarningConfig/index.ts | 41 + .../tWarnCenter/simWarningConfig/type.ts | 78 + .../iotlcm/zAnother/tAgentEnterprise/index.ts | 53 + .../iotlcm/zAnother/tAgentEnterprise/type.ts | 113 + .../zAnother/tCustWithdrawAccount/index.ts | 53 + .../zAnother/tCustWithdrawAccount/type.ts | 155 + .../iotlcm/zAnother/tDivisionCode/index.ts | 49 + .../api/iotlcm/zAnother/tDivisionCode/type.ts | 72 + .../zAnother/tTplatformSetting/index.ts | 39 + vue/apps/web-antd/src/api/monitor/cache.ts | 35 + .../src/api/monitor/full-sync.test.ts | 140 + .../web-antd/src/api/monitor/full-sync.ts | 170 + vue/apps/web-antd/src/api/monitor/index.ts | 11 + vue/apps/web-antd/src/api/monitor/online.ts | 57 + vue/apps/web-antd/src/api/regions/index.ts | 11 + vue/apps/web-antd/src/api/request.ts | 231 + vue/apps/web-antd/src/api/system/client.ts | 140 + vue/apps/web-antd/src/api/system/config.ts | 109 + vue/apps/web-antd/src/api/system/dept.ts | 237 + vue/apps/web-antd/src/api/system/dict.ts | 217 + vue/apps/web-antd/src/api/system/index.ts | 18 + vue/apps/web-antd/src/api/system/job.ts | 86 + .../web-antd/src/api/system/logininfor.ts | 53 + vue/apps/web-antd/src/api/system/menu.ts | 122 + vue/apps/web-antd/src/api/system/notice.ts | 104 + vue/apps/web-antd/src/api/system/oper-log.ts | 46 + .../web-antd/src/api/system/oss-config.ts | 127 + vue/apps/web-antd/src/api/system/oss.ts | 118 + vue/apps/web-antd/src/api/system/post.ts | 143 + vue/apps/web-antd/src/api/system/qrcode.ts | 129 + vue/apps/web-antd/src/api/system/role.ts | 136 + vue/apps/web-antd/src/api/system/social.ts | 54 + .../src/api/system/sysNoticeUser/index.ts | 38 + .../src/api/system/tTplatformSetting.ts | 54 + vue/apps/web-antd/src/api/system/tenant.ts | 136 + .../web-antd/src/api/system/tenant_package.ts | 116 + vue/apps/web-antd/src/api/system/user.ts | 320 + vue/apps/web-antd/src/api/utils/index.ts | 52 + vue/apps/web-antd/src/app.vue | 71 + vue/apps/web-antd/src/assets/icons/custom.ts | 120 + vue/apps/web-antd/src/assets/icons/index.ts | 6 + vue/apps/web-antd/src/assets/icons/mdiSlim.ts | 2351 ++ vue/apps/web-antd/src/bootstrap.ts | 76 + .../FormExpand/RegionSelect/index.vue | 183 + .../HtCustom/FormExpand/Switch/index.vue | 30 + .../HtCustom/FormExpand/TextArea/index.vue | 28 + .../HtCustom/FormExpand/register.ts | 28 + .../components/HtCustom/IconButton/index.png | Bin 0 -> 70767 bytes .../components/HtCustom/IconButton/index.vue | 66 + .../web-antd/src/components/HtCustom/index.ts | 41 + .../src/components/chatList/ChatList.vue | 118 + .../web-antd/src/components/cropper/index.ts | 3 + .../components/cropper/src/cropper-avatar.vue | 170 + .../components/cropper/src/cropper-modal.vue | 328 + .../src/components/cropper/src/cropper.vue | 216 + .../src/components/cropper/src/typing.ts | 8 + .../src/components/dept/dept-tree.vue | 132 + .../src/components/description/index.ts | 3 + .../description/src/description.vue | 202 + .../src/components/description/src/typing.ts | 48 + .../description/src/useDescription.ts | 44 + .../web-antd/src/components/dict/index.ts | 2 + .../web-antd/src/components/dict/src/data.tsx | 44 + .../src/components/dict/src/index.vue | 52 + .../src/components/echarts-vue/piechart.d.ts | 5 + .../src/components/echarts-vue/piechart.vue | 54 + .../web-antd/src/components/icon/AppIcon.vue | 87 + .../src/components/icon/IconSelect.vue | 77 + .../src/components/imgManage/ImgManage.vue | 465 + .../src/components/imgManage/types.d.ts | 0 .../src/components/selectDivision/index.vue | 186 + .../web-antd/src/components/tinymce/index.ts | 1 + .../src/components/tinymce/src/editor.vue | 384 + .../src/components/tinymce/src/helper.ts | 85 + .../src/components/tinymce/src/img-upload.vue | 115 + .../src/components/tinymce/src/tinymce.ts | 11 + .../web-antd/src/components/upload/index.ts | 2 + .../src/components/upload/src/file-upload.vue | 298 + .../src/components/upload/src/helper.ts | 51 + .../components/upload/src/image-upload.vue | 306 + .../src/components/upload/src/typing.ts | 37 + .../src/components/upload/src/use-upload.ts | 61 + .../src/components/vue3cron/job-corn.vue | 361 + .../src/components/vue3cron/language/cn.ts | 54 + .../src/components/vue3cron/language/en.ts | 54 + .../src/components/vue3cron/language/index.ts | 9 + .../src/components/vue3cron/language/pt_br.ts | 54 + vue/apps/web-antd/src/config/fileType.ts | 114 + vue/apps/web-antd/src/config/menu-setting.ts | 92 + vue/apps/web-antd/src/config/setting.ts | 227 + vue/apps/web-antd/src/config/tianditu.ts | 88 + .../src/constants/BetterVben/_form.ts | 31 + .../src/constants/BetterVben/_function.ts | 146 + .../src/constants/BetterVben/_grid.ts | 44 + .../src/constants/BetterVben/_gridForm.ts | 36 + .../src/constants/BetterVben/_modal.ts | 20 + .../src/constants/BetterVben/index.ts | 33 + vue/apps/web-antd/src/constants/DictEnum.ts | 139 + vue/apps/web-antd/src/constants/FormOption.ts | 232 + vue/apps/web-antd/src/constants/RouterPath.ts | 4 + vue/apps/web-antd/src/layouts/auth.vue | 54 + vue/apps/web-antd/src/layouts/basic.vue | 378 + vue/apps/web-antd/src/layouts/index.ts | 6 + vue/apps/web-antd/src/locales/README.md | 3 + vue/apps/web-antd/src/locales/index.ts | 102 + .../src/locales/langs/en-US/component.json | 55 + .../src/locales/langs/en-US/demos.json | 12 + .../src/locales/langs/en-US/http.json | 7 + .../src/locales/langs/en-US/menu.json | 36 + .../src/locales/langs/en-US/page.json | 15 + .../src/locales/langs/en-US/pages.json | 25 + .../web-antd/src/locales/langs/en-US/ui.json | 6 + .../src/locales/langs/zh-CN/component.json | 55 + .../src/locales/langs/zh-CN/demos.json | 12 + .../src/locales/langs/zh-CN/http.json | 7 + .../src/locales/langs/zh-CN/menu.json | 36 + .../src/locales/langs/zh-CN/page.json | 15 + .../src/locales/langs/zh-CN/pages.json | 24 + .../web-antd/src/locales/langs/zh-CN/ui.json | 6 + vue/apps/web-antd/src/main.ts | 50 + vue/apps/web-antd/src/preferences.ts | 73 + vue/apps/web-antd/src/router/access.ts | 44 + vue/apps/web-antd/src/router/guard.ts | 133 + vue/apps/web-antd/src/router/index.ts | 37 + vue/apps/web-antd/src/router/routes/core.ts | 112 + vue/apps/web-antd/src/router/routes/index.ts | 37 + vue/apps/web-antd/src/router/routes/local.ts | 25 + .../src/router/routes/modules/dashboard.ts | 38 + .../src/router/routes/modules/demos.ts | 28 + .../src/router/routes/modules/system.ts | 36 + .../src/router/routes/modules/tenant.ts | 36 + .../src/router/routes/modules/vben.ts | 71 + vue/apps/web-antd/src/store/auth.ts | 245 + vue/apps/web-antd/src/store/cache.ts | 66 + vue/apps/web-antd/src/store/dict.ts | 69 + vue/apps/web-antd/src/store/index.ts | 1 + .../src/template/iotlcm-crud-style/MEMORY.md | 107 + .../src/template/iotlcm-crud-style/README.md | 444 + .../iotlcm-crud-style/compare/README.md | 39 + .../compare/after/api/index.ts.txt | 49 + .../compare/after/api/type.ts.txt | 225 + .../compare/after/view/edit.vue.txt | 99 + .../compare/after/view/index.vue.txt | 180 + .../compare/after/view/model.tsx.txt | 320 + .../compare/after/view/view.vue.txt | 36 + .../compare/before/api/index.ts.txt | 41 + .../compare/before/api/type.ts.txt | 225 + .../compare/before/view/edit.vue.txt | 139 + .../compare/before/view/index.vue.txt | 169 + .../compare/before/view/model.tsx.txt | 491 + .../compare/before/view/view.vue.txt | 30 + .../iotlcm-crud-style/template/api/index.ts | 49 + .../iotlcm-crud-style/template/api/type.ts | 81 + .../iotlcm-crud-style/template/view/edit.vue | 101 + .../iotlcm-crud-style/template/view/index.vue | 182 + .../iotlcm-crud-style/template/view/model.tsx | 174 + .../iotlcm-crud-style/template/view/view.vue | 38 + vue/apps/web-antd/src/types/global.d.ts | 6 + .../web-antd/src/utils/HtCustom/QuickCopy.ts | 47 + .../src/utils/HtCustom/QuickDownLoad.ts | 18 + .../web-antd/src/utils/HtCustom/TabInit.ts | 51 + vue/apps/web-antd/src/utils/HtCustom/index.ts | 9 + vue/apps/web-antd/src/utils/IconManagers.ts | 67 + .../src/utils/__tests__/dept-tree.test.ts | 54 + vue/apps/web-antd/src/utils/bindArray.tsx | 18 + vue/apps/web-antd/src/utils/dept-tree.ts | 55 + vue/apps/web-antd/src/utils/dict.ts | 83 + .../web-antd/src/utils/file/base64Conver.ts | 46 + vue/apps/web-antd/src/utils/file/download.ts | 316 + vue/apps/web-antd/src/utils/file/index.ts | 31 + .../web-antd/src/utils/formatTimestamp.ts | 13 + vue/apps/web-antd/src/utils/image.ts | 45 + vue/apps/web-antd/src/utils/index.tsx | 71 + vue/apps/web-antd/src/utils/is/index.ts | 47 + vue/apps/web-antd/src/utils/render.tsx | 234 + vue/apps/web-antd/src/views/_core/README.md | 3 + .../web-antd/src/views/_core/about/index.vue | 18 + .../views/_core/authentication/code-login.vue | 152 + .../components/first-login-guide-modal.vue | 133 + .../authentication/components/img-captcha.vue | 61 + .../_core/authentication/forget-password.vue | 52 + .../src/views/_core/authentication/login.vue | 201 + .../views/_core/authentication/mfa-verify.vue | 157 + .../_core/authentication/qrcode-login.vue | 18 + .../views/_core/authentication/register.vue | 104 + .../src/views/_core/fallback/coming-soon.vue | 15 + .../src/views/_core/fallback/forbidden.vue | 17 + .../views/_core/fallback/internal-error.vue | 17 + .../src/views/_core/fallback/not-found.vue | 17 + .../src/views/_core/fallback/offline.vue | 17 + .../web-antd/src/views/_core/oauth-common.ts | 113 + .../_core/profile/components/account-bind.vue | 225 + .../_core/profile/components/base-setting.vue | 214 + .../profile/components/contact-setting.vue | 286 + .../profile/components/online-device.vue | 81 + .../profile/components/secure-setting.vue | 235 + .../src/views/_core/profile/index.vue | 59 + .../web-antd/src/views/_core/profile/mitt.ts | 16 + .../src/views/_core/profile/profile-panel.vue | 100 + .../src/views/_core/profile/setting-panel.vue | 102 + .../web-antd/src/views/agent/roles/index.vue | 263 + .../src/views/agent/roles/menu-select.vue | 157 + .../src/views/agent/roles/role-drawer.vue | 196 + .../src/views/agent/structure/dept-drawer.vue | 250 + .../agent/structure/dept-reset-pwd-modal.vue | 102 + .../structure/enterprise-manage-modal.vue | 349 + .../src/views/agent/structure/index.vue | 216 + .../src/views/agent/tApiGroup/edit.vue | 178 + .../src/views/agent/tApiGroup/index.vue | 181 + .../src/views/agent/tApiGroup/model.tsx | 210 + .../src/views/agent/tApiGroup/view.vue | 31 + .../src/views/agent/tApiResource/edit.vue | 115 + .../src/views/agent/tApiResource/index.vue | 181 + .../src/views/agent/tApiResource/model.tsx | 272 + .../src/views/agent/tApiResource/view.vue | 31 + .../web-antd/src/views/agent/users/index.vue | 263 + .../src/views/agent/users/user-drawer.vue | 302 + .../agent/users/user-reset-pwd-modal.vue | 99 + .../views/common/financialOverview/index.vue | 446 + .../views/common/financialOverview/model.ts | 431 + .../src/views/common/tAgentBalance/edit.vue | 114 + .../src/views/common/tAgentBalance/index.vue | 809 + .../src/views/common/tAgentBalance/model.tsx | 756 + .../src/views/common/tAgentBalance/view.vue | 31 + .../src/views/common/tBalanceDetail/edit.vue | 114 + .../src/views/common/tBalanceDetail/index.vue | 169 + .../src/views/common/tBalanceDetail/model.tsx | 440 + .../src/views/common/tBalanceDetail/view.vue | 31 + .../common/tConsumeAccountMonthBill/edit.vue | 114 + .../common/tConsumeAccountMonthBill/index.vue | 182 + .../common/tConsumeAccountMonthBill/model.tsx | 299 + .../common/tConsumeAccountMonthBill/view.vue | 31 + .../src/views/common/tCreditDetail/edit.vue | 114 + .../src/views/common/tCreditDetail/index.vue | 169 + .../src/views/common/tCreditDetail/model.tsx | 396 + .../src/views/common/tCreditDetail/view.vue | 31 + .../common/tFinCommissionDetail/edit.vue | 114 + .../common/tFinCommissionDetail/index.vue | 169 + .../common/tFinCommissionDetail/model.tsx | 445 + .../common/tFinCommissionDetail/view.vue | 31 + .../common/tFinWithdrawableChange/edit.vue | 114 + .../common/tFinWithdrawableChange/index.vue | 169 + .../common/tFinWithdrawableChange/model.tsx | 394 + .../common/tFinWithdrawableChange/view.vue | 31 + .../src/views/common/tFinanceApply/edit.vue | 114 + .../src/views/common/tFinanceApply/index.vue | 228 + .../src/views/common/tFinanceApply/model.tsx | 532 + .../src/views/common/tFinanceApply/view.vue | 31 + .../views/common/tFinanceAuditRecord/edit.vue | 114 + .../common/tFinanceAuditRecord/index.vue | 169 + .../common/tFinanceAuditRecord/model.tsx | 269 + .../views/common/tFinanceAuditRecord/view.vue | 31 + .../src/views/common/tMessageLog/edit.vue | 129 + .../src/views/common/tMessageLog/index.vue | 407 + .../src/views/common/tMessageLog/model.tsx | 376 + .../src/views/common/tMessageLog/view.vue | 26 + .../src/views/common/tNotifyLog/edit.vue | 110 + .../src/views/common/tNotifyLog/index.vue | 367 + .../src/views/common/tNotifyLog/model.tsx | 186 + .../src/views/common/tNotifyLog/view.vue | 26 + .../common/tProfitAccountMonthBill/edit.vue | 114 + .../common/tProfitAccountMonthBill/index.vue | 180 + .../common/tProfitAccountMonthBill/model.tsx | 307 + .../common/tProfitAccountMonthBill/view.vue | 31 + .../views/common/tWoCommunication/edit.vue | 113 + .../views/common/tWoCommunication/index.vue | 1024 + .../views/common/tWoCommunication/model.tsx | 388 + .../views/common/tWoCommunication/view.vue | 265 + .../src/views/common/tWoMain/edit.vue | 184 + .../src/views/common/tWoMain/index.vue | 195 + .../src/views/common/tWoMain/model.tsx | 328 + .../src/views/common/tWoRecord/edit.vue | 113 + .../src/views/common/tWoRecord/index.vue | 168 + .../src/views/common/tWoRecord/model.tsx | 318 + .../src/views/common/tWoRecord/view.vue | 26 + .../dashboard/analytics/analytics-trends.vue | 106 + .../analytics/analytics-visits-data.vue | 90 + .../analytics/analytics-visits-sales.vue | 54 + .../analytics/analytics-visits-source.vue | 65 + .../dashboard/analytics/analytics-visits.vue | 55 + .../src/views/dashboard/analytics/index.vue | 90 + .../src/views/dashboard/workspace/index.vue | 266 + .../web-antd/src/views/demos/antd/index.vue | 66 + .../src/views/gen/testCategory/edit.vue | 112 + .../src/views/gen/testCategory/index.vue | 181 + .../src/views/gen/testCategory/model.tsx | 326 + .../src/views/gen/testCategory/view.vue | 31 + .../web-antd/src/views/gen/testDemo/edit.vue | 112 + .../web-antd/src/views/gen/testDemo/index.vue | 169 + .../web-antd/src/views/gen/testDemo/model.tsx | 375 + .../web-antd/src/views/gen/testDemo/view.vue | 31 + .../web-antd/src/views/iotlcm/tApi/edit.vue | 143 + .../web-antd/src/views/iotlcm/tApi/index.vue | 183 + .../web-antd/src/views/iotlcm/tApi/model.tsx | 166 + .../web-antd/src/views/iotlcm/tApi/view.vue | 36 + .../tChannel/tSimChannelTemplate/edit.vue | 126 + .../tChannel/tSimChannelTemplate/index.vue | 191 + .../tChannel/tSimChannelTemplate/model.tsx | 196 + .../tChannel/tSimChannelTemplate/view.vue | 36 + .../iotlcm/tChannel/tSimChannels/edit.vue | 325 + .../iotlcm/tChannel/tSimChannels/index.vue | 331 + .../iotlcm/tChannel/tSimChannels/model.tsx | 719 + .../iotlcm/tChannel/tSimChannels/test.vue | 424 + .../iotlcm/tChannel/tSimChannels/view.vue | 41 + .../components/batchCardPreview.vue | 180 + .../components/cardSourceTabs.vue | 38 + .../tBusinessAcceptance/index.vue | 398 + .../tBusinessAcceptance/views/addPackage.vue | 1132 + .../tBusinessAcceptance/views/cancel.vue | 222 + .../tBusinessAcceptance/views/change.vue | 970 + .../tBusinessAcceptance/views/dataToggle.vue | 249 + .../tBusinessAcceptance/views/lifecycle.vue | 352 + .../tBusinessAcceptance/views/renew.vue | 1482 ++ .../views/trafficCutoff.vue | 357 + .../tBusinessAcceptance/views/unsubscribe.vue | 304 + .../views/warningConfig.vue | 750 + .../components/FormSchema/NumberSegment.vue | 77 + .../tSimCardInfo/diagnose-route.ts | 165 + .../tCommunication/tSimCardInfo/edit.vue | 104 + .../tCommunication/tSimCardInfo/index.vue | 511 + .../tCommunication/tSimCardInfo/model.test.ts | 135 + .../tCommunication/tSimCardInfo/model.tsx | 448 + .../tSimCardInfo/session-state.test.ts | 66 + .../tSimCardInfo/session-state.ts | 53 + .../tCommunication/tSimCardInfo/view.vue | 1177 + .../tSimCardTrafficCutoff/edit.vue | 96 + .../tSimCardTrafficCutoff/index.vue | 237 + .../tSimCardTrafficCutoff/model.tsx | 164 + .../components/BusinessAlarmPanel.vue | 195 + .../components/BusinessUsageChart.vue | 255 + .../CardLocationDistributionChart.vue | 153 + .../components/LifecycleDistributionChart.vue | 173 + .../iotlcm/tDashboard/components/MyPanel.vue | 155 + .../tDashboard/components/QuickNavigation.vue | 75 + .../tDashboard/components/RecentFeeChart.vue | 95 + .../components/TrafficPoolChart.vue | 152 + .../components/TrafficShareChart.vue | 117 + .../src/views/iotlcm/tDashboard/index.vue | 126 + .../src/views/iotlcm/tDeptApi/index.vue | 85 + .../src/views/iotlcm/tDeptApi/model.tsx | 30 + .../views/iotlcm/tFlowPackageConfig/edit.vue | 159 + .../views/iotlcm/tFlowPackageConfig/index.vue | 169 + .../views/iotlcm/tFlowPackageConfig/model.tsx | 379 + .../views/iotlcm/tFlowPackageConfig/view.vue | 31 + .../components/BasicStatusCard.vue | 362 + .../components/FlowChartCard.vue | 286 + .../components/PackageFlowDiagnosisCard.vue | 146 + .../components/SessionDiagnosisCard.vue | 80 + .../tIntelligentDiagnosis/display.test.ts | 172 + .../iotlcm/tIntelligentDiagnosis/display.ts | 147 + .../iotlcm/tIntelligentDiagnosis/index.vue | 1838 ++ .../iotlcm/tIntelligentDiagnosis/model.ts | 458 + .../tLifeCycle/batchTypeOptions.test.ts | 95 + .../iotlcm/tLifeCycle/batchTypeOptions.ts | 68 + .../views/iotlcm/tLifeCycle/tBatch/cards.vue | 87 + .../views/iotlcm/tLifeCycle/tBatch/edit.vue | 107 + .../views/iotlcm/tLifeCycle/tBatch/index.vue | 89 + .../views/iotlcm/tLifeCycle/tBatch/model.tsx | 464 + .../views/iotlcm/tLifeCycle/tBatch/view.vue | 40 + .../components/fileDownloadButton.tsx | 87 + .../tBatchExecutionLog/detailList.vue | 79 + .../tLifeCycle/tBatchExecutionLog/index.vue | 93 + .../tBatchExecutionLog/model.test.tsx | 261 + .../tLifeCycle/tBatchExecutionLog/model.tsx | 431 + .../tLifeCycle/tBatchExecutionLog/view.vue | 43 + .../tLifeCycle/tSimCardCancellation/index.vue | 83 + .../tLifeCycle/tSimCardCancellation/model.tsx | 157 + .../tSimCardStock/OutboundBalancePreview.vue | 188 + .../tSimCardStock/batch-outbound.vue | 346 + .../iotlcm/tLifeCycle/tSimCardStock/batch.vue | 129 + .../iotlcm/tLifeCycle/tSimCardStock/index.vue | 99 + .../iotlcm/tLifeCycle/tSimCardStock/input.vue | 152 + .../iotlcm/tLifeCycle/tSimCardStock/model.tsx | 669 + .../tSimCardStock/outboundBalance.ts | 52 + .../tSimCardStock/outboundFormUtils.ts | 111 + .../iotlcm/tLifeCycle/tSimCardStock/range.vue | 76 + .../iotlcm/tLifeCycle/tWarehousing/batch.vue | 141 + .../iotlcm/tLifeCycle/tWarehousing/index.vue | 152 + .../iotlcm/tLifeCycle/tWarehousing/input.vue | 158 + .../iotlcm/tLifeCycle/tWarehousing/model.tsx | 664 + .../iotlcm/tLifeCycle/tWarehousing/range.vue | 73 + .../src/views/iotlcm/tOrder/display.tsx | 147 + .../src/views/iotlcm/tOrder/index.vue | 129 + .../src/views/iotlcm/tOrder/indexTwo.vue | 131 + .../web-antd/src/views/iotlcm/tOrder/view.vue | 222 + .../tSimFlowPackageInfo/edit.vue | 293 + .../tSimFlowPackageInfo/index.vue | 230 + .../tSimFlowPackageInfo/model.tsx | 1545 ++ .../tSimFlowPackageInfo/view.vue | 42 + .../tSimFlowPackagePrice/batchAdjust.vue | 143 + .../components/AgentTree/index.vue | 187 + .../tSimFlowPackagePrice/edit.vue | 151 + .../tSimFlowPackagePrice/index.vue | 379 + .../tSimFlowPackagePrice/model.tsx | 208 + .../tPricingPackage/tSimFlowPool/edit.vue | 99 + .../tPricingPackage/tSimFlowPool/index.vue | 95 + .../tPricingPackage/tSimFlowPool/model.tsx | 436 + .../tPricingPackage/tSimFlowPool/view.vue | 162 + .../tSimPackageCategory/edit.vue | 99 + .../tSimPackageCategory/index.vue | 190 + .../tSimPackageCategory/model.tsx | 144 + .../tSimPackageCategory/view.vue | 36 + .../tSimUpstreamPackage/edit.vue | 99 + .../tSimUpstreamPackage/index.vue | 190 + .../tSimUpstreamPackage/model.tsx | 146 + .../tSimUpstreamPackage/view.vue | 36 + .../iotlcm/tWarnCenter/cardConfig/edit.vue | 117 + .../iotlcm/tWarnCenter/cardConfig/index.vue | 175 + .../iotlcm/tWarnCenter/cardConfig/view.vue | 36 + .../tWarnCenter/flowPoolConfig/edit.vue | 122 + .../tWarnCenter/flowPoolConfig/index.vue | 175 + .../tWarnCenter/flowPoolConfig/view.vue | 36 + .../views/iotlcm/tWarnCenter/shared/model.tsx | 576 + .../iotlcm/zAnother/tAgentEnterprise/edit.vue | 99 + .../zAnother/tAgentEnterprise/index.vue | 186 + .../zAnother/tAgentEnterprise/model.tsx | 252 + .../iotlcm/zAnother/tAgentEnterprise/view.vue | 36 + .../zAnother/tCustWithdrawAccount/edit.vue | 99 + .../zAnother/tCustWithdrawAccount/index.vue | 190 + .../zAnother/tCustWithdrawAccount/model.tsx | 269 + .../zAnother/tCustWithdrawAccount/view.vue | 36 + .../iotlcm/zAnother/tDivisionCode/edit.vue | 99 + .../iotlcm/zAnother/tDivisionCode/index.vue | 183 + .../iotlcm/zAnother/tDivisionCode/model.tsx | 127 + .../iotlcm/zAnother/tDivisionCode/view.vue | 36 + .../cache/components/command-chart.vue | 82 + .../views/monitor/cache/components/index.ts | 11 + .../monitor/cache/components/memory-chart.vue | 106 + .../cache/components/redis-description.vue | 112 + .../src/views/monitor/cache/index.vue | 139 + .../src/views/monitor/full-sync/index.test.ts | 373 + .../src/views/monitor/full-sync/index.vue | 862 + .../src/views/monitor/online/index.vue | 165 + .../src/views/monitor/server/index.vue | 1079 + .../api/components/ApiBrowserHeader.vue | 71 + .../system/api/components/ApiDetailTab.vue | 146 + .../api/components/ApiRequestTestTab.vue | 466 + .../system/api/components/ApiTreePanel.vue | 105 + .../components/ApiTypeBatchGenerateModal.vue | 443 + .../api/components/ApiTypeDefinitionTab.vue | 127 + .../api/components/ApiTypeGenerateModal.vue | 185 + .../system/api/composables/useApiBrowser.ts | 430 + .../src/views/system/api/constants.ts | 35 + .../web-antd/src/views/system/api/context.ts | 19 + .../web-antd/src/views/system/api/index.vue | 104 + .../web-antd/src/views/system/api/types.ts | 101 + .../src/views/system/api/utils/api-tree.ts | 183 + .../src/views/system/api/utils/schema.ts | 196 + .../views/system/api/utils/type-definition.ts | 567 + .../system/api/utils/type-generate-client.ts | 109 + .../src/views/system/client/edit-drawer.vue | 133 + .../src/views/system/client/index.vue | 210 + .../src/views/system/client/model.tsx | 258 + .../src/views/system/client/view-drawer.vue | 43 + .../src/views/system/config/config-drawer.vue | 122 + .../src/views/system/config/index.vue | 212 + .../web-antd/src/views/system/config/model.ts | 68 + .../src/views/system/dept/dept-drawer.vue | 219 + .../src/views/system/dept/dept-select.vue | 194 + .../web-antd/src/views/system/dept/index.vue | 256 + .../web-antd/src/views/system/dept/model.ts | 150 + .../views/system/dept/supplement-modal.vue | 211 + .../system/dict-data/dict-create-modal.vue | 358 + .../system/dict-data/dict-data-drawer.vue | 131 + .../src/views/system/dict-data/index.vue | 339 + .../src/views/system/dict-data/model.ts | 98 + .../src/views/system/dict-data/utils.ts | 32 + .../src/views/system/dict/dict-drawer.vue | 153 + .../web-antd/src/views/system/dict/index.vue | 278 + .../web-antd/src/views/system/dict/model.ts | 67 + .../UnitInformation/content.vue | 368 + .../UnitInformation/index.vue | 16 + .../realNameAuthentication/content.vue | 164 + .../tTplatformSetting/content.vue | 178 + .../src/views/system/job/edit-drawer.vue | 147 + .../web-antd/src/views/system/job/index.vue | 248 + .../src/views/system/job/job-cron-model.vue | 60 + .../web-antd/src/views/system/job/model.tsx | 160 + .../src/views/system/job/view-drawer.vue | 40 + .../src/views/system/logininfor/index.vue | 218 + .../src/views/system/logininfor/model.tsx | 133 + .../views/system/logininfor/view-drawer.vue | 39 + .../web-antd/src/views/system/menu/index.vue | 270 + .../src/views/system/menu/menu-drawer.vue | 183 + .../src/views/system/menu/menu-select.vue | 337 + .../web-antd/src/views/system/menu/model.ts | 265 + .../src/views/system/notice/index.vue | 255 + .../src/views/system/notice/model.tsx | 165 + .../src/views/system/notice/notice-drawer.vue | 224 + .../system/notice/selectDevice/index.vue | 334 + .../system/notice/selectDevice/model.tsx | 94 + .../web-antd/src/views/system/notice/view.vue | 83 + .../src/views/system/operlog/index.vue | 148 + .../src/views/system/operlog/model.tsx | 189 + .../src/views/system/operlog/view-drawer.vue | 39 + .../views/system/oss-config/edit-drawer.vue | 120 + .../src/views/system/oss-config/index.vue | 176 + .../src/views/system/oss-config/model.tsx | 328 + .../views/system/oss-config/view-drawer.vue | 43 + .../views/system/oss/file-upload-modal.vue | 52 + .../views/system/oss/image-upload-modal.vue | 51 + .../web-antd/src/views/system/oss/index.vue | 264 + .../web-antd/src/views/system/oss/model.tsx | 200 + .../web-antd/src/views/system/post/index.vue | 270 + .../web-antd/src/views/system/post/model.ts | 80 + .../src/views/system/post/post-drawer.vue | 153 + .../web-antd/src/views/system/role/index.vue | 262 + .../web-antd/src/views/system/role/model.ts | 153 + .../system/role/role-data-scope-modal.vue | 151 + .../src/views/system/role/role-drawer.vue | 200 + .../src/views/system/sysNoticeUser/edit.vue | 114 + .../src/views/system/sysNoticeUser/index.vue | 169 + .../src/views/system/sysNoticeUser/model.tsx | 301 + .../src/views/system/sysNoticeUser/view.vue | 31 + .../src/views/system/tenant/edit-drawer.vue | 139 + .../src/views/system/tenant/index.vue | 219 + .../src/views/system/tenant/model.tsx | 302 + .../src/views/system/tenant/view-drawer.vue | 41 + .../system/tenantPackage/edit-drawer.vue | 152 + .../src/views/system/tenantPackage/index.vue | 189 + .../src/views/system/tenantPackage/model.tsx | 109 + .../system/tenantPackage/view-drawer.vue | 42 + .../web-antd/src/views/system/user/index.vue | 276 + .../web-antd/src/views/system/user/model.ts | 133 + .../src/views/system/user/user-drawer.vue | 284 + .../system/user/user-reset-pwd-modal.vue | 112 + .../tool/gen/components/EditMasterCell.vue | 684 + .../tool/gen/components/EditSlaveCell.vue | 481 + .../views/tool/gen/components/PreviewTab.vue | 167 + .../web-antd/src/views/tool/gen/develop.vue | 380 + .../src/views/tool/gen/edit-drawer.vue | 149 + .../web-antd/src/views/tool/gen/index.vue | 193 + .../web-antd/src/views/tool/gen/model.tsx | 811 + .../src/views/tool/gen/view-drawer.vue | 41 + vue/apps/web-antd/tailwind.config.mjs | 1 + vue/apps/web-antd/tsconfig.json | 12 + vue/apps/web-antd/tsconfig.node.json | 10 + vue/apps/web-antd/vite.config.mts | 54 + vue/build/.dockerignore | 7 + vue/build/Dockerfile | 28 + vue/build/DockerfileNoBuild | 9 + vue/build/nginx.conf | 37 + vue/cspell.json | 70 + vue/eslint.config.mjs | 5 + vue/folder-alias.json | 200 + .../lint-configs/commitlint-config/index.mjs | 153 + .../commitlint-config/package.json | 33 + .../eslint-config/build.config.ts | 7 + .../lint-configs/eslint-config/package.json | 56 + .../eslint-config/src/configs/command.ts | 9 + .../eslint-config/src/configs/comments.ts | 24 + .../eslint-config/src/configs/disableds.ts | 28 + .../eslint-config/src/configs/ignores.ts | 52 + .../eslint-config/src/configs/import.ts | 25 + .../eslint-config/src/configs/index.ts | 17 + .../eslint-config/src/configs/javascript.ts | 241 + .../eslint-config/src/configs/jsdoc.ts | 34 + .../eslint-config/src/configs/jsonc.ts | 258 + .../eslint-config/src/configs/node.ts | 57 + .../src/configs/perfectionist.ts | 88 + .../eslint-config/src/configs/prettier.ts | 19 + .../eslint-config/src/configs/regexp.ts | 20 + .../eslint-config/src/configs/test.ts | 45 + .../eslint-config/src/configs/turbo.ts | 17 + .../eslint-config/src/configs/typescript.ts | 71 + .../eslint-config/src/configs/unicorn.ts | 45 + .../eslint-config/src/configs/vue.ts | 152 + .../eslint-config/src/custom-config.ts | 168 + .../lint-configs/eslint-config/src/index.ts | 60 + .../lint-configs/eslint-config/src/util.ts | 8 + .../lint-configs/eslint-config/tsconfig.json | 9 + .../lint-configs/prettier-config/index.mjs | 18 + .../lint-configs/prettier-config/package.json | 28 + .../lint-configs/stylelint-config/index.mjs | 141 + .../stylelint-config/package.json | 43 + vue/internal/node-utils/build.config.ts | 7 + vue/internal/node-utils/package.json | 43 + .../node-utils/src/__tests__/hash.test.ts | 52 + .../node-utils/src/__tests__/path.test.ts | 67 + vue/internal/node-utils/src/constants.ts | 6 + vue/internal/node-utils/src/date.ts | 12 + vue/internal/node-utils/src/fs.ts | 39 + vue/internal/node-utils/src/git.ts | 34 + vue/internal/node-utils/src/hash.ts | 18 + vue/internal/node-utils/src/index.ts | 19 + vue/internal/node-utils/src/monorepo.ts | 46 + vue/internal/node-utils/src/path.ts | 11 + vue/internal/node-utils/src/prettier.ts | 21 + vue/internal/node-utils/src/spinner.ts | 26 + vue/internal/node-utils/tsconfig.json | 6 + vue/internal/tailwind-config/build.config.ts | 10 + vue/internal/tailwind-config/package.json | 67 + vue/internal/tailwind-config/src/index.ts | 308 + vue/internal/tailwind-config/src/module.d.ts | 3 + .../tailwind-config/src/plugins/entry.ts | 53 + .../tailwind-config/src/postcss.config.ts | 15 + vue/internal/tailwind-config/tsconfig.json | 9 + vue/internal/tsconfig/base.json | 40 + vue/internal/tsconfig/library.json | 13 + vue/internal/tsconfig/node.json | 12 + vue/internal/tsconfig/package.json | 25 + vue/internal/tsconfig/web-app.json | 8 + vue/internal/tsconfig/web.json | 14 + vue/internal/vite-config/build.config.ts | 7 + vue/internal/vite-config/package.json | 59 + .../vite-config/src/config/application.ts | 125 + vue/internal/vite-config/src/config/common.ts | 13 + vue/internal/vite-config/src/config/index.ts | 37 + .../vite-config/src/config/library.ts | 59 + vue/internal/vite-config/src/index.ts | 4 + vue/internal/vite-config/src/options.ts | 45 + .../vite-config/src/plugins/archiver.ts | 75 + .../src/plugins/extra-app-config.ts | 92 + .../vite-config/src/plugins/importmap.ts | 245 + vue/internal/vite-config/src/plugins/index.ts | 247 + .../src/plugins/inject-app-loading/README.md | 3 + .../default-loading-antd.html | 107 + .../inject-app-loading/default-loading.html | 113 + .../src/plugins/inject-app-loading/index.ts | 66 + .../src/plugins/inject-metadata.ts | 111 + .../vite-config/src/plugins/license.ts | 63 + .../vite-config/src/plugins/nitro-mock.ts | 98 + vue/internal/vite-config/src/plugins/print.ts | 28 + .../vite-config/src/plugins/vxe-table.ts | 20 + vue/internal/vite-config/src/typing.ts | 343 + vue/internal/vite-config/src/utils/env.ts | 110 + vue/internal/vite-config/tsconfig.json | 6 + vue/lefthook.yml | 76 + vue/package.json | 124 + vue/packages/@core/README.md | 3 + vue/packages/@core/base/README.md | 5 + vue/packages/@core/base/design/package.json | 41 + .../@core/base/design/src/css/global.css | 161 + .../@core/base/design/src/css/nprogress.css | 59 + .../@core/base/design/src/css/transition.css | 236 + vue/packages/@core/base/design/src/css/ui.css | 101 + .../base/design/src/design-tokens/dark.css | 446 + .../base/design/src/design-tokens/default.css | 383 + .../base/design/src/design-tokens/index.ts | 2 + vue/packages/@core/base/design/src/index.ts | 6 + .../@core/base/design/src/scss-bem/bem.scss | 34 + .../base/design/src/scss-bem/constants.scss | 5 + vue/packages/@core/base/design/tsconfig.json | 6 + .../@core/base/design/vite.config.mts | 9 + vue/packages/@core/base/icons/build.config.ts | 7 + vue/packages/@core/base/icons/package.json | 41 + .../@core/base/icons/src/create-icon.ts | 24 + vue/packages/@core/base/icons/src/index.ts | 11 + vue/packages/@core/base/icons/src/lucide.ts | 69 + vue/packages/@core/base/icons/tsconfig.json | 6 + .../@core/base/shared/build.config.ts | 14 + vue/packages/@core/base/shared/package.json | 101 + .../cache/__tests__/storage-manager.test.ts | 130 + .../@core/base/shared/src/cache/index.ts | 1 + .../base/shared/src/cache/storage-manager.ts | 118 + .../@core/base/shared/src/cache/types.ts | 17 + .../src/color/__tests__/convert.test.ts | 58 + .../@core/base/shared/src/color/color.ts | 9 + .../@core/base/shared/src/color/convert.ts | 62 + .../@core/base/shared/src/color/generator.ts | 45 + .../@core/base/shared/src/color/index.ts | 3 + .../base/shared/src/constants/globals.ts | 16 + .../@core/base/shared/src/constants/index.ts | 2 + .../@core/base/shared/src/constants/vben.ts | 28 + .../@core/base/shared/src/global-state.ts | 45 + vue/packages/@core/base/shared/src/store.ts | 1 + .../shared/src/utils/__tests__/date.test.ts | 143 + .../shared/src/utils/__tests__/diff.test.ts | 53 + .../shared/src/utils/__tests__/dom.test.ts | 127 + .../src/utils/__tests__/inference.test.ts | 183 + .../shared/src/utils/__tests__/letter.test.ts | 116 + .../src/utils/__tests__/resources.test.ts | 82 + .../src/utils/__tests__/state-handler.test.ts | 60 + .../shared/src/utils/__tests__/tree.test.ts | 196 + .../shared/src/utils/__tests__/unique.test.ts | 60 + .../__tests__/update-css-variables.test.ts | 30 + .../shared/src/utils/__tests__/util.test.ts | 156 + .../shared/src/utils/__tests__/window.test.ts | 33 + .../@core/base/shared/src/utils/cn.ts | 10 + .../@core/base/shared/src/utils/date.ts | 75 + .../@core/base/shared/src/utils/diff.ts | 96 + .../@core/base/shared/src/utils/dom.ts | 95 + .../@core/base/shared/src/utils/download.ts | 157 + .../@core/base/shared/src/utils/index.ts | 20 + .../@core/base/shared/src/utils/inference.ts | 165 + .../@core/base/shared/src/utils/letter.ts | 47 + .../@core/base/shared/src/utils/merge.ts | 10 + .../@core/base/shared/src/utils/nprogress.ts | 43 + .../@core/base/shared/src/utils/resources.ts | 21 + .../base/shared/src/utils/state-handler.ts | 50 + .../@core/base/shared/src/utils/to.ts | 21 + .../@core/base/shared/src/utils/tree.ts | 125 + .../@core/base/shared/src/utils/unique.ts | 15 + .../shared/src/utils/update-css-variables.ts | 35 + .../@core/base/shared/src/utils/util.ts | 44 + .../@core/base/shared/src/utils/window.ts | 37 + vue/packages/@core/base/shared/tsconfig.json | 6 + .../@core/base/typings/build.config.ts | 7 + vue/packages/@core/base/typings/package.json | 44 + vue/packages/@core/base/typings/src/app.d.ts | 121 + .../@core/base/typings/src/basic.d.ts | 35 + .../@core/base/typings/src/helper.d.ts | 132 + vue/packages/@core/base/typings/src/index.ts | 6 + .../@core/base/typings/src/menu-record.ts | 76 + vue/packages/@core/base/typings/src/tabs.ts | 8 + .../@core/base/typings/src/vue-router.d.ts | 153 + vue/packages/@core/base/typings/tsconfig.json | 6 + .../@core/base/typings/vue-router.d.ts | 9 + .../@core/composables/build.config.ts | 7 + vue/packages/@core/composables/package.json | 47 + .../src/__tests__/use-sortable.test.ts | 48 + vue/packages/@core/composables/src/index.ts | 13 + .../@core/composables/src/use-is-mobile.ts | 7 + .../@core/composables/src/use-layout-style.ts | 87 + .../@core/composables/src/use-namespace.ts | 106 + .../composables/src/use-priority-value.ts | 94 + .../@core/composables/src/use-scroll-lock.ts | 54 + .../src/use-simple-locale/README.md | 3 + .../src/use-simple-locale/index.ts | 27 + .../src/use-simple-locale/messages.ts | 24 + .../@core/composables/src/use-sortable.ts | 29 + vue/packages/@core/composables/tsconfig.json | 6 + .../__snapshots__/config.test.ts.snap | 140 + .../preferences/__tests__/config.test.ts | 10 + .../preferences/__tests__/preferences.test.ts | 253 + .../@core/preferences/build.config.ts | 7 + vue/packages/@core/preferences/package.json | 37 + vue/packages/@core/preferences/src/config.ts | 142 + .../@core/preferences/src/constants.ts | 119 + vue/packages/@core/preferences/src/index.ts | 35 + .../@core/preferences/src/preferences.ts | 234 + vue/packages/@core/preferences/src/types.ts | 338 + .../preferences/src/update-css-variables.ts | 129 + .../@core/preferences/src/use-preferences.ts | 254 + vue/packages/@core/preferences/tsconfig.json | 6 + vue/packages/@core/ui-kit/README.md | 3 + .../form-ui/__tests__/expandable.test.ts | 56 + .../ui-kit/form-ui/__tests__/form-api.test.ts | 189 + .../@core/ui-kit/form-ui/build.config.ts | 21 + .../@core/ui-kit/form-ui/package.json | 52 + .../@core/ui-kit/form-ui/postcss.config.mjs | 1 + .../form-ui/src/components/form-actions.vue | 197 + .../@core/ui-kit/form-ui/src/config.ts | 87 + .../@core/ui-kit/form-ui/src/form-api.ts | 597 + .../ui-kit/form-ui/src/form-render/context.ts | 24 + .../form-ui/src/form-render/dependencies.ts | 124 + .../form-ui/src/form-render/expandable.ts | 159 + .../form-ui/src/form-render/form-field.vue | 395 + .../form-ui/src/form-render/form-label.vue | 31 + .../ui-kit/form-ui/src/form-render/form.vue | 193 + .../ui-kit/form-ui/src/form-render/helper.ts | 60 + .../ui-kit/form-ui/src/form-render/index.ts | 3 + .../@core/ui-kit/form-ui/src/index.ts | 12 + .../@core/ui-kit/form-ui/src/types.ts | 464 + .../ui-kit/form-ui/src/use-form-context.ts | 109 + .../@core/ui-kit/form-ui/src/use-vben-form.ts | 50 + .../@core/ui-kit/form-ui/src/vben-form.vue | 80 + .../ui-kit/form-ui/src/vben-use-form.vue | 152 + .../@core/ui-kit/form-ui/tailwind.config.mjs | 1 + .../@core/ui-kit/form-ui/tsconfig.json | 6 + .../@core/ui-kit/layout-ui/build.config.ts | 21 + .../@core/ui-kit/layout-ui/package.json | 48 + .../@core/ui-kit/layout-ui/postcss.config.mjs | 1 + .../ui-kit/layout-ui/src/components/index.ts | 5 + .../src/components/layout-content.vue | 64 + .../src/components/layout-footer.vue | 44 + .../src/components/layout-header.vue | 77 + .../src/components/layout-sidebar.vue | 322 + .../src/components/layout-tabbar.vue | 30 + .../layout-ui/src/components/widgets/index.ts | 2 + .../widgets/sidebar-collapse-button.vue | 19 + .../widgets/sidebar-fixed-button.vue | 19 + .../ui-kit/layout-ui/src/hooks/use-layout.ts | 53 + .../@core/ui-kit/layout-ui/src/index.ts | 2 + .../@core/ui-kit/layout-ui/src/vben-layout.ts | 175 + .../ui-kit/layout-ui/src/vben-layout.vue | 617 + .../ui-kit/layout-ui/tailwind.config.mjs | 1 + .../@core/ui-kit/layout-ui/tsconfig.json | 6 + vue/packages/@core/ui-kit/menu-ui/README.md | 1 + .../@core/ui-kit/menu-ui/build.config.ts | 26 + .../@core/ui-kit/menu-ui/package.json | 48 + .../@core/ui-kit/menu-ui/postcss.config.mjs | 1 + .../src/components/collapse-transition.vue | 96 + .../ui-kit/menu-ui/src/components/index.ts | 4 + .../menu-ui/src/components/menu-badge-dot.vue | 28 + .../menu-ui/src/components/menu-badge.vue | 57 + .../menu-ui/src/components/menu-item.vue | 122 + .../ui-kit/menu-ui/src/components/menu.vue | 877 + .../src/components/normal-menu/index.ts | 2 + .../src/components/normal-menu/normal-menu.ts | 27 + .../components/normal-menu/normal-menu.vue | 161 + .../src/components/sub-menu-content.vue | 105 + .../menu-ui/src/components/sub-menu.vue | 275 + .../@core/ui-kit/menu-ui/src/hooks/index.ts | 2 + .../menu-ui/src/hooks/use-menu-context.ts | 55 + .../menu-ui/src/hooks/use-menu-scroll.ts | 46 + .../ui-kit/menu-ui/src/hooks/use-menu.ts | 48 + .../@core/ui-kit/menu-ui/src/index.ts | 4 + .../@core/ui-kit/menu-ui/src/menu.vue | 32 + .../@core/ui-kit/menu-ui/src/sub-menu.vue | 71 + .../@core/ui-kit/menu-ui/src/types.ts | 145 + .../@core/ui-kit/menu-ui/src/utils/index.ts | 52 + .../@core/ui-kit/menu-ui/tailwind.config.mjs | 1 + .../@core/ui-kit/menu-ui/tsconfig.json | 6 + .../@core/ui-kit/popup-ui/build.config.ts | 21 + .../@core/ui-kit/popup-ui/package.json | 48 + .../@core/ui-kit/popup-ui/postcss.config.mjs | 1 + .../ui-kit/popup-ui/src/alert/AlertBuilder.ts | 246 + .../@core/ui-kit/popup-ui/src/alert/alert.ts | 99 + .../@core/ui-kit/popup-ui/src/alert/alert.vue | 210 + .../@core/ui-kit/popup-ui/src/alert/index.ts | 14 + .../src/drawer/__tests__/drawer-api.test.ts | 116 + .../ui-kit/popup-ui/src/drawer/drawer-api.ts | 183 + .../ui-kit/popup-ui/src/drawer/drawer.ts | 179 + .../ui-kit/popup-ui/src/drawer/drawer.vue | 332 + .../@core/ui-kit/popup-ui/src/drawer/index.ts | 3 + .../ui-kit/popup-ui/src/drawer/use-drawer.ts | 142 + .../@core/ui-kit/popup-ui/src/index.ts | 3 + .../src/modal/__tests__/modal-api.test.ts | 117 + .../@core/ui-kit/popup-ui/src/modal/index.ts | 3 + .../ui-kit/popup-ui/src/modal/modal-api.ts | 196 + .../@core/ui-kit/popup-ui/src/modal/modal.ts | 194 + .../@core/ui-kit/popup-ui/src/modal/modal.vue | 371 + .../popup-ui/src/modal/use-modal-draggable.ts | 138 + .../ui-kit/popup-ui/src/modal/use-modal.ts | 151 + .../@core/ui-kit/popup-ui/tailwind.config.mjs | 1 + .../@core/ui-kit/popup-ui/tsconfig.json | 6 + .../@core/ui-kit/shadcn-ui/build.config.ts | 27 + .../@core/ui-kit/shadcn-ui/components.json | 16 + .../@core/ui-kit/shadcn-ui/package.json | 54 + .../@core/ui-kit/shadcn-ui/postcss.config.mjs | 1 + .../src/components/avatar/avatar.vue | 76 + .../shadcn-ui/src/components/avatar/index.ts | 1 + .../src/components/back-top/back-top.vue | 43 + .../src/components/back-top/backtop.ts | 38 + .../src/components/back-top/index.ts | 1 + .../src/components/back-top/use-backtop.ts | 45 + .../breadcrumb/breadcrumb-background.vue | 109 + .../components/breadcrumb/breadcrumb-view.vue | 39 + .../src/components/breadcrumb/breadcrumb.vue | 98 + .../src/components/breadcrumb/index.ts | 3 + .../src/components/breadcrumb/types.ts | 17 + .../src/components/button/button-group.vue | 98 + .../shadcn-ui/src/components/button/button.ts | 53 + .../src/components/button/button.vue | 42 + .../components/button/check-button-group.vue | 196 + .../src/components/button/icon-button.vue | 68 + .../shadcn-ui/src/components/button/index.ts | 5 + .../src/components/checkbox/checkbox.vue | 26 + .../src/components/checkbox/index.ts | 1 + .../components/context-menu/context-menu.vue | 98 + .../src/components/context-menu/index.ts | 3 + .../src/components/context-menu/interface.ts | 42 + .../count-to-animator/count-to-animator.vue | 128 + .../src/components/count-to-animator/index.ts | 1 + .../dropdown-menu/dropdown-menu.vue | 49 + .../dropdown-menu/dropdown-radio-menu.vue | 52 + .../src/components/dropdown-menu/index.ts | 4 + .../src/components/dropdown-menu/interface.ts | 32 + .../expandable-arrow/expandable-arrow.vue | 31 + .../src/components/expandable-arrow/index.ts | 1 + .../components/full-screen/full-screen.vue | 31 + .../src/components/full-screen/index.ts | 1 + .../src/components/hover-card/hover-card.vue | 55 + .../src/components/hover-card/index.ts | 2 + .../shadcn-ui/src/components/icon/icon.vue | 35 + .../shadcn-ui/src/components/icon/index.ts | 1 + .../ui-kit/shadcn-ui/src/components/index.ts | 23 + .../src/components/input-password/index.ts | 1 + .../input-password/input-password.vue | 57 + .../input-password/password-strength.vue | 66 + .../shadcn-ui/src/components/logo/index.ts | 1 + .../shadcn-ui/src/components/logo/logo.vue | 92 + .../src/components/pin-input/index.ts | 3 + .../src/components/pin-input/input.vue | 122 + .../src/components/pin-input/types.ts | 30 + .../shadcn-ui/src/components/popover/index.ts | 1 + .../src/components/popover/popover.vue | 60 + .../src/components/render-content/index.ts | 1 + .../render-content/render-content.vue | 56 + .../src/components/scrollbar/index.ts | 1 + .../src/components/scrollbar/scrollbar.vue | 165 + .../src/components/segmented/index.ts | 3 + .../src/components/segmented/segmented.vue | 67 + .../components/segmented/tabs-indicator.vue | 37 + .../src/components/segmented/types.ts | 6 + .../shadcn-ui/src/components/select/index.ts | 1 + .../src/components/select/select.vue | 57 + .../src/components/spine-text/index.ts | 1 + .../src/components/spine-text/spine-text.vue | 49 + .../shadcn-ui/src/components/spinner/index.ts | 2 + .../src/components/spinner/loading.vue | 140 + .../src/components/spinner/spinner.vue | 137 + .../src/components/tooltip/help-tooltip.vue | 31 + .../shadcn-ui/src/components/tooltip/index.ts | 2 + .../src/components/tooltip/tooltip.vue | 44 + .../@core/ui-kit/shadcn-ui/src/index.ts | 3 + .../shadcn-ui/src/ui/accordion/Accordion.vue | 16 + .../src/ui/accordion/AccordionContent.vue | 28 + .../src/ui/accordion/AccordionItem.vue | 25 + .../src/ui/accordion/AccordionTrigger.vue | 39 + .../shadcn-ui/src/ui/accordion/index.ts | 4 + .../src/ui/alert-dialog/AlertDialog.vue | 16 + .../src/ui/alert-dialog/AlertDialogAction.vue | 13 + .../src/ui/alert-dialog/AlertDialogCancel.vue | 13 + .../ui/alert-dialog/AlertDialogContent.vue | 98 + .../alert-dialog/AlertDialogDescription.vue | 28 + .../ui/alert-dialog/AlertDialogOverlay.vue | 8 + .../src/ui/alert-dialog/AlertDialogTitle.vue | 30 + .../shadcn-ui/src/ui/alert-dialog/index.ts | 6 + .../ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue | 27 + .../src/ui/avatar/AvatarFallback.vue | 13 + .../shadcn-ui/src/ui/avatar/AvatarImage.vue | 11 + .../ui-kit/shadcn-ui/src/ui/avatar/avatar.ts | 22 + .../ui-kit/shadcn-ui/src/ui/avatar/index.ts | 4 + .../ui-kit/shadcn-ui/src/ui/badge/Badge.vue | 18 + .../ui-kit/shadcn-ui/src/ui/badge/badge.ts | 25 + .../ui-kit/shadcn-ui/src/ui/badge/index.ts | 3 + .../src/ui/breadcrumb/Breadcrumb.vue | 11 + .../src/ui/breadcrumb/BreadcrumbEllipsis.vue | 22 + .../src/ui/breadcrumb/BreadcrumbItem.vue | 17 + .../src/ui/breadcrumb/BreadcrumbLink.vue | 21 + .../src/ui/breadcrumb/BreadcrumbList.vue | 20 + .../src/ui/breadcrumb/BreadcrumbPage.vue | 18 + .../src/ui/breadcrumb/BreadcrumbSeparator.vue | 21 + .../shadcn-ui/src/ui/breadcrumb/index.ts | 7 + .../ui-kit/shadcn-ui/src/ui/button/Button.vue | 32 + .../ui-kit/shadcn-ui/src/ui/button/button.ts | 34 + .../ui-kit/shadcn-ui/src/ui/button/index.ts | 5 + .../ui-kit/shadcn-ui/src/ui/button/types.ts | 20 + .../ui-kit/shadcn-ui/src/ui/card/Card.vue | 20 + .../shadcn-ui/src/ui/card/CardContent.vue | 13 + .../shadcn-ui/src/ui/card/CardDescription.vue | 13 + .../shadcn-ui/src/ui/card/CardFooter.vue | 13 + .../shadcn-ui/src/ui/card/CardHeader.vue | 13 + .../shadcn-ui/src/ui/card/CardTitle.vue | 13 + .../ui-kit/shadcn-ui/src/ui/card/index.ts | 6 + .../shadcn-ui/src/ui/checkbox/Checkbox.vue | 43 + .../ui-kit/shadcn-ui/src/ui/checkbox/index.ts | 1 + .../src/ui/context-menu/ContextMenu.vue | 18 + .../context-menu/ContextMenuCheckboxItem.vue | 47 + .../ui/context-menu/ContextMenuContent.vue | 40 + .../src/ui/context-menu/ContextMenuGroup.vue | 13 + .../src/ui/context-menu/ContextMenuItem.vue | 37 + .../src/ui/context-menu/ContextMenuLabel.vue | 34 + .../src/ui/context-menu/ContextMenuPortal.vue | 13 + .../ui/context-menu/ContextMenuRadioGroup.vue | 19 + .../ui/context-menu/ContextMenuRadioItem.vue | 47 + .../ui/context-menu/ContextMenuSeparator.vue | 24 + .../ui/context-menu/ContextMenuShortcut.vue | 17 + .../src/ui/context-menu/ContextMenuSub.vue | 16 + .../ui/context-menu/ContextMenuSubContent.vue | 44 + .../ui/context-menu/ContextMenuSubTrigger.vue | 41 + .../ui/context-menu/ContextMenuTrigger.vue | 15 + .../shadcn-ui/src/ui/context-menu/index.ts | 14 + .../ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue | 16 + .../shadcn-ui/src/ui/dialog/DialogClose.vue | 13 + .../shadcn-ui/src/ui/dialog/DialogContent.vue | 131 + .../src/ui/dialog/DialogDescription.vue | 28 + .../shadcn-ui/src/ui/dialog/DialogFooter.vue | 15 + .../shadcn-ui/src/ui/dialog/DialogHeader.vue | 15 + .../shadcn-ui/src/ui/dialog/DialogOverlay.vue | 11 + .../src/ui/dialog/DialogScrollContent.vue | 71 + .../shadcn-ui/src/ui/dialog/DialogTitle.vue | 30 + .../shadcn-ui/src/ui/dialog/DialogTrigger.vue | 13 + .../ui-kit/shadcn-ui/src/ui/dialog/index.ts | 9 + .../src/ui/dropdown-menu/DropdownMenu.vue | 18 + .../DropdownMenuCheckboxItem.vue | 47 + .../ui/dropdown-menu/DropdownMenuContent.vue | 48 + .../ui/dropdown-menu/DropdownMenuGroup.vue | 13 + .../src/ui/dropdown-menu/DropdownMenuItem.vue | 36 + .../ui/dropdown-menu/DropdownMenuLabel.vue | 32 + .../dropdown-menu/DropdownMenuRadioGroup.vue | 19 + .../dropdown-menu/DropdownMenuRadioItem.vue | 48 + .../dropdown-menu/DropdownMenuSeparator.vue | 28 + .../ui/dropdown-menu/DropdownMenuShortcut.vue | 13 + .../src/ui/dropdown-menu/DropdownMenuSub.vue | 16 + .../dropdown-menu/DropdownMenuSubContent.vue | 44 + .../dropdown-menu/DropdownMenuSubTrigger.vue | 35 + .../ui/dropdown-menu/DropdownMenuTrigger.vue | 15 + .../shadcn-ui/src/ui/dropdown-menu/index.ts | 16 + .../shadcn-ui/src/ui/form/FormControl.vue | 19 + .../shadcn-ui/src/ui/form/FormDescription.vue | 20 + .../ui-kit/shadcn-ui/src/ui/form/FormItem.vue | 20 + .../shadcn-ui/src/ui/form/FormLabel.vue | 18 + .../shadcn-ui/src/ui/form/FormMessage.vue | 18 + .../ui-kit/shadcn-ui/src/ui/form/index.ts | 11 + .../shadcn-ui/src/ui/form/injectionKeys.ts | 4 + .../shadcn-ui/src/ui/form/useFormField.ts | 38 + .../shadcn-ui/src/ui/hover-card/HoverCard.vue | 16 + .../src/ui/hover-card/HoverCardContent.vue | 40 + .../src/ui/hover-card/HoverCardTrigger.vue | 13 + .../shadcn-ui/src/ui/hover-card/index.ts | 3 + .../@core/ui-kit/shadcn-ui/src/ui/index.ts | 31 + .../ui-kit/shadcn-ui/src/ui/input/Input.vue | 37 + .../ui-kit/shadcn-ui/src/ui/input/index.ts | 1 + .../ui-kit/shadcn-ui/src/ui/label/Label.vue | 31 + .../ui-kit/shadcn-ui/src/ui/label/index.ts | 1 + .../src/ui/number-field/NumberField.vue | 26 + .../ui/number-field/NumberFieldContent.vue | 20 + .../ui/number-field/NumberFieldDecrement.vue | 37 + .../ui/number-field/NumberFieldIncrement.vue | 37 + .../src/ui/number-field/NumberFieldInput.vue | 16 + .../shadcn-ui/src/ui/number-field/index.ts | 5 + .../src/ui/pagination/PaginationEllipsis.vue | 29 + .../src/ui/pagination/PaginationFirst.vue | 35 + .../src/ui/pagination/PaginationLast.vue | 35 + .../src/ui/pagination/PaginationNext.vue | 35 + .../src/ui/pagination/PaginationPrev.vue | 35 + .../shadcn-ui/src/ui/pagination/index.ts | 10 + .../shadcn-ui/src/ui/pin-input/PinInput.vue | 28 + .../src/ui/pin-input/PinInputGroup.vue | 25 + .../src/ui/pin-input/PinInputInput.vue | 30 + .../src/ui/pin-input/PinInputSeparator.vue | 17 + .../shadcn-ui/src/ui/pin-input/index.ts | 4 + .../shadcn-ui/src/ui/popover/Popover.vue | 16 + .../src/ui/popover/PopoverContent.vue | 46 + .../src/ui/popover/PopoverTrigger.vue | 13 + .../ui-kit/shadcn-ui/src/ui/popover/index.ts | 4 + .../src/ui/radio-group/RadioGroup.vue | 26 + .../src/ui/radio-group/RadioGroupItem.vue | 36 + .../shadcn-ui/src/ui/radio-group/index.ts | 2 + .../src/ui/resizable/ResizableHandle.vue | 50 + .../src/ui/resizable/ResizablePanelGroup.vue | 37 + .../shadcn-ui/src/ui/resizable/index.ts | 3 + .../src/ui/scroll-area/ScrollArea.vue | 46 + .../src/ui/scroll-area/ScrollBar.vue | 40 + .../shadcn-ui/src/ui/scroll-area/index.ts | 2 + .../ui-kit/shadcn-ui/src/ui/select/Select.vue | 16 + .../shadcn-ui/src/ui/select/SelectContent.vue | 67 + .../shadcn-ui/src/ui/select/SelectGroup.vue | 23 + .../shadcn-ui/src/ui/select/SelectItem.vue | 47 + .../src/ui/select/SelectItemText.vue | 13 + .../shadcn-ui/src/ui/select/SelectLabel.vue | 15 + .../src/ui/select/SelectScrollDownButton.vue | 33 + .../src/ui/select/SelectScrollUpButton.vue | 33 + .../src/ui/select/SelectSeparator.vue | 24 + .../shadcn-ui/src/ui/select/SelectTrigger.vue | 37 + .../shadcn-ui/src/ui/select/SelectValue.vue | 13 + .../ui-kit/shadcn-ui/src/ui/select/index.ts | 11 + .../shadcn-ui/src/ui/separator/Separator.vue | 44 + .../shadcn-ui/src/ui/separator/index.ts | 1 + .../ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue | 16 + .../shadcn-ui/src/ui/sheet/SheetClose.vue | 13 + .../shadcn-ui/src/ui/sheet/SheetContent.vue | 107 + .../src/ui/sheet/SheetDescription.vue | 26 + .../shadcn-ui/src/ui/sheet/SheetFooter.vue | 15 + .../shadcn-ui/src/ui/sheet/SheetHeader.vue | 11 + .../shadcn-ui/src/ui/sheet/SheetOverlay.vue | 11 + .../shadcn-ui/src/ui/sheet/SheetTitle.vue | 26 + .../shadcn-ui/src/ui/sheet/SheetTrigger.vue | 13 + .../ui-kit/shadcn-ui/src/ui/sheet/index.ts | 10 + .../ui-kit/shadcn-ui/src/ui/sheet/sheet.ts | 24 + .../ui-kit/shadcn-ui/src/ui/switch/Switch.vue | 41 + .../ui-kit/shadcn-ui/src/ui/switch/index.ts | 1 + .../ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue | 16 + .../shadcn-ui/src/ui/tabs/TabsContent.vue | 31 + .../ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue | 31 + .../shadcn-ui/src/ui/tabs/TabsTrigger.vue | 33 + .../ui-kit/shadcn-ui/src/ui/tabs/index.ts | 5 + .../shadcn-ui/src/ui/textarea/Textarea.vue | 32 + .../ui-kit/shadcn-ui/src/ui/textarea/index.ts | 1 + .../src/ui/toggle-group/ToggleGroup.vue | 44 + .../src/ui/toggle-group/ToggleGroupItem.vue | 48 + .../shadcn-ui/src/ui/toggle-group/index.ts | 2 + .../ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue | 47 + .../ui-kit/shadcn-ui/src/ui/toggle/index.ts | 2 + .../ui-kit/shadcn-ui/src/ui/toggle/toggle.ts | 27 + .../shadcn-ui/src/ui/tooltip/Tooltip.vue | 16 + .../src/ui/tooltip/TooltipContent.vue | 48 + .../src/ui/tooltip/TooltipProvider.vue | 13 + .../src/ui/tooltip/TooltipTrigger.vue | 13 + .../ui-kit/shadcn-ui/src/ui/tooltip/index.ts | 4 + .../ui-kit/shadcn-ui/src/ui/tree/index.ts | 4 + .../ui-kit/shadcn-ui/src/ui/tree/tree.vue | 467 + .../ui-kit/shadcn-ui/src/ui/tree/types.ts | 62 + .../ui-kit/shadcn-ui/tailwind.config.mjs | 1 + .../@core/ui-kit/shadcn-ui/tsconfig.json | 12 + .../@core/ui-kit/tabs-ui/build.config.ts | 21 + .../@core/ui-kit/tabs-ui/package.json | 47 + .../@core/ui-kit/tabs-ui/postcss.config.mjs | 1 + .../ui-kit/tabs-ui/src/components/index.ts | 2 + .../src/components/tabs-chrome/tabs.vue | 209 + .../tabs-ui/src/components/tabs/tabs.vue | 148 + .../tabs-ui/src/components/widgets/index.ts | 2 + .../src/components/widgets/tool-more.vue | 18 + .../src/components/widgets/tool-screen.vue | 19 + .../@core/ui-kit/tabs-ui/src/index.ts | 3 + .../@core/ui-kit/tabs-ui/src/tabs-view.vue | 106 + .../@core/ui-kit/tabs-ui/src/types.ts | 73 + .../@core/ui-kit/tabs-ui/src/use-tabs-drag.ts | 124 + .../tabs-ui/src/use-tabs-view-scroll.ts | 202 + .../@core/ui-kit/tabs-ui/tailwind.config.mjs | 1 + .../@core/ui-kit/tabs-ui/tsconfig.json | 6 + vue/packages/constants/README.md | 19 + vue/packages/constants/package.json | 25 + vue/packages/constants/src/core.ts | 29 + vue/packages/constants/src/dict-enum.ts | 23 + vue/packages/constants/src/index.ts | 3 + vue/packages/constants/tsconfig.json | 6 + vue/packages/effects/README.md | 10 + vue/packages/effects/access/package.json | 29 + .../effects/access/src/access-control.vue | 47 + vue/packages/effects/access/src/accessible.ts | 156 + vue/packages/effects/access/src/directive.ts | 42 + vue/packages/effects/access/src/index.ts | 4 + vue/packages/effects/access/src/use-access.ts | 53 + vue/packages/effects/access/tsconfig.json | 6 + vue/packages/effects/common-ui/package.json | 54 + .../api-component/api-component.vue | 299 + .../src/components/api-component/index.ts | 1 + .../captcha/hooks/useCaptchaPoints.ts | 19 + .../captcha/image-captcha/index.vue | 1 + .../common-ui/src/components/captcha/index.ts | 7 + .../captcha/point-selection-captcha/index.vue | 176 + .../point-selection-captcha-card.vue | 84 + .../captcha/slider-captcha/index.vue | 244 + .../slider-captcha/slider-captcha-action.vue | 65 + .../slider-captcha/slider-captcha-bar.vue | 40 + .../slider-captcha/slider-captcha-content.vue | 53 + .../captcha/slider-rotate-captcha/index.vue | 213 + .../slider-translate-captcha/index.vue | 311 + .../common-ui/src/components/captcha/types.ts | 211 + .../src/components/col-page/col-page.vue | 107 + .../src/components/col-page/index.ts | 2 + .../src/components/col-page/types.ts | 26 + .../src/components/count-to/count-to.vue | 123 + .../src/components/count-to/index.ts | 2 + .../src/components/count-to/types.ts | 53 + .../ellipsis-text/ellipsis-text.vue | 232 + .../src/components/ellipsis-text/index.ts | 1 + .../components/icon-picker/icon-picker.vue | 318 + .../src/components/icon-picker/icons.ts | 56 + .../src/components/icon-picker/index.ts | 1 + .../effects/common-ui/src/components/index.ts | 35 + .../src/components/json-preview/index.ts | 1 + .../components/json-preview/json-preview.vue | 19 + .../src/components/json-viewer/index.ts | 3 + .../src/components/json-viewer/index.vue | 112 + .../src/components/json-viewer/style.scss | 98 + .../src/components/json-viewer/types.ts | 44 + .../src/components/loading/directive.ts | 132 + .../common-ui/src/components/loading/index.ts | 3 + .../src/components/loading/loading.vue | 39 + .../src/components/loading/spinner.vue | 28 + .../components/page/__tests__/page.test.ts | 89 + .../common-ui/src/components/page/index.ts | 2 + .../common-ui/src/components/page/page.vue | 100 + .../common-ui/src/components/page/types.ts | 17 + .../common-ui/src/components/resize/index.ts | 1 + .../src/components/resize/resize.vue | 1120 + .../src/components/tippy/directive.ts | 100 + .../common-ui/src/components/tippy/index.ts | 67 + .../common-ui/src/components/tree/index.ts | 1 + .../common-ui/src/components/tree/tree.vue | 25 + vue/packages/effects/common-ui/src/index.ts | 2 + .../effects/common-ui/src/ui/about/about.ts | 14 + .../effects/common-ui/src/ui/about/about.vue | 183 + .../effects/common-ui/src/ui/about/index.ts | 1 + .../src/ui/authentication/auth-title.vue | 13 + .../src/ui/authentication/code-login.vue | 127 + .../src/ui/authentication/dingding-login.vue | 113 + .../src/ui/authentication/forget-password.vue | 116 + .../common-ui/src/ui/authentication/index.ts | 7 + .../ui/authentication/login-expired-modal.vue | 95 + .../common-ui/src/ui/authentication/login.vue | 186 + .../src/ui/authentication/qrcode-login.vue | 105 + .../src/ui/authentication/register.vue | 121 + .../ui/authentication/third-party-login.vue | 71 + .../common-ui/src/ui/authentication/types.ts | 70 + .../analysis/analysis-chart-card.vue | 24 + .../analysis/analysis-charts-tabs.vue | 40 + .../dashboard/analysis/analysis-overview.vue | 55 + .../src/ui/dashboard/analysis/index.ts | 3 + .../common-ui/src/ui/dashboard/index.ts | 3 + .../common-ui/src/ui/dashboard/typing.ts | 48 + .../src/ui/dashboard/workbench/index.ts | 5 + .../dashboard/workbench/workbench-header.vue | 46 + .../dashboard/workbench/workbench-project.vue | 65 + .../workbench/workbench-quick-nav.vue | 56 + .../ui/dashboard/workbench/workbench-todo.vue | 63 + .../dashboard/workbench/workbench-trends.vue | 64 + .../common-ui/src/ui/fallback/fallback.ts | 25 + .../common-ui/src/ui/fallback/fallback.vue | 164 + .../src/ui/fallback/icons/icon-403.vue | 151 + .../src/ui/fallback/icons/icon-404.vue | 154 + .../src/ui/fallback/icons/icon-500.vue | 215 + .../ui/fallback/icons/icon-coming-soon.vue | 262 + .../src/ui/fallback/icons/icon-offline.vue | 112 + .../src/ui/fallback/icons/warning.svg | 1 + .../common-ui/src/ui/fallback/index.ts | 2 + .../effects/common-ui/src/ui/index.ts | 5 + .../common-ui/src/ui/profile/base-setting.vue | 56 + .../effects/common-ui/src/ui/profile/index.ts | 6 + .../src/ui/profile/notification-setting.vue | 53 + .../src/ui/profile/password-setting.vue | 56 + .../common-ui/src/ui/profile/profile.vue | 62 + .../src/ui/profile/security-setting.vue | 53 + .../effects/common-ui/src/ui/profile/types.ts | 21 + vue/packages/effects/common-ui/tsconfig.json | 6 + vue/packages/effects/hooks/README.md | 19 + vue/packages/effects/hooks/package.json | 33 + vue/packages/effects/hooks/src/index.ts | 9 + .../effects/hooks/src/use-app-config.ts | 36 + .../effects/hooks/src/use-content-maximize.ts | 24 + .../effects/hooks/src/use-design-tokens.ts | 321 + .../effects/hooks/src/use-hover-toggle.ts | 163 + .../effects/hooks/src/use-pagination.ts | 72 + vue/packages/effects/hooks/src/use-refresh.ts | 16 + vue/packages/effects/hooks/src/use-tabs.ts | 133 + .../effects/hooks/src/use-watermark.ts | 84 + vue/packages/effects/hooks/tsconfig.json | 9 + vue/packages/effects/layouts/package.json | 43 + .../src/authentication/authentication.vue | 196 + .../layouts/src/authentication/form.vue | 38 + .../src/authentication/icons/slogan.vue | 4568 ++++ .../layouts/src/authentication/index.ts | 2 + .../layouts/src/authentication/toolbar.vue | 49 + .../layouts/src/authentication/types.ts | 1 + .../effects/layouts/src/basic/README.md | 7 + .../src/basic/content/content-spinner.vue | 12 + .../layouts/src/basic/content/content.vue | 148 + .../layouts/src/basic/content/index.ts | 2 + .../src/basic/content/use-content-spinner.ts | 50 + .../layouts/src/basic/copyright/copyright.vue | 48 + .../layouts/src/basic/copyright/index.ts | 1 + .../layouts/src/basic/footer/footer.vue | 11 + .../effects/layouts/src/basic/footer/index.ts | 1 + .../layouts/src/basic/header/header.vue | 195 + .../effects/layouts/src/basic/header/index.ts | 1 + .../effects/layouts/src/basic/index.ts | 1 + .../effects/layouts/src/basic/layout.vue | 412 + .../layouts/src/basic/menu/extra-menu.vue | 41 + .../effects/layouts/src/basic/menu/index.ts | 5 + .../effects/layouts/src/basic/menu/menu.vue | 45 + .../layouts/src/basic/menu/mixed-menu.vue | 46 + .../layouts/src/basic/menu/use-extra-menu.ts | 133 + .../layouts/src/basic/menu/use-mixed-menu.ts | 172 + .../layouts/src/basic/menu/use-navigation.ts | 74 + .../effects/layouts/src/basic/tabbar/index.ts | 2 + .../layouts/src/basic/tabbar/tabbar.vue | 75 + .../layouts/src/basic/tabbar/use-tabbar.ts | 227 + .../layouts/src/iframe/iframe-router-view.vue | 86 + .../layouts/src/iframe/iframe-view.vue | 3 + .../effects/layouts/src/iframe/index.ts | 2 + vue/packages/effects/layouts/src/index.ts | 4 + .../layouts/src/widgets/breadcrumb.vue | 74 + .../widgets/check-updates/check-updates.vue | 136 + .../src/widgets/check-updates/index.ts | 1 + .../layouts/src/widgets/color-toggle.vue | 64 + .../widgets/global-search/global-search.vue | 157 + .../src/widgets/global-search/index.ts | 1 + .../widgets/global-search/search-panel.vue | 288 + .../effects/layouts/src/widgets/index.ts | 12 + .../layouts/src/widgets/language-toggle.vue | 39 + .../layouts/src/widgets/layout-toggle.vue | 64 + .../layouts/src/widgets/lock-screen/index.ts | 2 + .../widgets/lock-screen/lock-screen-modal.vue | 110 + .../src/widgets/lock-screen/lock-screen.vue | 167 + .../layouts/src/widgets/notification/index.ts | 3 + .../src/widgets/notification/notification.vue | 235 + .../layouts/src/widgets/notification/types.ts | 17 + .../src/widgets/preferences/blocks/block.vue | 22 + .../preferences/blocks/checkbox-item.vue | 63 + .../preferences/blocks/general/animation.vue | 51 + .../preferences/blocks/general/general.vue | 47 + .../src/widgets/preferences/blocks/index.ts | 20 + .../widgets/preferences/blocks/input-item.vue | 63 + .../preferences/blocks/layout/breadcrumb.vue | 56 + .../preferences/blocks/layout/content.vue | 53 + .../preferences/blocks/layout/copyright.vue | 44 + .../preferences/blocks/layout/footer.vue | 17 + .../preferences/blocks/layout/header.vue | 74 + .../preferences/blocks/layout/layout.vue | 112 + .../preferences/blocks/layout/navigation.vue | 45 + .../preferences/blocks/layout/sidebar.vue | 100 + .../preferences/blocks/layout/tabbar.vue | 94 + .../preferences/blocks/layout/widget.vue | 71 + .../preferences/blocks/number-field-item.vue | 74 + .../preferences/blocks/select-item.vue | 68 + .../blocks/shortcut-keys/global.vue | 50 + .../preferences/blocks/switch-item.vue | 55 + .../preferences/blocks/theme/builtin.vue | 163 + .../preferences/blocks/theme/color-mode.vue | 26 + .../preferences/blocks/theme/font-size.vue | 62 + .../preferences/blocks/theme/radius.vue | 38 + .../preferences/blocks/theme/theme.vue | 83 + .../preferences/blocks/toggle-item.vue | 46 + .../preferences/icons/content-compact.vue | 119 + .../preferences/icons/full-content.vue | 50 + .../preferences/icons/header-mixed-nav.vue | 202 + .../widgets/preferences/icons/header-nav.vue | 119 + .../preferences/icons/header-sidebar-nav.vue | 177 + .../src/widgets/preferences/icons/index.ts | 12 + .../widgets/preferences/icons/mixed-nav.vue | 161 + .../src/widgets/preferences/icons/setting.vue | 12 + .../preferences/icons/sidebar-mixed-nav.vue | 173 + .../widgets/preferences/icons/sidebar-nav.vue | 153 + .../layouts/src/widgets/preferences/index.ts | 3 + .../preferences/preferences-button.vue | 20 + .../preferences/preferences-drawer.vue | 493 + .../src/widgets/preferences/preferences.vue | 72 + .../preferences/use-open-preferences.ts | 16 + .../layouts/src/widgets/theme-toggle/index.ts | 1 + .../src/widgets/theme-toggle/theme-button.vue | 188 + .../src/widgets/theme-toggle/theme-toggle.vue | 83 + .../layouts/src/widgets/timezone/index.ts | 1 + .../src/widgets/timezone/timezone-button.vue | 87 + .../src/widgets/user-dropdown/index.ts | 1 + .../widgets/user-dropdown/user-dropdown.vue | 262 + vue/packages/effects/layouts/tsconfig.json | 6 + vue/packages/effects/plugins/README.md | 28 + vue/packages/effects/plugins/package.json | 47 + .../plugins/src/echarts/echarts-ui.vue | 15 + .../effects/plugins/src/echarts/echarts.ts | 61 + .../effects/plugins/src/echarts/index.ts | 3 + .../plugins/src/echarts/use-echarts.ts | 148 + .../effects/plugins/src/motion/index.ts | 8 + .../effects/plugins/src/motion/types.ts | 26 + .../effects/plugins/src/vxe-table/api.ts | 128 + .../effects/plugins/src/vxe-table/extends.ts | 81 + .../effects/plugins/src/vxe-table/index.ts | 10 + .../effects/plugins/src/vxe-table/init.ts | 131 + .../effects/plugins/src/vxe-table/style.css | 117 + .../effects/plugins/src/vxe-table/types.ts | 93 + .../plugins/src/vxe-table/use-vxe-grid.ts | 70 + .../plugins/src/vxe-table/use-vxe-grid.vue | 479 + vue/packages/effects/plugins/tsconfig.json | 6 + vue/packages/effects/request/package.json | 32 + vue/packages/effects/request/src/index.ts | 2 + .../request/src/request-client/index.ts | 3 + .../request-client/modules/downloader.test.ts | 157 + .../src/request-client/modules/downloader.ts | 60 + .../src/request-client/modules/interceptor.ts | 40 + .../src/request-client/modules/sse.test.ts | 142 + .../request/src/request-client/modules/sse.ts | 136 + .../request-client/modules/uploader.test.ts | 118 + .../src/request-client/modules/uploader.ts | 42 + .../src/request-client/preset-interceptors.ts | 169 + .../src/request-client/request-client.test.ts | 99 + .../src/request-client/request-client.ts | 164 + .../request/src/request-client/types.ts | 106 + vue/packages/effects/request/tsconfig.json | 6 + vue/packages/icons/README.md | 19 + vue/packages/icons/package.json | 33 + .../icons/src/iconify-offline/index.ts | 151 + vue/packages/icons/src/iconify/index.ts | 26 + vue/packages/icons/src/icons/empty-icon.vue | 27 + vue/packages/icons/src/index.ts | 4 + .../icons/src/svg/icons/antdv-logo.svg | 29 + .../svg/icons/arcticons--quark-browser.svg | 1 + vue/packages/icons/src/svg/icons/avatar-1.svg | 1 + vue/packages/icons/src/svg/icons/avatar-2.svg | 1 + vue/packages/icons/src/svg/icons/avatar-3.svg | 1 + vue/packages/icons/src/svg/icons/avatar-4.svg | 1 + vue/packages/icons/src/svg/icons/bell.svg | 1 + vue/packages/icons/src/svg/icons/cake.svg | 1 + vue/packages/icons/src/svg/icons/card.svg | 1 + vue/packages/icons/src/svg/icons/download.svg | 1 + vue/packages/icons/src/svg/index.ts | 27 + vue/packages/icons/src/svg/load.ts | 79 + vue/packages/icons/tsconfig.json | 6 + vue/packages/locales/package.json | 28 + vue/packages/locales/src/i18n.ts | 147 + vue/packages/locales/src/index.ts | 30 + .../src/langs/en-US/authentication.json | 65 + .../locales/src/langs/en-US/common.json | 24 + .../locales/src/langs/en-US/preferences.json | 194 + vue/packages/locales/src/langs/en-US/ui.json | 112 + .../src/langs/zh-CN/authentication.json | 65 + .../locales/src/langs/zh-CN/common.json | 24 + .../locales/src/langs/zh-CN/preferences.json | 194 + vue/packages/locales/src/langs/zh-CN/ui.json | 112 + vue/packages/locales/src/typing.ts | 25 + vue/packages/locales/tsconfig.json | 6 + vue/packages/preferences/package.json | 26 + vue/packages/preferences/src/index.ts | 17 + vue/packages/preferences/tsconfig.json | 6 + vue/packages/stores/package.json | 32 + vue/packages/stores/shim-pinia.d.ts | 9 + vue/packages/stores/src/index.ts | 3 + .../stores/src/modules/access.test.ts | 46 + vue/packages/stores/src/modules/access.ts | 129 + vue/packages/stores/src/modules/index.ts | 4 + .../stores/src/modules/tabbar.test.ts | 325 + vue/packages/stores/src/modules/tabbar.ts | 658 + vue/packages/stores/src/modules/timezone.ts | 132 + vue/packages/stores/src/modules/user.test.ts | 37 + vue/packages/stores/src/modules/user.ts | 64 + vue/packages/stores/src/setup.ts | 60 + vue/packages/stores/tsconfig.json | 5 + vue/packages/styles/README.md | 19 + vue/packages/styles/package.json | 34 + vue/packages/styles/src/antd/index.css | 75 + vue/packages/styles/src/ele/index.css | 44 + vue/packages/styles/src/global/index.scss | 1 + vue/packages/styles/src/index.ts | 1 + vue/packages/styles/src/naive/index.css | 20 + vue/packages/styles/tsconfig.json | 6 + vue/packages/types/README.md | 20 + vue/packages/types/global.d.ts | 32 + vue/packages/types/package.json | 27 + vue/packages/types/src/index.ts | 2 + vue/packages/types/src/user.ts | 30 + vue/packages/types/tsconfig.json | 6 + vue/packages/utils/README.md | 19 + vue/packages/utils/package.json | 28 + .../__tests__/find-menu-by-path.test.ts | 88 + .../helpers/__tests__/generate-menus.test.ts | 236 + .../generate-routes-frontend.test.ts | 105 + .../__tests__/merge-route-modules.test.ts | 68 + vue/packages/utils/src/helpers/file.ts | 40 + .../utils/src/helpers/find-menu-by-path.ts | 37 + .../utils/src/helpers/generate-menus.ts | 90 + .../src/helpers/generate-routes-backend.ts | 86 + .../src/helpers/generate-routes-frontend.ts | 58 + .../utils/src/helpers/get-popup-container.ts | 28 + vue/packages/utils/src/helpers/index.ts | 12 + .../utils/src/helpers/merge-route-modules.ts | 28 + vue/packages/utils/src/helpers/mitt.ts | 135 + .../utils/src/helpers/reset-routes.ts | 31 + vue/packages/utils/src/helpers/tree.ts | 400 + .../src/helpers/unmount-global-loading.ts | 31 + vue/packages/utils/src/helpers/uuid.ts | 42 + vue/packages/utils/src/index.ts | 5 + vue/packages/utils/tsconfig.json | 9 + vue/pnpm-lock.yaml | 19158 ++++++++++++++++ vue/pnpm-workspace.yaml | 197 + vue/private-folder-alias.json | 1 + vue/scripts/clean.mjs | 141 + vue/scripts/deploy/Dockerfile | 37 + .../deploy/build-local-docker-image.sh | 55 + vue/scripts/deploy/nginx.conf | 75 + vue/scripts/turbo-run/README.md | 59 + vue/scripts/turbo-run/bin/turbo-run.mjs | 3 + vue/scripts/turbo-run/build.config.ts | 7 + vue/scripts/turbo-run/package.json | 29 + vue/scripts/turbo-run/src/index.ts | 29 + vue/scripts/turbo-run/src/run.ts | 67 + vue/scripts/turbo-run/tsconfig.json | 6 + vue/scripts/vsh/README.md | 56 + vue/scripts/vsh/bin/vsh.mjs | 3 + vue/scripts/vsh/build.config.ts | 7 + vue/scripts/vsh/package.json | 31 + vue/scripts/vsh/src/check-circular/index.ts | 170 + vue/scripts/vsh/src/check-dep/index.ts | 194 + vue/scripts/vsh/src/code-workspace/index.ts | 78 + vue/scripts/vsh/src/index.ts | 74 + vue/scripts/vsh/src/lint/index.ts | 48 + vue/scripts/vsh/src/publint/index.ts | 185 + vue/scripts/vsh/tsconfig.json | 6 + vue/stylelint.config.mjs | 4 + vue/tea.yaml | 6 + vue/turbo.json | 49 + vue/vben-admin.code-workspace | 172 + vue/vitest.config.ts | 11 + vue/vitest.workspace.ts | 3 + 1607 files changed, 185856 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 vue/.browserslistrc create mode 100644 vue/.commitlintrc.js create mode 100644 vue/.dockerignore create mode 100644 vue/.editorconfig create mode 100644 vue/.husky/commit-msg create mode 100644 vue/.husky/post-merge create mode 100644 vue/.husky/pre-commit create mode 100644 vue/.lintstagedrc.mjs create mode 100644 vue/.node-version create mode 100644 vue/.npmrc create mode 100644 vue/.prettierignore create mode 100644 vue/.prettierrc.mjs create mode 100644 vue/.stylelintignore create mode 100644 vue/.vscode/settings.json create mode 100644 vue/README.md create mode 100644 vue/README.zh-CN.md create mode 100644 vue/aaa.md create mode 100644 vue/apps/.gitignore create mode 100644 vue/apps/web-antd/.env create mode 100644 vue/apps/web-antd/.env.analyze create mode 100644 vue/apps/web-antd/.env.development create mode 100644 vue/apps/web-antd/.env.production create mode 100644 vue/apps/web-antd/index.html create mode 100644 vue/apps/web-antd/loading.html create mode 100644 vue/apps/web-antd/package.json create mode 100644 vue/apps/web-antd/plugins/api-type-generator.ts create mode 100644 vue/apps/web-antd/postcss.config.mjs create mode 100644 vue/apps/web-antd/public/config.json create mode 100644 vue/apps/web-antd/public/favicon.ico create mode 100644 vue/apps/web-antd/public/logo.png create mode 100644 vue/apps/web-antd/public/menu-setting.json create mode 100644 vue/apps/web-antd/public/mini-program-code.png create mode 100644 vue/apps/web-antd/public/setting.json create mode 100644 vue/apps/web-antd/src/adapter/component/antd.ts create mode 100644 vue/apps/web-antd/src/adapter/component/helpers/message.ts create mode 100644 vue/apps/web-antd/src/adapter/component/helpers/upload-preview.ts create mode 100644 vue/apps/web-antd/src/adapter/component/helpers/with-default-placeholder.ts create mode 100644 vue/apps/web-antd/src/adapter/component/helpers/with-preview-upload.ts create mode 100644 vue/apps/web-antd/src/adapter/component/index.ts create mode 100644 vue/apps/web-antd/src/adapter/component/props.ts create mode 100644 vue/apps/web-antd/src/adapter/component/types.ts create mode 100644 vue/apps/web-antd/src/adapter/form.ts create mode 100644 vue/apps/web-antd/src/adapter/highlightedit.ts create mode 100644 vue/apps/web-antd/src/adapter/vxe-table.ts create mode 100644 vue/apps/web-antd/src/api/agent/index.ts create mode 100644 vue/apps/web-antd/src/api/agent/tApiGroup/index.ts create mode 100644 vue/apps/web-antd/src/api/agent/tApiResource/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tAgentBalance/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tBalanceDetail/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tConsumeAccountMonthBill/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tCreditDetail/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tFinCommissionDetail/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tFinWithdrawableChange/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tFinanceApply/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tFinanceAuditRecord/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tMessageLog/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tNotifyLog/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tProfitAccountMonthBill/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tWoCommunication/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tWoMain/index.ts create mode 100644 vue/apps/web-antd/src/api/common/tWoRecord/index.ts create mode 100644 vue/apps/web-antd/src/api/core/auth.ts create mode 100644 vue/apps/web-antd/src/api/core/captcha.ts create mode 100644 vue/apps/web-antd/src/api/core/index.ts create mode 100644 vue/apps/web-antd/src/api/core/menu.ts create mode 100644 vue/apps/web-antd/src/api/core/upload.ts create mode 100644 vue/apps/web-antd/src/api/core/user.ts create mode 100644 vue/apps/web-antd/src/api/gen/testCategory/index.ts create mode 100644 vue/apps/web-antd/src/api/gen/testDemo/index.ts create mode 100644 vue/apps/web-antd/src/api/gen_codes/gen_table.ts create mode 100644 vue/apps/web-antd/src/api/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tApi/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tApi/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardLifecycle/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tDashboard/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tDashboard/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tFlowPackageConfig/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tOrder/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/zAnother/tTplatformSetting/index.ts create mode 100644 vue/apps/web-antd/src/api/monitor/cache.ts create mode 100644 vue/apps/web-antd/src/api/monitor/full-sync.test.ts create mode 100644 vue/apps/web-antd/src/api/monitor/full-sync.ts create mode 100644 vue/apps/web-antd/src/api/monitor/index.ts create mode 100644 vue/apps/web-antd/src/api/monitor/online.ts create mode 100644 vue/apps/web-antd/src/api/regions/index.ts create mode 100644 vue/apps/web-antd/src/api/request.ts create mode 100644 vue/apps/web-antd/src/api/system/client.ts create mode 100644 vue/apps/web-antd/src/api/system/config.ts create mode 100644 vue/apps/web-antd/src/api/system/dept.ts create mode 100644 vue/apps/web-antd/src/api/system/dict.ts create mode 100644 vue/apps/web-antd/src/api/system/index.ts create mode 100644 vue/apps/web-antd/src/api/system/job.ts create mode 100644 vue/apps/web-antd/src/api/system/logininfor.ts create mode 100644 vue/apps/web-antd/src/api/system/menu.ts create mode 100644 vue/apps/web-antd/src/api/system/notice.ts create mode 100644 vue/apps/web-antd/src/api/system/oper-log.ts create mode 100644 vue/apps/web-antd/src/api/system/oss-config.ts create mode 100644 vue/apps/web-antd/src/api/system/oss.ts create mode 100644 vue/apps/web-antd/src/api/system/post.ts create mode 100644 vue/apps/web-antd/src/api/system/qrcode.ts create mode 100644 vue/apps/web-antd/src/api/system/role.ts create mode 100644 vue/apps/web-antd/src/api/system/social.ts create mode 100644 vue/apps/web-antd/src/api/system/sysNoticeUser/index.ts create mode 100644 vue/apps/web-antd/src/api/system/tTplatformSetting.ts create mode 100644 vue/apps/web-antd/src/api/system/tenant.ts create mode 100644 vue/apps/web-antd/src/api/system/tenant_package.ts create mode 100644 vue/apps/web-antd/src/api/system/user.ts create mode 100644 vue/apps/web-antd/src/api/utils/index.ts create mode 100644 vue/apps/web-antd/src/app.vue create mode 100644 vue/apps/web-antd/src/assets/icons/custom.ts create mode 100644 vue/apps/web-antd/src/assets/icons/index.ts create mode 100644 vue/apps/web-antd/src/assets/icons/mdiSlim.ts create mode 100644 vue/apps/web-antd/src/bootstrap.ts create mode 100644 vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue create mode 100644 vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue create mode 100644 vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue create mode 100644 vue/apps/web-antd/src/components/HtCustom/FormExpand/register.ts create mode 100644 vue/apps/web-antd/src/components/HtCustom/IconButton/index.png create mode 100644 vue/apps/web-antd/src/components/HtCustom/IconButton/index.vue create mode 100644 vue/apps/web-antd/src/components/HtCustom/index.ts create mode 100644 vue/apps/web-antd/src/components/chatList/ChatList.vue create mode 100644 vue/apps/web-antd/src/components/cropper/index.ts create mode 100644 vue/apps/web-antd/src/components/cropper/src/cropper-avatar.vue create mode 100644 vue/apps/web-antd/src/components/cropper/src/cropper-modal.vue create mode 100644 vue/apps/web-antd/src/components/cropper/src/cropper.vue create mode 100644 vue/apps/web-antd/src/components/cropper/src/typing.ts create mode 100644 vue/apps/web-antd/src/components/dept/dept-tree.vue create mode 100644 vue/apps/web-antd/src/components/description/index.ts create mode 100644 vue/apps/web-antd/src/components/description/src/description.vue create mode 100644 vue/apps/web-antd/src/components/description/src/typing.ts create mode 100644 vue/apps/web-antd/src/components/description/src/useDescription.ts create mode 100644 vue/apps/web-antd/src/components/dict/index.ts create mode 100644 vue/apps/web-antd/src/components/dict/src/data.tsx create mode 100644 vue/apps/web-antd/src/components/dict/src/index.vue create mode 100644 vue/apps/web-antd/src/components/echarts-vue/piechart.d.ts create mode 100644 vue/apps/web-antd/src/components/echarts-vue/piechart.vue create mode 100644 vue/apps/web-antd/src/components/icon/AppIcon.vue create mode 100644 vue/apps/web-antd/src/components/icon/IconSelect.vue create mode 100644 vue/apps/web-antd/src/components/imgManage/ImgManage.vue create mode 100644 vue/apps/web-antd/src/components/imgManage/types.d.ts create mode 100644 vue/apps/web-antd/src/components/selectDivision/index.vue create mode 100644 vue/apps/web-antd/src/components/tinymce/index.ts create mode 100644 vue/apps/web-antd/src/components/tinymce/src/editor.vue create mode 100644 vue/apps/web-antd/src/components/tinymce/src/helper.ts create mode 100644 vue/apps/web-antd/src/components/tinymce/src/img-upload.vue create mode 100644 vue/apps/web-antd/src/components/tinymce/src/tinymce.ts create mode 100644 vue/apps/web-antd/src/components/upload/index.ts create mode 100644 vue/apps/web-antd/src/components/upload/src/file-upload.vue create mode 100644 vue/apps/web-antd/src/components/upload/src/helper.ts create mode 100644 vue/apps/web-antd/src/components/upload/src/image-upload.vue create mode 100644 vue/apps/web-antd/src/components/upload/src/typing.ts create mode 100644 vue/apps/web-antd/src/components/upload/src/use-upload.ts create mode 100644 vue/apps/web-antd/src/components/vue3cron/job-corn.vue create mode 100644 vue/apps/web-antd/src/components/vue3cron/language/cn.ts create mode 100644 vue/apps/web-antd/src/components/vue3cron/language/en.ts create mode 100644 vue/apps/web-antd/src/components/vue3cron/language/index.ts create mode 100644 vue/apps/web-antd/src/components/vue3cron/language/pt_br.ts create mode 100644 vue/apps/web-antd/src/config/fileType.ts create mode 100644 vue/apps/web-antd/src/config/menu-setting.ts create mode 100644 vue/apps/web-antd/src/config/setting.ts create mode 100644 vue/apps/web-antd/src/config/tianditu.ts create mode 100644 vue/apps/web-antd/src/constants/BetterVben/_form.ts create mode 100644 vue/apps/web-antd/src/constants/BetterVben/_function.ts create mode 100644 vue/apps/web-antd/src/constants/BetterVben/_grid.ts create mode 100644 vue/apps/web-antd/src/constants/BetterVben/_gridForm.ts create mode 100644 vue/apps/web-antd/src/constants/BetterVben/_modal.ts create mode 100644 vue/apps/web-antd/src/constants/BetterVben/index.ts create mode 100644 vue/apps/web-antd/src/constants/DictEnum.ts create mode 100644 vue/apps/web-antd/src/constants/FormOption.ts create mode 100644 vue/apps/web-antd/src/constants/RouterPath.ts create mode 100644 vue/apps/web-antd/src/layouts/auth.vue create mode 100644 vue/apps/web-antd/src/layouts/basic.vue create mode 100644 vue/apps/web-antd/src/layouts/index.ts create mode 100644 vue/apps/web-antd/src/locales/README.md create mode 100644 vue/apps/web-antd/src/locales/index.ts create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/component.json create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/demos.json create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/http.json create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/menu.json create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/page.json create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/pages.json create mode 100644 vue/apps/web-antd/src/locales/langs/en-US/ui.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/component.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/demos.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/http.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/menu.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/page.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/pages.json create mode 100644 vue/apps/web-antd/src/locales/langs/zh-CN/ui.json create mode 100644 vue/apps/web-antd/src/main.ts create mode 100644 vue/apps/web-antd/src/preferences.ts create mode 100644 vue/apps/web-antd/src/router/access.ts create mode 100644 vue/apps/web-antd/src/router/guard.ts create mode 100644 vue/apps/web-antd/src/router/index.ts create mode 100644 vue/apps/web-antd/src/router/routes/core.ts create mode 100644 vue/apps/web-antd/src/router/routes/index.ts create mode 100644 vue/apps/web-antd/src/router/routes/local.ts create mode 100644 vue/apps/web-antd/src/router/routes/modules/dashboard.ts create mode 100644 vue/apps/web-antd/src/router/routes/modules/demos.ts create mode 100644 vue/apps/web-antd/src/router/routes/modules/system.ts create mode 100644 vue/apps/web-antd/src/router/routes/modules/tenant.ts create mode 100644 vue/apps/web-antd/src/router/routes/modules/vben.ts create mode 100644 vue/apps/web-antd/src/store/auth.ts create mode 100644 vue/apps/web-antd/src/store/cache.ts create mode 100644 vue/apps/web-antd/src/store/dict.ts create mode 100644 vue/apps/web-antd/src/store/index.ts create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/MEMORY.md create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/README.md create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/README.md create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/after/api/index.ts.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/after/api/type.ts.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/after/view/edit.vue.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/after/view/index.vue.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/after/view/model.tsx.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/after/view/view.vue.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/before/api/index.ts.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/before/api/type.ts.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/before/view/edit.vue.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/before/view/index.vue.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/before/view/model.tsx.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/compare/before/view/view.vue.txt create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/template/api/index.ts create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/template/api/type.ts create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/template/view/edit.vue create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/template/view/index.vue create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/template/view/model.tsx create mode 100644 vue/apps/web-antd/src/template/iotlcm-crud-style/template/view/view.vue create mode 100644 vue/apps/web-antd/src/types/global.d.ts create mode 100644 vue/apps/web-antd/src/utils/HtCustom/QuickCopy.ts create mode 100644 vue/apps/web-antd/src/utils/HtCustom/QuickDownLoad.ts create mode 100644 vue/apps/web-antd/src/utils/HtCustom/TabInit.ts create mode 100644 vue/apps/web-antd/src/utils/HtCustom/index.ts create mode 100644 vue/apps/web-antd/src/utils/IconManagers.ts create mode 100644 vue/apps/web-antd/src/utils/__tests__/dept-tree.test.ts create mode 100644 vue/apps/web-antd/src/utils/bindArray.tsx create mode 100644 vue/apps/web-antd/src/utils/dept-tree.ts create mode 100644 vue/apps/web-antd/src/utils/dict.ts create mode 100644 vue/apps/web-antd/src/utils/file/base64Conver.ts create mode 100644 vue/apps/web-antd/src/utils/file/download.ts create mode 100644 vue/apps/web-antd/src/utils/file/index.ts create mode 100644 vue/apps/web-antd/src/utils/formatTimestamp.ts create mode 100644 vue/apps/web-antd/src/utils/image.ts create mode 100644 vue/apps/web-antd/src/utils/index.tsx create mode 100644 vue/apps/web-antd/src/utils/is/index.ts create mode 100644 vue/apps/web-antd/src/utils/render.tsx create mode 100644 vue/apps/web-antd/src/views/_core/README.md create mode 100644 vue/apps/web-antd/src/views/_core/about/index.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/code-login.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/components/first-login-guide-modal.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/components/img-captcha.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/forget-password.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/login.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/mfa-verify.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/qrcode-login.vue create mode 100644 vue/apps/web-antd/src/views/_core/authentication/register.vue create mode 100644 vue/apps/web-antd/src/views/_core/fallback/coming-soon.vue create mode 100644 vue/apps/web-antd/src/views/_core/fallback/forbidden.vue create mode 100644 vue/apps/web-antd/src/views/_core/fallback/internal-error.vue create mode 100644 vue/apps/web-antd/src/views/_core/fallback/not-found.vue create mode 100644 vue/apps/web-antd/src/views/_core/fallback/offline.vue create mode 100644 vue/apps/web-antd/src/views/_core/oauth-common.ts create mode 100644 vue/apps/web-antd/src/views/_core/profile/components/account-bind.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/components/base-setting.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/components/contact-setting.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/components/online-device.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/components/secure-setting.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/index.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/mitt.ts create mode 100644 vue/apps/web-antd/src/views/_core/profile/profile-panel.vue create mode 100644 vue/apps/web-antd/src/views/_core/profile/setting-panel.vue create mode 100644 vue/apps/web-antd/src/views/agent/roles/index.vue create mode 100644 vue/apps/web-antd/src/views/agent/roles/menu-select.vue create mode 100644 vue/apps/web-antd/src/views/agent/roles/role-drawer.vue create mode 100644 vue/apps/web-antd/src/views/agent/structure/dept-drawer.vue create mode 100644 vue/apps/web-antd/src/views/agent/structure/dept-reset-pwd-modal.vue create mode 100644 vue/apps/web-antd/src/views/agent/structure/enterprise-manage-modal.vue create mode 100644 vue/apps/web-antd/src/views/agent/structure/index.vue create mode 100644 vue/apps/web-antd/src/views/agent/tApiGroup/edit.vue create mode 100644 vue/apps/web-antd/src/views/agent/tApiGroup/index.vue create mode 100644 vue/apps/web-antd/src/views/agent/tApiGroup/model.tsx create mode 100644 vue/apps/web-antd/src/views/agent/tApiGroup/view.vue create mode 100644 vue/apps/web-antd/src/views/agent/tApiResource/edit.vue create mode 100644 vue/apps/web-antd/src/views/agent/tApiResource/index.vue create mode 100644 vue/apps/web-antd/src/views/agent/tApiResource/model.tsx create mode 100644 vue/apps/web-antd/src/views/agent/tApiResource/view.vue create mode 100644 vue/apps/web-antd/src/views/agent/users/index.vue create mode 100644 vue/apps/web-antd/src/views/agent/users/user-drawer.vue create mode 100644 vue/apps/web-antd/src/views/agent/users/user-reset-pwd-modal.vue create mode 100644 vue/apps/web-antd/src/views/common/financialOverview/index.vue create mode 100644 vue/apps/web-antd/src/views/common/financialOverview/model.ts create mode 100644 vue/apps/web-antd/src/views/common/tAgentBalance/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tAgentBalance/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tAgentBalance/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tAgentBalance/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tBalanceDetail/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tBalanceDetail/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tBalanceDetail/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tBalanceDetail/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tConsumeAccountMonthBill/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tConsumeAccountMonthBill/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tConsumeAccountMonthBill/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tConsumeAccountMonthBill/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tCreditDetail/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tCreditDetail/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tCreditDetail/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tCreditDetail/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinCommissionDetail/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinCommissionDetail/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinCommissionDetail/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tFinCommissionDetail/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinWithdrawableChange/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinWithdrawableChange/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinWithdrawableChange/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tFinWithdrawableChange/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinanceApply/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinanceApply/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinanceApply/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tFinanceApply/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinanceAuditRecord/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinanceAuditRecord/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tFinanceAuditRecord/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tFinanceAuditRecord/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tMessageLog/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tMessageLog/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tMessageLog/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tMessageLog/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tNotifyLog/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tNotifyLog/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tNotifyLog/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tNotifyLog/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tProfitAccountMonthBill/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tProfitAccountMonthBill/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tProfitAccountMonthBill/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tProfitAccountMonthBill/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoCommunication/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoCommunication/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoCommunication/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tWoCommunication/view.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoMain/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoMain/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoMain/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tWoRecord/edit.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoRecord/index.vue create mode 100644 vue/apps/web-antd/src/views/common/tWoRecord/model.tsx create mode 100644 vue/apps/web-antd/src/views/common/tWoRecord/view.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/analytics/analytics-trends.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/analytics/analytics-visits-data.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/analytics/analytics-visits-sales.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/analytics/analytics-visits-source.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/analytics/analytics-visits.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/analytics/index.vue create mode 100644 vue/apps/web-antd/src/views/dashboard/workspace/index.vue create mode 100644 vue/apps/web-antd/src/views/demos/antd/index.vue create mode 100644 vue/apps/web-antd/src/views/gen/testCategory/edit.vue create mode 100644 vue/apps/web-antd/src/views/gen/testCategory/index.vue create mode 100644 vue/apps/web-antd/src/views/gen/testCategory/model.tsx create mode 100644 vue/apps/web-antd/src/views/gen/testCategory/view.vue create mode 100644 vue/apps/web-antd/src/views/gen/testDemo/edit.vue create mode 100644 vue/apps/web-antd/src/views/gen/testDemo/index.vue create mode 100644 vue/apps/web-antd/src/views/gen/testDemo/model.tsx create mode 100644 vue/apps/web-antd/src/views/gen/testDemo/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tApi/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tApi/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tApi/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tApi/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannelTemplate/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannelTemplate/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannelTemplate/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannelTemplate/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannels/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannels/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannels/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannels/test.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tChannel/tSimChannels/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/components/batchCardPreview.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/components/cardSourceTabs.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/addPackage.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/cancel.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/change.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/dataToggle.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/lifecycle.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/renew.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/trafficCutoff.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/unsubscribe.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/warningConfig.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/components/FormSchema/NumberSegment.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/diagnose-route.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/model.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/session-state.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/session-state.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardInfo/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardTrafficCutoff/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardTrafficCutoff/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tSimCardTrafficCutoff/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/BusinessAlarmPanel.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/BusinessUsageChart.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/CardLocationDistributionChart.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/LifecycleDistributionChart.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/MyPanel.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/QuickNavigation.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/RecentFeeChart.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/TrafficPoolChart.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/components/TrafficShareChart.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDashboard/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDeptApi/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tDeptApi/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tFlowPackageConfig/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tFlowPackageConfig/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tFlowPackageConfig/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tFlowPackageConfig/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/components/BasicStatusCard.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/components/FlowChartCard.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/components/PackageFlowDiagnosisCard.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/components/SessionDiagnosisCard.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/display.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/display.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tIntelligentDiagnosis/model.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/batchTypeOptions.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/batchTypeOptions.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatch/cards.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatch/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatch/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatch/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatch/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatchExecutionLog/components/fileDownloadButton.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatchExecutionLog/detailList.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatchExecutionLog/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatchExecutionLog/model.test.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatchExecutionLog/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tBatchExecutionLog/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardCancellation/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardCancellation/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/OutboundBalancePreview.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/batch-outbound.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/batch.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/input.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/outboundBalance.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/outboundFormUtils.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardStock/range.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tWarehousing/batch.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tWarehousing/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tWarehousing/input.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tWarehousing/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tWarehousing/range.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tOrder/display.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tOrder/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tOrder/indexTwo.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tOrder/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackageInfo/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackageInfo/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackageInfo/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackagePrice/batchAdjust.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackagePrice/components/AgentTree/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackagePrice/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPackagePrice/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPool/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPool/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPool/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimFlowPool/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimPackageCategory/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimPackageCategory/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimPackageCategory/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimPackageCategory/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimUpstreamPackage/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimUpstreamPackage/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimUpstreamPackage/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/tPricingPackage/tSimUpstreamPackage/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/cardConfig/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/cardConfig/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/cardConfig/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/flowPoolConfig/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/flowPoolConfig/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/flowPoolConfig/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tWarnCenter/shared/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tAgentEnterprise/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tAgentEnterprise/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tAgentEnterprise/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tAgentEnterprise/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tCustWithdrawAccount/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tCustWithdrawAccount/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tCustWithdrawAccount/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tCustWithdrawAccount/view.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tDivisionCode/edit.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tDivisionCode/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tDivisionCode/model.tsx create mode 100644 vue/apps/web-antd/src/views/iotlcm/zAnother/tDivisionCode/view.vue create mode 100644 vue/apps/web-antd/src/views/monitor/cache/components/command-chart.vue create mode 100644 vue/apps/web-antd/src/views/monitor/cache/components/index.ts create mode 100644 vue/apps/web-antd/src/views/monitor/cache/components/memory-chart.vue create mode 100644 vue/apps/web-antd/src/views/monitor/cache/components/redis-description.vue create mode 100644 vue/apps/web-antd/src/views/monitor/cache/index.vue create mode 100644 vue/apps/web-antd/src/views/monitor/full-sync/index.test.ts create mode 100644 vue/apps/web-antd/src/views/monitor/full-sync/index.vue create mode 100644 vue/apps/web-antd/src/views/monitor/online/index.vue create mode 100644 vue/apps/web-antd/src/views/monitor/server/index.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiBrowserHeader.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiDetailTab.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiRequestTestTab.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiTreePanel.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiTypeBatchGenerateModal.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiTypeDefinitionTab.vue create mode 100644 vue/apps/web-antd/src/views/system/api/components/ApiTypeGenerateModal.vue create mode 100644 vue/apps/web-antd/src/views/system/api/composables/useApiBrowser.ts create mode 100644 vue/apps/web-antd/src/views/system/api/constants.ts create mode 100644 vue/apps/web-antd/src/views/system/api/context.ts create mode 100644 vue/apps/web-antd/src/views/system/api/index.vue create mode 100644 vue/apps/web-antd/src/views/system/api/types.ts create mode 100644 vue/apps/web-antd/src/views/system/api/utils/api-tree.ts create mode 100644 vue/apps/web-antd/src/views/system/api/utils/schema.ts create mode 100644 vue/apps/web-antd/src/views/system/api/utils/type-definition.ts create mode 100644 vue/apps/web-antd/src/views/system/api/utils/type-generate-client.ts create mode 100644 vue/apps/web-antd/src/views/system/client/edit-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/client/index.vue create mode 100644 vue/apps/web-antd/src/views/system/client/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/client/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/config/config-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/config/index.vue create mode 100644 vue/apps/web-antd/src/views/system/config/model.ts create mode 100644 vue/apps/web-antd/src/views/system/dept/dept-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/dept/dept-select.vue create mode 100644 vue/apps/web-antd/src/views/system/dept/index.vue create mode 100644 vue/apps/web-antd/src/views/system/dept/model.ts create mode 100644 vue/apps/web-antd/src/views/system/dept/supplement-modal.vue create mode 100644 vue/apps/web-antd/src/views/system/dict-data/dict-create-modal.vue create mode 100644 vue/apps/web-antd/src/views/system/dict-data/dict-data-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/dict-data/index.vue create mode 100644 vue/apps/web-antd/src/views/system/dict-data/model.ts create mode 100644 vue/apps/web-antd/src/views/system/dict-data/utils.ts create mode 100644 vue/apps/web-antd/src/views/system/dict/dict-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/dict/index.vue create mode 100644 vue/apps/web-antd/src/views/system/dict/model.ts create mode 100644 vue/apps/web-antd/src/views/system/enterpriseManagement/UnitInformation/content.vue create mode 100644 vue/apps/web-antd/src/views/system/enterpriseManagement/UnitInformation/index.vue create mode 100644 vue/apps/web-antd/src/views/system/enterpriseManagement/realNameAuthentication/content.vue create mode 100644 vue/apps/web-antd/src/views/system/enterpriseManagement/tTplatformSetting/content.vue create mode 100644 vue/apps/web-antd/src/views/system/job/edit-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/job/index.vue create mode 100644 vue/apps/web-antd/src/views/system/job/job-cron-model.vue create mode 100644 vue/apps/web-antd/src/views/system/job/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/job/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/logininfor/index.vue create mode 100644 vue/apps/web-antd/src/views/system/logininfor/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/logininfor/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/menu/index.vue create mode 100644 vue/apps/web-antd/src/views/system/menu/menu-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/menu/menu-select.vue create mode 100644 vue/apps/web-antd/src/views/system/menu/model.ts create mode 100644 vue/apps/web-antd/src/views/system/notice/index.vue create mode 100644 vue/apps/web-antd/src/views/system/notice/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/notice/notice-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/notice/selectDevice/index.vue create mode 100644 vue/apps/web-antd/src/views/system/notice/selectDevice/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/notice/view.vue create mode 100644 vue/apps/web-antd/src/views/system/operlog/index.vue create mode 100644 vue/apps/web-antd/src/views/system/operlog/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/operlog/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/oss-config/edit-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/oss-config/index.vue create mode 100644 vue/apps/web-antd/src/views/system/oss-config/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/oss-config/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/oss/file-upload-modal.vue create mode 100644 vue/apps/web-antd/src/views/system/oss/image-upload-modal.vue create mode 100644 vue/apps/web-antd/src/views/system/oss/index.vue create mode 100644 vue/apps/web-antd/src/views/system/oss/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/post/index.vue create mode 100644 vue/apps/web-antd/src/views/system/post/model.ts create mode 100644 vue/apps/web-antd/src/views/system/post/post-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/role/index.vue create mode 100644 vue/apps/web-antd/src/views/system/role/model.ts create mode 100644 vue/apps/web-antd/src/views/system/role/role-data-scope-modal.vue create mode 100644 vue/apps/web-antd/src/views/system/role/role-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/sysNoticeUser/edit.vue create mode 100644 vue/apps/web-antd/src/views/system/sysNoticeUser/index.vue create mode 100644 vue/apps/web-antd/src/views/system/sysNoticeUser/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/sysNoticeUser/view.vue create mode 100644 vue/apps/web-antd/src/views/system/tenant/edit-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/tenant/index.vue create mode 100644 vue/apps/web-antd/src/views/system/tenant/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/tenant/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/tenantPackage/edit-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/tenantPackage/index.vue create mode 100644 vue/apps/web-antd/src/views/system/tenantPackage/model.tsx create mode 100644 vue/apps/web-antd/src/views/system/tenantPackage/view-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/user/index.vue create mode 100644 vue/apps/web-antd/src/views/system/user/model.ts create mode 100644 vue/apps/web-antd/src/views/system/user/user-drawer.vue create mode 100644 vue/apps/web-antd/src/views/system/user/user-reset-pwd-modal.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/components/EditMasterCell.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/components/EditSlaveCell.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/components/PreviewTab.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/develop.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/edit-drawer.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/index.vue create mode 100644 vue/apps/web-antd/src/views/tool/gen/model.tsx create mode 100644 vue/apps/web-antd/src/views/tool/gen/view-drawer.vue create mode 100644 vue/apps/web-antd/tailwind.config.mjs create mode 100644 vue/apps/web-antd/tsconfig.json create mode 100644 vue/apps/web-antd/tsconfig.node.json create mode 100644 vue/apps/web-antd/vite.config.mts create mode 100644 vue/build/.dockerignore create mode 100644 vue/build/Dockerfile create mode 100644 vue/build/DockerfileNoBuild create mode 100644 vue/build/nginx.conf create mode 100644 vue/cspell.json create mode 100644 vue/eslint.config.mjs create mode 100644 vue/folder-alias.json create mode 100644 vue/internal/lint-configs/commitlint-config/index.mjs create mode 100644 vue/internal/lint-configs/commitlint-config/package.json create mode 100644 vue/internal/lint-configs/eslint-config/build.config.ts create mode 100644 vue/internal/lint-configs/eslint-config/package.json create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/command.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/comments.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/disableds.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/ignores.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/import.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/index.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/javascript.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/jsdoc.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/jsonc.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/node.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/perfectionist.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/prettier.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/regexp.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/test.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/turbo.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/typescript.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/unicorn.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/configs/vue.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/custom-config.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/index.ts create mode 100644 vue/internal/lint-configs/eslint-config/src/util.ts create mode 100644 vue/internal/lint-configs/eslint-config/tsconfig.json create mode 100644 vue/internal/lint-configs/prettier-config/index.mjs create mode 100644 vue/internal/lint-configs/prettier-config/package.json create mode 100644 vue/internal/lint-configs/stylelint-config/index.mjs create mode 100644 vue/internal/lint-configs/stylelint-config/package.json create mode 100644 vue/internal/node-utils/build.config.ts create mode 100644 vue/internal/node-utils/package.json create mode 100644 vue/internal/node-utils/src/__tests__/hash.test.ts create mode 100644 vue/internal/node-utils/src/__tests__/path.test.ts create mode 100644 vue/internal/node-utils/src/constants.ts create mode 100644 vue/internal/node-utils/src/date.ts create mode 100644 vue/internal/node-utils/src/fs.ts create mode 100644 vue/internal/node-utils/src/git.ts create mode 100644 vue/internal/node-utils/src/hash.ts create mode 100644 vue/internal/node-utils/src/index.ts create mode 100644 vue/internal/node-utils/src/monorepo.ts create mode 100644 vue/internal/node-utils/src/path.ts create mode 100644 vue/internal/node-utils/src/prettier.ts create mode 100644 vue/internal/node-utils/src/spinner.ts create mode 100644 vue/internal/node-utils/tsconfig.json create mode 100644 vue/internal/tailwind-config/build.config.ts create mode 100644 vue/internal/tailwind-config/package.json create mode 100644 vue/internal/tailwind-config/src/index.ts create mode 100644 vue/internal/tailwind-config/src/module.d.ts create mode 100644 vue/internal/tailwind-config/src/plugins/entry.ts create mode 100644 vue/internal/tailwind-config/src/postcss.config.ts create mode 100644 vue/internal/tailwind-config/tsconfig.json create mode 100644 vue/internal/tsconfig/base.json create mode 100644 vue/internal/tsconfig/library.json create mode 100644 vue/internal/tsconfig/node.json create mode 100644 vue/internal/tsconfig/package.json create mode 100644 vue/internal/tsconfig/web-app.json create mode 100644 vue/internal/tsconfig/web.json create mode 100644 vue/internal/vite-config/build.config.ts create mode 100644 vue/internal/vite-config/package.json create mode 100644 vue/internal/vite-config/src/config/application.ts create mode 100644 vue/internal/vite-config/src/config/common.ts create mode 100644 vue/internal/vite-config/src/config/index.ts create mode 100644 vue/internal/vite-config/src/config/library.ts create mode 100644 vue/internal/vite-config/src/index.ts create mode 100644 vue/internal/vite-config/src/options.ts create mode 100644 vue/internal/vite-config/src/plugins/archiver.ts create mode 100644 vue/internal/vite-config/src/plugins/extra-app-config.ts create mode 100644 vue/internal/vite-config/src/plugins/importmap.ts create mode 100644 vue/internal/vite-config/src/plugins/index.ts create mode 100644 vue/internal/vite-config/src/plugins/inject-app-loading/README.md create mode 100644 vue/internal/vite-config/src/plugins/inject-app-loading/default-loading-antd.html create mode 100644 vue/internal/vite-config/src/plugins/inject-app-loading/default-loading.html create mode 100644 vue/internal/vite-config/src/plugins/inject-app-loading/index.ts create mode 100644 vue/internal/vite-config/src/plugins/inject-metadata.ts create mode 100644 vue/internal/vite-config/src/plugins/license.ts create mode 100644 vue/internal/vite-config/src/plugins/nitro-mock.ts create mode 100644 vue/internal/vite-config/src/plugins/print.ts create mode 100644 vue/internal/vite-config/src/plugins/vxe-table.ts create mode 100644 vue/internal/vite-config/src/typing.ts create mode 100644 vue/internal/vite-config/src/utils/env.ts create mode 100644 vue/internal/vite-config/tsconfig.json create mode 100644 vue/lefthook.yml create mode 100644 vue/package.json create mode 100644 vue/packages/@core/README.md create mode 100644 vue/packages/@core/base/README.md create mode 100644 vue/packages/@core/base/design/package.json create mode 100644 vue/packages/@core/base/design/src/css/global.css create mode 100644 vue/packages/@core/base/design/src/css/nprogress.css create mode 100644 vue/packages/@core/base/design/src/css/transition.css create mode 100644 vue/packages/@core/base/design/src/css/ui.css create mode 100644 vue/packages/@core/base/design/src/design-tokens/dark.css create mode 100644 vue/packages/@core/base/design/src/design-tokens/default.css create mode 100644 vue/packages/@core/base/design/src/design-tokens/index.ts create mode 100644 vue/packages/@core/base/design/src/index.ts create mode 100644 vue/packages/@core/base/design/src/scss-bem/bem.scss create mode 100644 vue/packages/@core/base/design/src/scss-bem/constants.scss create mode 100644 vue/packages/@core/base/design/tsconfig.json create mode 100644 vue/packages/@core/base/design/vite.config.mts create mode 100644 vue/packages/@core/base/icons/build.config.ts create mode 100644 vue/packages/@core/base/icons/package.json create mode 100644 vue/packages/@core/base/icons/src/create-icon.ts create mode 100644 vue/packages/@core/base/icons/src/index.ts create mode 100644 vue/packages/@core/base/icons/src/lucide.ts create mode 100644 vue/packages/@core/base/icons/tsconfig.json create mode 100644 vue/packages/@core/base/shared/build.config.ts create mode 100644 vue/packages/@core/base/shared/package.json create mode 100644 vue/packages/@core/base/shared/src/cache/__tests__/storage-manager.test.ts create mode 100644 vue/packages/@core/base/shared/src/cache/index.ts create mode 100644 vue/packages/@core/base/shared/src/cache/storage-manager.ts create mode 100644 vue/packages/@core/base/shared/src/cache/types.ts create mode 100644 vue/packages/@core/base/shared/src/color/__tests__/convert.test.ts create mode 100644 vue/packages/@core/base/shared/src/color/color.ts create mode 100644 vue/packages/@core/base/shared/src/color/convert.ts create mode 100644 vue/packages/@core/base/shared/src/color/generator.ts create mode 100644 vue/packages/@core/base/shared/src/color/index.ts create mode 100644 vue/packages/@core/base/shared/src/constants/globals.ts create mode 100644 vue/packages/@core/base/shared/src/constants/index.ts create mode 100644 vue/packages/@core/base/shared/src/constants/vben.ts create mode 100644 vue/packages/@core/base/shared/src/global-state.ts create mode 100644 vue/packages/@core/base/shared/src/store.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/date.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/diff.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/dom.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/inference.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/letter.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/resources.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/state-handler.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/tree.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/unique.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/update-css-variables.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/util.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/__tests__/window.test.ts create mode 100644 vue/packages/@core/base/shared/src/utils/cn.ts create mode 100644 vue/packages/@core/base/shared/src/utils/date.ts create mode 100644 vue/packages/@core/base/shared/src/utils/diff.ts create mode 100644 vue/packages/@core/base/shared/src/utils/dom.ts create mode 100644 vue/packages/@core/base/shared/src/utils/download.ts create mode 100644 vue/packages/@core/base/shared/src/utils/index.ts create mode 100644 vue/packages/@core/base/shared/src/utils/inference.ts create mode 100644 vue/packages/@core/base/shared/src/utils/letter.ts create mode 100644 vue/packages/@core/base/shared/src/utils/merge.ts create mode 100644 vue/packages/@core/base/shared/src/utils/nprogress.ts create mode 100644 vue/packages/@core/base/shared/src/utils/resources.ts create mode 100644 vue/packages/@core/base/shared/src/utils/state-handler.ts create mode 100644 vue/packages/@core/base/shared/src/utils/to.ts create mode 100644 vue/packages/@core/base/shared/src/utils/tree.ts create mode 100644 vue/packages/@core/base/shared/src/utils/unique.ts create mode 100644 vue/packages/@core/base/shared/src/utils/update-css-variables.ts create mode 100644 vue/packages/@core/base/shared/src/utils/util.ts create mode 100644 vue/packages/@core/base/shared/src/utils/window.ts create mode 100644 vue/packages/@core/base/shared/tsconfig.json create mode 100644 vue/packages/@core/base/typings/build.config.ts create mode 100644 vue/packages/@core/base/typings/package.json create mode 100644 vue/packages/@core/base/typings/src/app.d.ts create mode 100644 vue/packages/@core/base/typings/src/basic.d.ts create mode 100644 vue/packages/@core/base/typings/src/helper.d.ts create mode 100644 vue/packages/@core/base/typings/src/index.ts create mode 100644 vue/packages/@core/base/typings/src/menu-record.ts create mode 100644 vue/packages/@core/base/typings/src/tabs.ts create mode 100644 vue/packages/@core/base/typings/src/vue-router.d.ts create mode 100644 vue/packages/@core/base/typings/tsconfig.json create mode 100644 vue/packages/@core/base/typings/vue-router.d.ts create mode 100644 vue/packages/@core/composables/build.config.ts create mode 100644 vue/packages/@core/composables/package.json create mode 100644 vue/packages/@core/composables/src/__tests__/use-sortable.test.ts create mode 100644 vue/packages/@core/composables/src/index.ts create mode 100644 vue/packages/@core/composables/src/use-is-mobile.ts create mode 100644 vue/packages/@core/composables/src/use-layout-style.ts create mode 100644 vue/packages/@core/composables/src/use-namespace.ts create mode 100644 vue/packages/@core/composables/src/use-priority-value.ts create mode 100644 vue/packages/@core/composables/src/use-scroll-lock.ts create mode 100644 vue/packages/@core/composables/src/use-simple-locale/README.md create mode 100644 vue/packages/@core/composables/src/use-simple-locale/index.ts create mode 100644 vue/packages/@core/composables/src/use-simple-locale/messages.ts create mode 100644 vue/packages/@core/composables/src/use-sortable.ts create mode 100644 vue/packages/@core/composables/tsconfig.json create mode 100644 vue/packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap create mode 100644 vue/packages/@core/preferences/__tests__/config.test.ts create mode 100644 vue/packages/@core/preferences/__tests__/preferences.test.ts create mode 100644 vue/packages/@core/preferences/build.config.ts create mode 100644 vue/packages/@core/preferences/package.json create mode 100644 vue/packages/@core/preferences/src/config.ts create mode 100644 vue/packages/@core/preferences/src/constants.ts create mode 100644 vue/packages/@core/preferences/src/index.ts create mode 100644 vue/packages/@core/preferences/src/preferences.ts create mode 100644 vue/packages/@core/preferences/src/types.ts create mode 100644 vue/packages/@core/preferences/src/update-css-variables.ts create mode 100644 vue/packages/@core/preferences/src/use-preferences.ts create mode 100644 vue/packages/@core/preferences/tsconfig.json create mode 100644 vue/packages/@core/ui-kit/README.md create mode 100644 vue/packages/@core/ui-kit/form-ui/__tests__/expandable.test.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/__tests__/form-api.test.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/build.config.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/package.json create mode 100644 vue/packages/@core/ui-kit/form-ui/postcss.config.mjs create mode 100644 vue/packages/@core/ui-kit/form-ui/src/components/form-actions.vue create mode 100644 vue/packages/@core/ui-kit/form-ui/src/config.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-api.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/context.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/dependencies.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/expandable.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/form-field.vue create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/form-label.vue create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/form.vue create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/helper.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/form-render/index.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/index.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/types.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/use-form-context.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/use-vben-form.ts create mode 100644 vue/packages/@core/ui-kit/form-ui/src/vben-form.vue create mode 100644 vue/packages/@core/ui-kit/form-ui/src/vben-use-form.vue create mode 100644 vue/packages/@core/ui-kit/form-ui/tailwind.config.mjs create mode 100644 vue/packages/@core/ui-kit/form-ui/tsconfig.json create mode 100644 vue/packages/@core/ui-kit/layout-ui/build.config.ts create mode 100644 vue/packages/@core/ui-kit/layout-ui/package.json create mode 100644 vue/packages/@core/ui-kit/layout-ui/postcss.config.mjs create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/index.ts create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/layout-content.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/layout-footer.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/layout-header.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/layout-sidebar.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/layout-tabbar.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/widgets/index.ts create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-collapse-button.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/components/widgets/sidebar-fixed-button.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/hooks/use-layout.ts create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/index.ts create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/vben-layout.ts create mode 100644 vue/packages/@core/ui-kit/layout-ui/src/vben-layout.vue create mode 100644 vue/packages/@core/ui-kit/layout-ui/tailwind.config.mjs create mode 100644 vue/packages/@core/ui-kit/layout-ui/tsconfig.json create mode 100644 vue/packages/@core/ui-kit/menu-ui/README.md create mode 100644 vue/packages/@core/ui-kit/menu-ui/build.config.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/package.json create mode 100644 vue/packages/@core/ui-kit/menu-ui/postcss.config.mjs create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/collapse-transition.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/index.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/menu-badge-dot.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/menu-badge.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/menu-item.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/menu.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/normal-menu/index.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/normal-menu/normal-menu.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/sub-menu-content.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/components/sub-menu.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/hooks/index.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-context.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/hooks/use-menu-scroll.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/hooks/use-menu.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/index.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/menu.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/sub-menu.vue create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/types.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/src/utils/index.ts create mode 100644 vue/packages/@core/ui-kit/menu-ui/tailwind.config.mjs create mode 100644 vue/packages/@core/ui-kit/menu-ui/tsconfig.json create mode 100644 vue/packages/@core/ui-kit/popup-ui/build.config.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/package.json create mode 100644 vue/packages/@core/ui-kit/popup-ui/postcss.config.mjs create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/alert/AlertBuilder.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/alert/alert.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/alert/alert.vue create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/alert/index.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/drawer/__tests__/drawer-api.test.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/drawer/index.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/index.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/__tests__/modal-api.test.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/index.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/modal-api.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/modal.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/modal.vue create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/use-modal-draggable.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts create mode 100644 vue/packages/@core/ui-kit/popup-ui/tailwind.config.mjs create mode 100644 vue/packages/@core/ui-kit/popup-ui/tsconfig.json create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/build.config.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/components.json create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/package.json create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/postcss.config.mjs create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/avatar/avatar.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/avatar/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/back-top/back-top.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/back-top/backtop.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/back-top/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/back-top/use-backtop.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-background.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb-view.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/breadcrumb.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/breadcrumb/types.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/button/button-group.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/button/button.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/button/button.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/button/check-button-group.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/button/icon-button.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/button/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/checkbox.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/checkbox/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/context-menu.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/context-menu/interface.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/count-to-animator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/count-to-animator/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-menu.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/dropdown-radio-menu.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/dropdown-menu/interface.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/expandable-arrow.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/expandable-arrow/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/full-screen.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/full-screen/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/hover-card.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/hover-card/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/icon/icon.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/icon/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/input-password/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/input-password/input-password.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/input-password/password-strength.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/logo/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/pin-input/types.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/popover/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/popover/popover.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/render-content/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/render-content/render-content.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/scrollbar/scrollbar.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/segmented/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/segmented/segmented.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/segmented/tabs-indicator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/segmented/types.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/select/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/select/select.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/spine-text/spine-text.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/spinner/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/spinner/loading.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/spinner/spinner.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/help-tooltip.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/components/tooltip/tooltip.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/Accordion.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/AccordionTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/accordion/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialog.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogAction.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogCancel.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogDescription.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogOverlay.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/AlertDialogTitle.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/alert-dialog/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/Avatar.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarFallback.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/AvatarImage.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/avatar.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/avatar/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/badge/Badge.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/badge/badge.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/badge/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/Breadcrumb.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbEllipsis.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbLink.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbList.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbPage.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/BreadcrumbSeparator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/breadcrumb/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/button/Button.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/button/button.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/button/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/button/types.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/Card.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardDescription.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardFooter.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardHeader.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/CardTitle.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/card/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/Checkbox.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/checkbox/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenu.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuCheckboxItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuLabel.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuPortal.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuRadioItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSeparator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuShortcut.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSub.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuSubTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/ContextMenuTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/context-menu/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/Dialog.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogClose.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogDescription.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogFooter.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogHeader.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogOverlay.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogScrollContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTitle.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/DialogTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dialog/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenu.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuCheckboxItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuLabel.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuRadioItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSeparator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuShortcut.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSub.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuSubTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/DropdownMenuTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/dropdown-menu/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormControl.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormDescription.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormLabel.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/FormMessage.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/injectionKeys.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/form/useFormField.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCard.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/HoverCardTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/hover-card/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/input/Input.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/input/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/label/Label.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/label/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberField.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldDecrement.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldIncrement.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/NumberFieldInput.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/number-field/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationEllipsis.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationFirst.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationLast.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationNext.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/PaginationPrev.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pagination/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInput.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputInput.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/PinInputSeparator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/pin-input/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/popover/Popover.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/popover/PopoverTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/popover/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/RadioGroupItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/radio-group/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/resizable/ResizableHandle.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/resizable/ResizablePanelGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/resizable/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollArea.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/ScrollBar.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/scroll-area/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/Select.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectItemText.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectLabel.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollDownButton.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectScrollUpButton.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectSeparator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/SelectValue.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/select/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/separator/Separator.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/separator/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/Sheet.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetClose.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetDescription.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetHeader.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetOverlay.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTitle.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/sheet.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/switch/Switch.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/switch/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/Tabs.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsList.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/TabsTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tabs/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/Textarea.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs create mode 100644 vue/packages/@core/ui-kit/shadcn-ui/tsconfig.json create mode 100644 vue/packages/@core/ui-kit/tabs-ui/build.config.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/package.json create mode 100644 vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/components/index.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/index.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/types.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts create mode 100644 vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs create mode 100644 vue/packages/@core/ui-kit/tabs-ui/tsconfig.json create mode 100644 vue/packages/constants/README.md create mode 100644 vue/packages/constants/package.json create mode 100644 vue/packages/constants/src/core.ts create mode 100644 vue/packages/constants/src/dict-enum.ts create mode 100644 vue/packages/constants/src/index.ts create mode 100644 vue/packages/constants/tsconfig.json create mode 100644 vue/packages/effects/README.md create mode 100644 vue/packages/effects/access/package.json create mode 100644 vue/packages/effects/access/src/access-control.vue create mode 100644 vue/packages/effects/access/src/accessible.ts create mode 100644 vue/packages/effects/access/src/directive.ts create mode 100644 vue/packages/effects/access/src/index.ts create mode 100644 vue/packages/effects/access/src/use-access.ts create mode 100644 vue/packages/effects/access/tsconfig.json create mode 100644 vue/packages/effects/common-ui/package.json create mode 100644 vue/packages/effects/common-ui/src/components/api-component/api-component.vue create mode 100644 vue/packages/effects/common-ui/src/components/api-component/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts create mode 100644 vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue create mode 100644 vue/packages/effects/common-ui/src/components/captcha/types.ts create mode 100644 vue/packages/effects/common-ui/src/components/col-page/col-page.vue create mode 100644 vue/packages/effects/common-ui/src/components/col-page/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/col-page/types.ts create mode 100644 vue/packages/effects/common-ui/src/components/count-to/count-to.vue create mode 100644 vue/packages/effects/common-ui/src/components/count-to/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/count-to/types.ts create mode 100644 vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue create mode 100644 vue/packages/effects/common-ui/src/components/ellipsis-text/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue create mode 100644 vue/packages/effects/common-ui/src/components/icon-picker/icons.ts create mode 100644 vue/packages/effects/common-ui/src/components/icon-picker/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/json-preview/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue create mode 100644 vue/packages/effects/common-ui/src/components/json-viewer/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/json-viewer/index.vue create mode 100644 vue/packages/effects/common-ui/src/components/json-viewer/style.scss create mode 100644 vue/packages/effects/common-ui/src/components/json-viewer/types.ts create mode 100644 vue/packages/effects/common-ui/src/components/loading/directive.ts create mode 100644 vue/packages/effects/common-ui/src/components/loading/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/loading/loading.vue create mode 100644 vue/packages/effects/common-ui/src/components/loading/spinner.vue create mode 100644 vue/packages/effects/common-ui/src/components/page/__tests__/page.test.ts create mode 100644 vue/packages/effects/common-ui/src/components/page/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/page/page.vue create mode 100644 vue/packages/effects/common-ui/src/components/page/types.ts create mode 100644 vue/packages/effects/common-ui/src/components/resize/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/resize/resize.vue create mode 100644 vue/packages/effects/common-ui/src/components/tippy/directive.ts create mode 100644 vue/packages/effects/common-ui/src/components/tippy/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/tree/index.ts create mode 100644 vue/packages/effects/common-ui/src/components/tree/tree.vue create mode 100644 vue/packages/effects/common-ui/src/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/about/about.ts create mode 100644 vue/packages/effects/common-ui/src/ui/about/about.vue create mode 100644 vue/packages/effects/common-ui/src/ui/about/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/code-login.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/login.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/register.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue create mode 100644 vue/packages/effects/common-ui/src/ui/authentication/types.ts create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/typing.ts create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue create mode 100644 vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/fallback.ts create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/fallback.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg create mode 100644 vue/packages/effects/common-ui/src/ui/fallback/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/profile/base-setting.vue create mode 100644 vue/packages/effects/common-ui/src/ui/profile/index.ts create mode 100644 vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue create mode 100644 vue/packages/effects/common-ui/src/ui/profile/password-setting.vue create mode 100644 vue/packages/effects/common-ui/src/ui/profile/profile.vue create mode 100644 vue/packages/effects/common-ui/src/ui/profile/security-setting.vue create mode 100644 vue/packages/effects/common-ui/src/ui/profile/types.ts create mode 100644 vue/packages/effects/common-ui/tsconfig.json create mode 100644 vue/packages/effects/hooks/README.md create mode 100644 vue/packages/effects/hooks/package.json create mode 100644 vue/packages/effects/hooks/src/index.ts create mode 100644 vue/packages/effects/hooks/src/use-app-config.ts create mode 100644 vue/packages/effects/hooks/src/use-content-maximize.ts create mode 100644 vue/packages/effects/hooks/src/use-design-tokens.ts create mode 100644 vue/packages/effects/hooks/src/use-hover-toggle.ts create mode 100644 vue/packages/effects/hooks/src/use-pagination.ts create mode 100644 vue/packages/effects/hooks/src/use-refresh.ts create mode 100644 vue/packages/effects/hooks/src/use-tabs.ts create mode 100644 vue/packages/effects/hooks/src/use-watermark.ts create mode 100644 vue/packages/effects/hooks/tsconfig.json create mode 100644 vue/packages/effects/layouts/package.json create mode 100644 vue/packages/effects/layouts/src/authentication/authentication.vue create mode 100644 vue/packages/effects/layouts/src/authentication/form.vue create mode 100644 vue/packages/effects/layouts/src/authentication/icons/slogan.vue create mode 100644 vue/packages/effects/layouts/src/authentication/index.ts create mode 100644 vue/packages/effects/layouts/src/authentication/toolbar.vue create mode 100644 vue/packages/effects/layouts/src/authentication/types.ts create mode 100644 vue/packages/effects/layouts/src/basic/README.md create mode 100644 vue/packages/effects/layouts/src/basic/content/content-spinner.vue create mode 100644 vue/packages/effects/layouts/src/basic/content/content.vue create mode 100644 vue/packages/effects/layouts/src/basic/content/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/content/use-content-spinner.ts create mode 100644 vue/packages/effects/layouts/src/basic/copyright/copyright.vue create mode 100644 vue/packages/effects/layouts/src/basic/copyright/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/footer/footer.vue create mode 100644 vue/packages/effects/layouts/src/basic/footer/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/header/header.vue create mode 100644 vue/packages/effects/layouts/src/basic/header/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/layout.vue create mode 100644 vue/packages/effects/layouts/src/basic/menu/extra-menu.vue create mode 100644 vue/packages/effects/layouts/src/basic/menu/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/menu/menu.vue create mode 100644 vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue create mode 100644 vue/packages/effects/layouts/src/basic/menu/use-extra-menu.ts create mode 100644 vue/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts create mode 100644 vue/packages/effects/layouts/src/basic/menu/use-navigation.ts create mode 100644 vue/packages/effects/layouts/src/basic/tabbar/index.ts create mode 100644 vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue create mode 100644 vue/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts create mode 100644 vue/packages/effects/layouts/src/iframe/iframe-router-view.vue create mode 100644 vue/packages/effects/layouts/src/iframe/iframe-view.vue create mode 100644 vue/packages/effects/layouts/src/iframe/index.ts create mode 100644 vue/packages/effects/layouts/src/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/breadcrumb.vue create mode 100644 vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue create mode 100644 vue/packages/effects/layouts/src/widgets/check-updates/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/color-toggle.vue create mode 100644 vue/packages/effects/layouts/src/widgets/global-search/global-search.vue create mode 100644 vue/packages/effects/layouts/src/widgets/global-search/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue create mode 100644 vue/packages/effects/layouts/src/widgets/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/language-toggle.vue create mode 100644 vue/packages/effects/layouts/src/widgets/layout-toggle.vue create mode 100644 vue/packages/effects/layouts/src/widgets/lock-screen/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue create mode 100644 vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue create mode 100644 vue/packages/effects/layouts/src/widgets/notification/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/notification/notification.vue create mode 100644 vue/packages/effects/layouts/src/widgets/notification/types.ts create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/preferences.vue create mode 100644 vue/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts create mode 100644 vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue create mode 100644 vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue create mode 100644 vue/packages/effects/layouts/src/widgets/timezone/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue create mode 100644 vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts create mode 100644 vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue create mode 100644 vue/packages/effects/layouts/tsconfig.json create mode 100644 vue/packages/effects/plugins/README.md create mode 100644 vue/packages/effects/plugins/package.json create mode 100644 vue/packages/effects/plugins/src/echarts/echarts-ui.vue create mode 100644 vue/packages/effects/plugins/src/echarts/echarts.ts create mode 100644 vue/packages/effects/plugins/src/echarts/index.ts create mode 100644 vue/packages/effects/plugins/src/echarts/use-echarts.ts create mode 100644 vue/packages/effects/plugins/src/motion/index.ts create mode 100644 vue/packages/effects/plugins/src/motion/types.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/api.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/extends.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/index.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/init.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/style.css create mode 100644 vue/packages/effects/plugins/src/vxe-table/types.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts create mode 100644 vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue create mode 100644 vue/packages/effects/plugins/tsconfig.json create mode 100644 vue/packages/effects/request/package.json create mode 100644 vue/packages/effects/request/src/index.ts create mode 100644 vue/packages/effects/request/src/request-client/index.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/downloader.test.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/downloader.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/interceptor.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/sse.test.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/sse.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/uploader.test.ts create mode 100644 vue/packages/effects/request/src/request-client/modules/uploader.ts create mode 100644 vue/packages/effects/request/src/request-client/preset-interceptors.ts create mode 100644 vue/packages/effects/request/src/request-client/request-client.test.ts create mode 100644 vue/packages/effects/request/src/request-client/request-client.ts create mode 100644 vue/packages/effects/request/src/request-client/types.ts create mode 100644 vue/packages/effects/request/tsconfig.json create mode 100644 vue/packages/icons/README.md create mode 100644 vue/packages/icons/package.json create mode 100644 vue/packages/icons/src/iconify-offline/index.ts create mode 100644 vue/packages/icons/src/iconify/index.ts create mode 100644 vue/packages/icons/src/icons/empty-icon.vue create mode 100644 vue/packages/icons/src/index.ts create mode 100644 vue/packages/icons/src/svg/icons/antdv-logo.svg create mode 100644 vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg create mode 100644 vue/packages/icons/src/svg/icons/avatar-1.svg create mode 100644 vue/packages/icons/src/svg/icons/avatar-2.svg create mode 100644 vue/packages/icons/src/svg/icons/avatar-3.svg create mode 100644 vue/packages/icons/src/svg/icons/avatar-4.svg create mode 100644 vue/packages/icons/src/svg/icons/bell.svg create mode 100644 vue/packages/icons/src/svg/icons/cake.svg create mode 100644 vue/packages/icons/src/svg/icons/card.svg create mode 100644 vue/packages/icons/src/svg/icons/download.svg create mode 100644 vue/packages/icons/src/svg/index.ts create mode 100644 vue/packages/icons/src/svg/load.ts create mode 100644 vue/packages/icons/tsconfig.json create mode 100644 vue/packages/locales/package.json create mode 100644 vue/packages/locales/src/i18n.ts create mode 100644 vue/packages/locales/src/index.ts create mode 100644 vue/packages/locales/src/langs/en-US/authentication.json create mode 100644 vue/packages/locales/src/langs/en-US/common.json create mode 100644 vue/packages/locales/src/langs/en-US/preferences.json create mode 100644 vue/packages/locales/src/langs/en-US/ui.json create mode 100644 vue/packages/locales/src/langs/zh-CN/authentication.json create mode 100644 vue/packages/locales/src/langs/zh-CN/common.json create mode 100644 vue/packages/locales/src/langs/zh-CN/preferences.json create mode 100644 vue/packages/locales/src/langs/zh-CN/ui.json create mode 100644 vue/packages/locales/src/typing.ts create mode 100644 vue/packages/locales/tsconfig.json create mode 100644 vue/packages/preferences/package.json create mode 100644 vue/packages/preferences/src/index.ts create mode 100644 vue/packages/preferences/tsconfig.json create mode 100644 vue/packages/stores/package.json create mode 100644 vue/packages/stores/shim-pinia.d.ts create mode 100644 vue/packages/stores/src/index.ts create mode 100644 vue/packages/stores/src/modules/access.test.ts create mode 100644 vue/packages/stores/src/modules/access.ts create mode 100644 vue/packages/stores/src/modules/index.ts create mode 100644 vue/packages/stores/src/modules/tabbar.test.ts create mode 100644 vue/packages/stores/src/modules/tabbar.ts create mode 100644 vue/packages/stores/src/modules/timezone.ts create mode 100644 vue/packages/stores/src/modules/user.test.ts create mode 100644 vue/packages/stores/src/modules/user.ts create mode 100644 vue/packages/stores/src/setup.ts create mode 100644 vue/packages/stores/tsconfig.json create mode 100644 vue/packages/styles/README.md create mode 100644 vue/packages/styles/package.json create mode 100644 vue/packages/styles/src/antd/index.css create mode 100644 vue/packages/styles/src/ele/index.css create mode 100644 vue/packages/styles/src/global/index.scss create mode 100644 vue/packages/styles/src/index.ts create mode 100644 vue/packages/styles/src/naive/index.css create mode 100644 vue/packages/styles/tsconfig.json create mode 100644 vue/packages/types/README.md create mode 100644 vue/packages/types/global.d.ts create mode 100644 vue/packages/types/package.json create mode 100644 vue/packages/types/src/index.ts create mode 100644 vue/packages/types/src/user.ts create mode 100644 vue/packages/types/tsconfig.json create mode 100644 vue/packages/utils/README.md create mode 100644 vue/packages/utils/package.json create mode 100644 vue/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts create mode 100644 vue/packages/utils/src/helpers/__tests__/generate-menus.test.ts create mode 100644 vue/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts create mode 100644 vue/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts create mode 100644 vue/packages/utils/src/helpers/file.ts create mode 100644 vue/packages/utils/src/helpers/find-menu-by-path.ts create mode 100644 vue/packages/utils/src/helpers/generate-menus.ts create mode 100644 vue/packages/utils/src/helpers/generate-routes-backend.ts create mode 100644 vue/packages/utils/src/helpers/generate-routes-frontend.ts create mode 100644 vue/packages/utils/src/helpers/get-popup-container.ts create mode 100644 vue/packages/utils/src/helpers/index.ts create mode 100644 vue/packages/utils/src/helpers/merge-route-modules.ts create mode 100644 vue/packages/utils/src/helpers/mitt.ts create mode 100644 vue/packages/utils/src/helpers/reset-routes.ts create mode 100644 vue/packages/utils/src/helpers/tree.ts create mode 100644 vue/packages/utils/src/helpers/unmount-global-loading.ts create mode 100644 vue/packages/utils/src/helpers/uuid.ts create mode 100644 vue/packages/utils/src/index.ts create mode 100644 vue/packages/utils/tsconfig.json create mode 100644 vue/pnpm-lock.yaml create mode 100644 vue/pnpm-workspace.yaml create mode 100644 vue/private-folder-alias.json create mode 100644 vue/scripts/clean.mjs create mode 100644 vue/scripts/deploy/Dockerfile create mode 100644 vue/scripts/deploy/build-local-docker-image.sh create mode 100644 vue/scripts/deploy/nginx.conf create mode 100644 vue/scripts/turbo-run/README.md create mode 100644 vue/scripts/turbo-run/bin/turbo-run.mjs create mode 100644 vue/scripts/turbo-run/build.config.ts create mode 100644 vue/scripts/turbo-run/package.json create mode 100644 vue/scripts/turbo-run/src/index.ts create mode 100644 vue/scripts/turbo-run/src/run.ts create mode 100644 vue/scripts/turbo-run/tsconfig.json create mode 100644 vue/scripts/vsh/README.md create mode 100644 vue/scripts/vsh/bin/vsh.mjs create mode 100644 vue/scripts/vsh/build.config.ts create mode 100644 vue/scripts/vsh/package.json create mode 100644 vue/scripts/vsh/src/check-circular/index.ts create mode 100644 vue/scripts/vsh/src/check-dep/index.ts create mode 100644 vue/scripts/vsh/src/code-workspace/index.ts create mode 100644 vue/scripts/vsh/src/index.ts create mode 100644 vue/scripts/vsh/src/lint/index.ts create mode 100644 vue/scripts/vsh/src/publint/index.ts create mode 100644 vue/scripts/vsh/tsconfig.json create mode 100644 vue/stylelint.config.mjs create mode 100644 vue/tea.yaml create mode 100644 vue/turbo.json create mode 100644 vue/vben-admin.code-workspace create mode 100644 vue/vitest.config.ts create mode 100644 vue/vitest.workspace.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..891b902 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.git +.gitignore +README.md +.env.local +*.zip \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..33f3c22 --- /dev/null +++ b/.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/.gitignore b/.gitignore new file mode 100644 index 0000000..72ef840 --- /dev/null +++ b/.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/LICENSE b/LICENSE new file mode 100644 index 0000000..2e83190 --- /dev/null +++ b/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/Makefile b/Makefile new file mode 100644 index 0000000..c1d5861 --- /dev/null +++ b/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}/$1:$2 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed3d167 --- /dev/null +++ b/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/vue/.browserslistrc b/vue/.browserslistrc new file mode 100644 index 0000000..dc3bc09 --- /dev/null +++ b/vue/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 diff --git a/vue/.commitlintrc.js b/vue/.commitlintrc.js new file mode 100644 index 0000000..02e33fa --- /dev/null +++ b/vue/.commitlintrc.js @@ -0,0 +1 @@ +export { default } from '@vben/commitlint-config'; diff --git a/vue/.dockerignore b/vue/.dockerignore new file mode 100644 index 0000000..52b833a --- /dev/null +++ b/vue/.dockerignore @@ -0,0 +1,7 @@ +node_modules +.git +.gitignore +*.md +dist +.turbo +dist.zip diff --git a/vue/.editorconfig b/vue/.editorconfig new file mode 100644 index 0000000..179aec6 --- /dev/null +++ b/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/vue/.husky/commit-msg b/vue/.husky/commit-msg new file mode 100644 index 0000000..270ebb8 --- /dev/null +++ b/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/vue/.husky/post-merge b/vue/.husky/post-merge new file mode 100644 index 0000000..83fa775 --- /dev/null +++ b/vue/.husky/post-merge @@ -0,0 +1,3 @@ +# 每次 git pull 之后, 安装依赖 + +pnpm install diff --git a/vue/.husky/pre-commit b/vue/.husky/pre-commit new file mode 100644 index 0000000..5dccee2 --- /dev/null +++ b/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/vue/.lintstagedrc.mjs b/vue/.lintstagedrc.mjs new file mode 100644 index 0000000..94b0192 --- /dev/null +++ b/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/vue/.node-version b/vue/.node-version new file mode 100644 index 0000000..ee5c244 --- /dev/null +++ b/vue/.node-version @@ -0,0 +1 @@ +22.1.0 diff --git a/vue/.npmrc b/vue/.npmrc new file mode 100644 index 0000000..aeac1ae --- /dev/null +++ b/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/vue/.prettierignore b/vue/.prettierignore new file mode 100644 index 0000000..d0b0ca1 --- /dev/null +++ b/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/vue/.prettierrc.mjs b/vue/.prettierrc.mjs new file mode 100644 index 0000000..3e25d2c --- /dev/null +++ b/vue/.prettierrc.mjs @@ -0,0 +1 @@ +export { default } from '@vben/prettier-config'; diff --git a/vue/.stylelintignore b/vue/.stylelintignore new file mode 100644 index 0000000..f4b2db2 --- /dev/null +++ b/vue/.stylelintignore @@ -0,0 +1,4 @@ +dist +public +__tests__ +coverage diff --git a/vue/.vscode/settings.json b/vue/.vscode/settings.json new file mode 100644 index 0000000..3f572bd --- /dev/null +++ b/vue/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "cSpell.words": [ + "iccid", + "imei", + "imsi", + "IOTLCM", + "msisdn" + ] +} \ No newline at end of file diff --git a/vue/README.md b/vue/README.md new file mode 100644 index 0000000..e84c839 --- /dev/null +++ b/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/vue/README.zh-CN.md b/vue/README.zh-CN.md new file mode 100644 index 0000000..e2f05bb --- /dev/null +++ b/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/vue/aaa.md b/vue/aaa.md new file mode 100644 index 0000000..641d002 --- /dev/null +++ b/vue/aaa.md @@ -0,0 +1,269 @@ +import { h, ref } from 'vue'; +import type { VxeGridProps } from '#/adapter/vxe-table'; +import { getPopupContainer } from '@vben/utils'; +import type { DescItem } from '#/components/description'; +import { cloneDeep } from 'lodash-es'; +import type { VbenFormSchema } from '@vben/common-ui'; +import { z } from '@vben/common-ui'; +import { renderDict, renderPopoverMemberSumma, type MemberSumma } from '#/utils'; +import { getDictOptions } from '#/utils/dict'; +import FormOptions from '#/constants/FormOption'; + +export class State { + public id = 0; // 主键ID + public apiName = ''; // 接口名称 + public apiCode = ''; // 接口权限标识 + public method = ''; // 请求方法:GET/POST/PUT/DELETE + public path = ''; // 接口路径 + public status = 0; // 状态:0启用,1停用 + public version = ''; // 接口版本 + public remark = ''; // 备注 + public tenantId = ''; // 租户ID + public createdDept = 0; // 创建部门 + public createdBy = 0; // 创建者 + public createdBySumma?: null | MemberSumma = null; // 创建者摘要信息 + public createdAt = ''; // 创建时间 + public updatedBy = 0; // 更新者 + public updatedBySumma?: null | MemberSumma = null; // 更新者摘要信息 + public updatedAt = ''; // 更新时间 + + constructor(state?: Partial) { + if (state) { + Object.assign(this, state); + } + } +} + +export function newState(state: State | Record | null): State { + if (state !== null) { + if (state instanceof State) { + return cloneDeep(state); + } + return new State(state); + } + return new State(); +} + +// 表单验证规则 + +// 表格搜索表单 +export const querySchema: VbenFormSchema[] = [ + { + fieldName: 'id', + component: 'InputNumber', + label: '主键ID', + componentProps: { + placeholder: '请输入主键ID', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, rules:null, + formItemClass: 'col-span-1', + }, { + fieldName: 'status', + component: 'Select', + label: '状态:0启用,1停用', + defaultValue: null, + componentProps: { + placeholder: '请选择状态:0启用,1停用', + options: getDictOptions('sys_common_status'), + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:'selectRequired', + formItemClass: 'col-span-1', + }, + { + fieldName: 'createdAt', + component: 'RangePicker', + label: '创建时间', + componentProps: { + type: 'datetimerange', + clearable: true, + valueFormat: 'YYYY-MM-DD HH:mm:ss', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, rules:null, + formItemClass: 'col-span-1', + },]; + +// 表格列 +export const columns: VxeGridProps['columns'] = [ + { + title: '接口名称', + field: 'apiName', + align: 'left', + width: -1, + }, + { + title: '接口权限标识', + field: 'apiCode', + align: 'left', + width: -1, + }, + { + title: '请求方法', + field: 'method', + align: 'left', + width: -1, + slots: { + default: ({ row }) => { + return renderDict(row.method, DictEnum.T_METHOD); + } + }, + }, + { + title: '接口路径', + field: 'path', + align: 'left', + width: -1, + }, + { + title: '状态', field: 'status', align: 'left', width: -1, + slots: { + default: ({ row }) => { + return renderDict(row.status, DictEnum.GLOBAL_ENABLED); + } + }, + }, + { + title: '接口版本', + field: 'version', + align: 'left', + width: -1, + }, + + { title: '操作', width: 120, slots: { default: 'action' } }, +]; + +// 表格列接口 +export interface RowType { + id: number; + apiName: string; + apiCode: string; + method: string; + path: string; + status: number; + version: string; + remark: string; + tenantId: string; + createdDept: number; + createdBy: number; + createdAt: string; + updatedBy: number; + updatedAt: string; +}; + +// 查看字段列表 +export const viewSchema: DescItem[] = [ + { field: 'apiName', label: '接口名称'}, + { field: 'apiCode', label: '接口权限标识'}, + { field: 'method', label: '请求方法:GET/POST/PUT/DELETE'}, + { field: 'path', label: '接口路径'}, + { + field: 'status', + label: '状态', + render: (val) => renderDict(val, 'sys_common_status'), + }, + { field: 'version', label: '接口版本'}, + { field: 'remark', label: '备注'}, +]; + +// 编辑字段列表 +export const editSchema: VbenFormSchema[] = [ + { + fieldName: 'id', + component: 'Input', + label: '主键ID', + dependencies: { show: () => false, triggerFields: [''], }, + componentProps: { + placeholder: '', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + formItemClass: 'col-span-1', + }, { + fieldName: 'apiName', + component: 'Input', + label: '接口名称', + componentProps: { + placeholder: '请输入接口名称', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:'required', + formItemClass: 'col-span-1', + }, { + fieldName: 'apiCode', + component: 'Input', + label: '接口权限标识', + componentProps: { + placeholder: '请输入接口权限标识', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:'required', + formItemClass: 'col-span-1', + }, { + fieldName: 'method', + component: 'Select', + label: '请求方法', + componentProps: { + placeholder: '请选择请求方法', + options: getDictOptions(DictEnum.T_METHOD ), + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:'required', + formItemClass: 'col-span-1', + }, { + fieldName: 'path', + component: 'Input', + label: '接口路径', + componentProps: { + placeholder: '请输入接口路径', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:'required', + formItemClass: 'col-span-1', + }, + { + fieldName: 'status', + component: 'Switch', + label: '状态', + defaultValue: 0, + componentProps: FormOptions.Component.SwitchEnabled(), + }, + { + fieldName: 'version', + component: 'Input', + label: '接口版本', + componentProps: { + placeholder: '请输入接口版本', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:'required', + formItemClass: 'col-span-1', + }, { + fieldName: 'remark', + component: 'Input', + label: '备注', + componentProps: { + placeholder: '请输入备注', + onUpdateValue: (e: any) => { + console.log(e); + }, + }, + rules:null, + formItemClass: 'col-span-1', + }, ]; \ No newline at end of file diff --git a/vue/apps/.gitignore b/vue/apps/.gitignore new file mode 100644 index 0000000..cadf95f --- /dev/null +++ b/vue/apps/.gitignore @@ -0,0 +1 @@ +backend-mock/nitro.config.ts diff --git a/vue/apps/web-antd/.env b/vue/apps/web-antd/.env new file mode 100644 index 0000000..5a5584d --- /dev/null +++ b/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/vue/apps/web-antd/.env.analyze b/vue/apps/web-antd/.env.analyze new file mode 100644 index 0000000..ffafa8d --- /dev/null +++ b/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/vue/apps/web-antd/.env.development b/vue/apps/web-antd/.env.development new file mode 100644 index 0000000..0e2c2ca --- /dev/null +++ b/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/vue/apps/web-antd/.env.production b/vue/apps/web-antd/.env.production new file mode 100644 index 0000000..87a0f8e --- /dev/null +++ b/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/vue/apps/web-antd/index.html b/vue/apps/web-antd/index.html new file mode 100644 index 0000000..6b58bda --- /dev/null +++ b/vue/apps/web-antd/index.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + +
+ + + diff --git a/vue/apps/web-antd/loading.html b/vue/apps/web-antd/loading.html new file mode 100644 index 0000000..7461939 --- /dev/null +++ b/vue/apps/web-antd/loading.html @@ -0,0 +1,290 @@ + +
+ +
+
正在初始化应用...
+
+ 请稍候,系统正在准备运行环境 +
+
智联·云
+
+
+ diff --git a/vue/apps/web-antd/package.json b/vue/apps/web-antd/package.json new file mode 100644 index 0000000..9d3f8b7 --- /dev/null +++ b/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": "annvben@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/vue/apps/web-antd/plugins/api-type-generator.ts b/vue/apps/web-antd/plugins/api-type-generator.ts new file mode 100644 index 0000000..19de09b --- /dev/null +++ b/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/vue/apps/web-antd/postcss.config.mjs b/vue/apps/web-antd/postcss.config.mjs new file mode 100644 index 0000000..3d80704 --- /dev/null +++ b/vue/apps/web-antd/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config/postcss'; diff --git a/vue/apps/web-antd/public/config.json b/vue/apps/web-antd/public/config.json new file mode 100644 index 0000000..e69de29 diff --git a/vue/apps/web-antd/public/favicon.ico b/vue/apps/web-antd/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..17edf348bfe8c42c5ee7dcc105b73ab5a40dbb2e GIT binary patch literal 16958 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
?;Fu^N$}! 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 V%WgRwIN)EPWF?g(s>F-}{vY?xc@O{q literal 0 HcmV?d00001 diff --git a/vue/apps/web-antd/public/setting.json b/vue/apps/web-antd/public/setting.json new file mode 100644 index 0000000..7ec7815 --- /dev/null +++ b/vue/apps/web-antd/public/setting.json @@ -0,0 +1,14 @@ +{ + "appTitle": "物联网全生命周期管理平台", + "appIcon": "/logo.png", + "loginPageTitle": "物联网设备上云首选", + "loginPageDescription": "新一代物联网设备统一接入平台", + "loginSloganImage": "", + "copyright": { + "companyName": "示例智联", + "companySiteLink": "https://www.xiujiezhilian.cn", + "date": "2024-2025", + "icp": "鲁ICP备2024117944号-1", + "icpLink": "https://beian.miit.gov.cn/" + } +} diff --git a/vue/apps/web-antd/src/adapter/component/antd.ts b/vue/apps/web-antd/src/adapter/component/antd.ts new file mode 100644 index 0000000..ec537dc --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/helpers/message.ts b/vue/apps/web-antd/src/adapter/component/helpers/message.ts new file mode 100644 index 0000000..81d7282 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/helpers/upload-preview.ts b/vue/apps/web-antd/src/adapter/component/helpers/upload-preview.ts new file mode 100644 index 0000000..2ab25b1 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/helpers/with-default-placeholder.ts b/vue/apps/web-antd/src/adapter/component/helpers/with-default-placeholder.ts new file mode 100644 index 0000000..c19be18 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/helpers/with-preview-upload.ts b/vue/apps/web-antd/src/adapter/component/helpers/with-preview-upload.ts new file mode 100644 index 0000000..305ffe8 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/index.ts b/vue/apps/web-antd/src/adapter/component/index.ts new file mode 100644 index 0000000..fb4b084 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/props.ts b/vue/apps/web-antd/src/adapter/component/props.ts new file mode 100644 index 0000000..09f6cc6 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/component/types.ts b/vue/apps/web-antd/src/adapter/component/types.ts new file mode 100644 index 0000000..fbced8b --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/form.ts b/vue/apps/web-antd/src/adapter/form.ts new file mode 100644 index 0000000..a6d01bd --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/highlightedit.ts b/vue/apps/web-antd/src/adapter/highlightedit.ts new file mode 100644 index 0000000..5eb7d16 --- /dev/null +++ b/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/vue/apps/web-antd/src/adapter/vxe-table.ts b/vue/apps/web-antd/src/adapter/vxe-table.ts new file mode 100644 index 0000000..b0a1f00 --- /dev/null +++ b/vue/apps/web-antd/src/adapter/vxe-table.ts @@ -0,0 +1,70 @@ +import type { VxeTableGridOptions } from '@vben/plugins/vxe-table'; + +import { h } from 'vue'; + +import { setupVbenVxeTable, useVbenVxeGrid } from '@vben/plugins/vxe-table'; + +import { Button, Image } from 'ant-design-vue'; + +import { useVbenForm } from './form'; + +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/vue/apps/web-antd/src/api/agent/index.ts b/vue/apps/web-antd/src/api/agent/index.ts new file mode 100644 index 0000000..55e4ddc --- /dev/null +++ b/vue/apps/web-antd/src/api/agent/index.ts @@ -0,0 +1,170 @@ +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 { + 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 function getAgentDeptListApi(params?: Record) { + return requestClient.get<{ items: AgentDept[]; 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: { userId: number; password: string }) { + 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/vue/apps/web-antd/src/api/agent/tApiGroup/index.ts b/vue/apps/web-antd/src/api/agent/tApiGroup/index.ts new file mode 100644 index 0000000..ff208af --- /dev/null +++ b/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/vue/apps/web-antd/src/api/agent/tApiResource/index.ts b/vue/apps/web-antd/src/api/agent/tApiResource/index.ts new file mode 100644 index 0000000..06b89a9 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tAgentBalance/index.ts b/vue/apps/web-antd/src/api/common/tAgentBalance/index.ts new file mode 100644 index 0000000..76c1ee7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tBalanceDetail/index.ts b/vue/apps/web-antd/src/api/common/tBalanceDetail/index.ts new file mode 100644 index 0000000..202af86 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tConsumeAccountMonthBill/index.ts b/vue/apps/web-antd/src/api/common/tConsumeAccountMonthBill/index.ts new file mode 100644 index 0000000..8a457d9 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tCreditDetail/index.ts b/vue/apps/web-antd/src/api/common/tCreditDetail/index.ts new file mode 100644 index 0000000..a5fa756 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tFinCommissionDetail/index.ts b/vue/apps/web-antd/src/api/common/tFinCommissionDetail/index.ts new file mode 100644 index 0000000..295540b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tFinWithdrawableChange/index.ts b/vue/apps/web-antd/src/api/common/tFinWithdrawableChange/index.ts new file mode 100644 index 0000000..75f4be1 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tFinanceApply/index.ts b/vue/apps/web-antd/src/api/common/tFinanceApply/index.ts new file mode 100644 index 0000000..030f58f --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tFinanceAuditRecord/index.ts b/vue/apps/web-antd/src/api/common/tFinanceAuditRecord/index.ts new file mode 100644 index 0000000..8fe376b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tMessageLog/index.ts b/vue/apps/web-antd/src/api/common/tMessageLog/index.ts new file mode 100644 index 0000000..28ca887 --- /dev/null +++ b/vue/apps/web-antd/src/api/common/tMessageLog/index.ts @@ -0,0 +1,29 @@ +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', + }); +} diff --git a/vue/apps/web-antd/src/api/common/tNotifyLog/index.ts b/vue/apps/web-antd/src/api/common/tNotifyLog/index.ts new file mode 100644 index 0000000..857001e --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tProfitAccountMonthBill/index.ts b/vue/apps/web-antd/src/api/common/tProfitAccountMonthBill/index.ts new file mode 100644 index 0000000..2bbcd5e --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tWoCommunication/index.ts b/vue/apps/web-antd/src/api/common/tWoCommunication/index.ts new file mode 100644 index 0000000..3601433 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tWoMain/index.ts b/vue/apps/web-antd/src/api/common/tWoMain/index.ts new file mode 100644 index 0000000..2738dec --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tWoRecord/index.ts b/vue/apps/web-antd/src/api/common/tWoRecord/index.ts new file mode 100644 index 0000000..ed7cfa8 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/core/auth.ts b/vue/apps/web-antd/src/api/core/auth.ts new file mode 100644 index 0000000..6500ca4 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/core/captcha.ts b/vue/apps/web-antd/src/api/core/captcha.ts new file mode 100644 index 0000000..b4c809b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/core/index.ts b/vue/apps/web-antd/src/api/core/index.ts new file mode 100644 index 0000000..949e7b6 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/core/menu.ts b/vue/apps/web-antd/src/api/core/menu.ts new file mode 100644 index 0000000..94cf36e --- /dev/null +++ b/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/vue/apps/web-antd/src/api/core/upload.ts b/vue/apps/web-antd/src/api/core/upload.ts new file mode 100644 index 0000000..3615ff6 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/core/user.ts b/vue/apps/web-antd/src/api/core/user.ts new file mode 100644 index 0000000..c1756af --- /dev/null +++ b/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/vue/apps/web-antd/src/api/gen/testCategory/index.ts b/vue/apps/web-antd/src/api/gen/testCategory/index.ts new file mode 100644 index 0000000..4d2c380 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/gen/testDemo/index.ts b/vue/apps/web-antd/src/api/gen/testDemo/index.ts new file mode 100644 index 0000000..7f38cb8 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/gen_codes/gen_table.ts b/vue/apps/web-antd/src/api/gen_codes/gen_table.ts new file mode 100644 index 0000000..b2dbb41 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/index.ts b/vue/apps/web-antd/src/api/index.ts new file mode 100644 index 0000000..5bcebc9 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tApi/index.ts b/vue/apps/web-antd/src/api/iotlcm/tApi/index.ts new file mode 100644 index 0000000..96f976c --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tApi/type.ts b/vue/apps/web-antd/src/api/iotlcm/tApi/type.ts new file mode 100644 index 0000000..71c57dc --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/index.ts b/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/index.ts new file mode 100644 index 0000000..9f03fb3 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/type.ts b/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannelTemplate/type.ts new file mode 100644 index 0000000..ed4e4b7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/index.ts b/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/index.ts new file mode 100644 index 0000000..c425fc9 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/type.ts b/vue/apps/web-antd/src/api/iotlcm/tChannel/tSimChannels/type.ts new file mode 100644 index 0000000..2311b9d --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/index.ts new file mode 100644 index 0000000..8fe9809 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardAllocate/type.ts new file mode 100644 index 0000000..ec0052f --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/index.ts new file mode 100644 index 0000000..2ebfdd3 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardBindPkg/type.ts new file mode 100644 index 0000000..615fabe --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/index.ts new file mode 100644 index 0000000..0a92e29 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardCancel/type.ts new file mode 100644 index 0000000..8579e33 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.test.ts new file mode 100644 index 0000000..8cf42ec --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/index.ts new file mode 100644 index 0000000..9d9e1ab --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardChange/type.ts new file mode 100644 index 0000000..5bd8b42 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.test.ts new file mode 100644 index 0000000..9cbd831 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/index.ts new file mode 100644 index 0000000..01058ce --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataCut/type.ts new file mode 100644 index 0000000..aab045f --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.test.ts new file mode 100644 index 0000000..2acc273 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStart/index.ts new file mode 100644 index 0000000..4438309 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.test.ts new file mode 100644 index 0000000..b99aa0b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardDataStop/index.ts new file mode 100644 index 0000000..062c20f --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.test.ts new file mode 100644 index 0000000..0c6b61d --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts new file mode 100644 index 0000000..ffa20e6 --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts @@ -0,0 +1,71 @@ +import { requestClient } from '#/api/request'; + +// 获取卡信息表列表 +export function List(params: any) { + return requestClient.get('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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/type.ts new file mode 100644 index 0000000..31919b4 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardLifecycle/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardLifecycle/type.ts new file mode 100644 index 0000000..d0c155b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.test.ts new file mode 100644 index 0000000..6114ffc --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/index.ts new file mode 100644 index 0000000..e7a016c --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRenew/type.ts new file mode 100644 index 0000000..e939fb0 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.test.ts new file mode 100644 index 0000000..bd41041 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardRestart/index.ts new file mode 100644 index 0000000..aaee594 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.test.ts new file mode 100644 index 0000000..a720347 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStart/index.ts new file mode 100644 index 0000000..23b0eb5 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.test.ts new file mode 100644 index 0000000..411a62b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardStop/index.ts new file mode 100644 index 0000000..a8a5a8d --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.test.ts new file mode 100644 index 0000000..1f4a578 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/index.ts new file mode 100644 index 0000000..a2875a1 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts new file mode 100644 index 0000000..ebc120a --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts @@ -0,0 +1,62 @@ +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 { + 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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts new file mode 100644 index 0000000..7234f53 --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts @@ -0,0 +1,126 @@ +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 typeModule = await import('./type'); + const res: typeof typeModule.TSimCardUnsubSubmitRes.prototype = { + 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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.ts new file mode 100644 index 0000000..85c71e9 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/type.ts new file mode 100644 index 0000000..3b8d672 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/index.ts new file mode 100644 index 0000000..ed0e945 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimPoolBindPackage/type.ts new file mode 100644 index 0000000..de1d563 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/index.ts new file mode 100644 index 0000000..e3f69a8 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimWarningConfig/type.ts new file mode 100644 index 0000000..0534836 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tDashboard/index.ts b/vue/apps/web-antd/src/api/iotlcm/tDashboard/index.ts new file mode 100644 index 0000000..e7189ae --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tDashboard/type.ts b/vue/apps/web-antd/src/api/iotlcm/tDashboard/type.ts new file mode 100644 index 0000000..69aea58 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tFlowPackageConfig/index.ts b/vue/apps/web-antd/src/api/iotlcm/tFlowPackageConfig/index.ts new file mode 100644 index 0000000..141a152 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts new file mode 100644 index 0000000..915e199 --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts @@ -0,0 +1,67 @@ +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 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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts new file mode 100644 index 0000000..26d4f6d --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts @@ -0,0 +1,268 @@ +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' +>; + +/** 获取批次主表列表 响应 */ +export type BatchMainListRes = GlobalListRes; + +/** 批次卡清单列表项 */ +export interface BatchCardListModel extends AllocationUnits { + /** 明细状态 */ + detailStatus?: number; + /** ICCID */ + iccid?: string; + /** IMSI */ + imsi?: string; + /** MSISDN */ + msisdn?: string; + /** 行号 */ + rowNo?: number; + [property: string]: any; +} + +/** 获取批次卡清单请求参数 */ +export interface BatchMainCardsParam { + /** 批次编号 */ + 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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/index.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/index.ts new file mode 100644 index 0000000..48783c7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/type.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardCancellation/type.ts new file mode 100644 index 0000000..15265a3 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.test.ts new file mode 100644 index 0000000..440f548 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardInbound/index.ts new file mode 100644 index 0000000..7966330 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts new file mode 100644 index 0000000..1f8b0d4 --- /dev/null +++ b/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: 60_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, + ); + }); + + 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, + ); + }); + + 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, + ); + }); +}); + +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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.ts new file mode 100644 index 0000000..8e19e11 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/index.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/index.ts new file mode 100644 index 0000000..a96e50a --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts new file mode 100644 index 0000000..f7e5a5a --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts @@ -0,0 +1,125 @@ +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; + /** 创建者 */ + 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/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts new file mode 100644 index 0000000..6058dda --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts @@ -0,0 +1,40 @@ +import type { + BatchExecutionLogDetailListParam, + BatchExecutionLogDetailListRes, + BatchExecutionLogListParam, + BatchExecutionLogListRes, + BatchExecutionLogSummaryParam, + BatchExecutionLogSummaryRes, +} 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, + }, + ); +} diff --git a/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts new file mode 100644 index 0000000..af8092a --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts @@ -0,0 +1,197 @@ +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; + /** 批次类型 */ + batchType?: number; + /** 来源方式 */ + sourceType?: null | number; + /** 总数量 */ + totalCount?: 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; + /** 批次类型 */ + batchType?: number; + /** 来源方式 */ + sourceType?: null | number; + /** 总数量 */ + totalCount?: number; + /** 运行结果 */ + runResult?: number; + /** 失败原因 */ + failReason?: string; + /** 源文件 */ + sourceFile?: BatchExecutionLogFileModel; + /** 结果文件 */ + resultFile?: BatchExecutionLogResultFileModel; + /** 开始时间 */ + startTime?: string; + /** 结束时间 */ + endTime?: string; +} + +/** 批次执行日志文件信息 */ +export interface BatchExecutionLogFileModel { + /** OSS文件ID */ + ossId?: number; + /** 文件URL */ + url?: string; +} + +/** 批次执行日志结果文件信息 */ +export interface BatchExecutionLogResultFileModel extends BatchExecutionLogFileModel { + /** 下载任务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 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/vue/apps/web-antd/src/api/iotlcm/tOrder/index.ts b/vue/apps/web-antd/src/api/iotlcm/tOrder/index.ts new file mode 100644 index 0000000..c0efd14 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/index.ts new file mode 100644 index 0000000..dee6fd7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/type.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackageInfo/type.ts new file mode 100644 index 0000000..42a315a --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/index.ts new file mode 100644 index 0000000..440bd7f --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/type.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPackagePrice/type.ts new file mode 100644 index 0000000..2affc71 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/index.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/index.ts new file mode 100644 index 0000000..5892413 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/type.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimFlowPool/type.ts new file mode 100644 index 0000000..177b08c --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/index.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/index.ts new file mode 100644 index 0000000..6d03714 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/type.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimPackageCategory/type.ts new file mode 100644 index 0000000..5a014ae --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/index.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/index.ts new file mode 100644 index 0000000..6414fff --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/type.ts b/vue/apps/web-antd/src/api/iotlcm/tPricingPackage/tSimUpstreamPackage/type.ts new file mode 100644 index 0000000..d75fc57 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/index.ts b/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/index.ts new file mode 100644 index 0000000..3876b57 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/type.ts b/vue/apps/web-antd/src/api/iotlcm/tSimDiagnose/type.ts new file mode 100644 index 0000000..112b5c8 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/index.ts b/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/index.ts new file mode 100644 index 0000000..cd32871 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts b/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts new file mode 100644 index 0000000..113819d --- /dev/null +++ b/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts @@ -0,0 +1,78 @@ +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/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/index.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/index.ts new file mode 100644 index 0000000..f7ebdfd --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/type.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tAgentEnterprise/type.ts new file mode 100644 index 0000000..9f39131 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/index.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/index.ts new file mode 100644 index 0000000..15c9fd5 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/type.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tCustWithdrawAccount/type.ts new file mode 100644 index 0000000..f8e89c6 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/index.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/index.ts new file mode 100644 index 0000000..d741c3c --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/type.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tDivisionCode/type.ts new file mode 100644 index 0000000..1d28dff --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/zAnother/tTplatformSetting/index.ts b/vue/apps/web-antd/src/api/iotlcm/zAnother/tTplatformSetting/index.ts new file mode 100644 index 0000000..4aba3f2 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/monitor/cache.ts b/vue/apps/web-antd/src/api/monitor/cache.ts new file mode 100644 index 0000000..47a4d2d --- /dev/null +++ b/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/vue/apps/web-antd/src/api/monitor/full-sync.test.ts b/vue/apps/web-antd/src/api/monitor/full-sync.test.ts new file mode 100644 index 0000000..80fcf86 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/monitor/full-sync.ts b/vue/apps/web-antd/src/api/monitor/full-sync.ts new file mode 100644 index 0000000..a57c398 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/monitor/index.ts b/vue/apps/web-antd/src/api/monitor/index.ts new file mode 100644 index 0000000..8a9ace0 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/monitor/online.ts b/vue/apps/web-antd/src/api/monitor/online.ts new file mode 100644 index 0000000..3c6027d --- /dev/null +++ b/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/vue/apps/web-antd/src/api/regions/index.ts b/vue/apps/web-antd/src/api/regions/index.ts new file mode 100644 index 0000000..8b7388c --- /dev/null +++ b/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/vue/apps/web-antd/src/api/request.ts b/vue/apps/web-antd/src/api/request.ts new file mode 100644 index 0000000..c574682 --- /dev/null +++ b/vue/apps/web-antd/src/api/request.ts @@ -0,0 +1,231 @@ +/** + * @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')) { + if (config.responseType === 'blob' && Reflect.has(responseData, 'data')) + { + // 这时候的data为blob类型 + const blob = responseData.data as unknown as Blob; + // 拿到字符串转json对象 + responseData.data = JSON.parse(await blob.text()); + } + } 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/vue/apps/web-antd/src/api/system/client.ts b/vue/apps/web-antd/src/api/system/client.ts new file mode 100644 index 0000000..50bcd7b --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/config.ts b/vue/apps/web-antd/src/api/system/config.ts new file mode 100644 index 0000000..59232f3 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/dept.ts b/vue/apps/web-antd/src/api/system/dept.ts new file mode 100644 index 0000000..bfe71aa --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/dict.ts b/vue/apps/web-antd/src/api/system/dict.ts new file mode 100644 index 0000000..92ec7ed --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/index.ts b/vue/apps/web-antd/src/api/system/index.ts new file mode 100644 index 0000000..210e362 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/job.ts b/vue/apps/web-antd/src/api/system/job.ts new file mode 100644 index 0000000..450fe00 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/logininfor.ts b/vue/apps/web-antd/src/api/system/logininfor.ts new file mode 100644 index 0000000..3bd5fbc --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/menu.ts b/vue/apps/web-antd/src/api/system/menu.ts new file mode 100644 index 0000000..0f4047d --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/notice.ts b/vue/apps/web-antd/src/api/system/notice.ts new file mode 100644 index 0000000..ac9fba2 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/oper-log.ts b/vue/apps/web-antd/src/api/system/oper-log.ts new file mode 100644 index 0000000..94a8dfb --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/oss-config.ts b/vue/apps/web-antd/src/api/system/oss-config.ts new file mode 100644 index 0000000..ce27bef --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/oss.ts b/vue/apps/web-antd/src/api/system/oss.ts new file mode 100644 index 0000000..b540332 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/post.ts b/vue/apps/web-antd/src/api/system/post.ts new file mode 100644 index 0000000..15bf175 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/qrcode.ts b/vue/apps/web-antd/src/api/system/qrcode.ts new file mode 100644 index 0000000..749054a --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/role.ts b/vue/apps/web-antd/src/api/system/role.ts new file mode 100644 index 0000000..7ce3da0 --- /dev/null +++ b/vue/apps/web-antd/src/api/system/role.ts @@ -0,0 +1,136 @@ +/** + * @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; + 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 { + 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/vue/apps/web-antd/src/api/system/social.ts b/vue/apps/web-antd/src/api/system/social.ts new file mode 100644 index 0000000..5dc5086 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/sysNoticeUser/index.ts b/vue/apps/web-antd/src/api/system/sysNoticeUser/index.ts new file mode 100644 index 0000000..daff7a7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/tTplatformSetting.ts b/vue/apps/web-antd/src/api/system/tTplatformSetting.ts new file mode 100644 index 0000000..ddc0dc7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/tenant.ts b/vue/apps/web-antd/src/api/system/tenant.ts new file mode 100644 index 0000000..b1fcdf7 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/tenant_package.ts b/vue/apps/web-antd/src/api/system/tenant_package.ts new file mode 100644 index 0000000..844bcec --- /dev/null +++ b/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/vue/apps/web-antd/src/api/system/user.ts b/vue/apps/web-antd/src/api/system/user.ts new file mode 100644 index 0000000..97cead5 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/utils/index.ts b/vue/apps/web-antd/src/api/utils/index.ts new file mode 100644 index 0000000..e162956 --- /dev/null +++ b/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/vue/apps/web-antd/src/app.vue b/vue/apps/web-antd/src/app.vue new file mode 100644 index 0000000..5f6d937 --- /dev/null +++ b/vue/apps/web-antd/src/app.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/vue/apps/web-antd/src/assets/icons/custom.ts b/vue/apps/web-antd/src/assets/icons/custom.ts new file mode 100644 index 0000000..743b95b --- /dev/null +++ b/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/vue/apps/web-antd/src/assets/icons/index.ts b/vue/apps/web-antd/src/assets/icons/index.ts new file mode 100644 index 0000000..3ec0d7b --- /dev/null +++ b/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/vue/apps/web-antd/src/assets/icons/mdiSlim.ts b/vue/apps/web-antd/src/assets/icons/mdiSlim.ts new file mode 100644 index 0000000..285e681 --- /dev/null +++ b/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/vue/apps/web-antd/src/bootstrap.ts b/vue/apps/web-antd/src/bootstrap.ts new file mode 100644 index 0000000..ec72112 --- /dev/null +++ b/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/vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue b/vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue new file mode 100644 index 0000000..82ddf97 --- /dev/null +++ b/vue/apps/web-antd/src/components/HtCustom/FormExpand/RegionSelect/index.vue @@ -0,0 +1,183 @@ + + + + + diff --git a/vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue b/vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue new file mode 100644 index 0000000..f3d524b --- /dev/null +++ b/vue/apps/web-antd/src/components/HtCustom/FormExpand/Switch/index.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue b/vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue new file mode 100644 index 0000000..e8ec865 --- /dev/null +++ b/vue/apps/web-antd/src/components/HtCustom/FormExpand/TextArea/index.vue @@ -0,0 +1,28 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/textarea/index.ts new file mode 100644 index 0000000..e2d4773 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue new file mode 100644 index 0000000..299b669 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroup.vue @@ -0,0 +1,44 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue new file mode 100644 index 0000000..615562f --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/ToggleGroupItem.vue @@ -0,0 +1,48 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle-group/index.ts new file mode 100644 index 0000000..ac3e34b --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue new file mode 100644 index 0000000..779a60c --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/Toggle.vue @@ -0,0 +1,47 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/index.ts new file mode 100644 index 0000000..ecc1e3f --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/toggle/toggle.ts new file mode 100644 index 0000000..d251328 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue new file mode 100644 index 0000000..95aef73 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/Tooltip.vue @@ -0,0 +1,16 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue new file mode 100644 index 0000000..0a6be32 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipContent.vue @@ -0,0 +1,48 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue new file mode 100644 index 0000000..6ad95a0 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipProvider.vue @@ -0,0 +1,13 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue new file mode 100644 index 0000000..52d1e64 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/TooltipTrigger.vue @@ -0,0 +1,13 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tooltip/index.ts new file mode 100644 index 0000000..94e681c --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/index.ts new file mode 100644 index 0000000..d390f63 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue new file mode 100644 index 0000000..c2c7607 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/tree.vue @@ -0,0 +1,467 @@ + + + diff --git a/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts b/vue/packages/@core/ui-kit/shadcn-ui/src/ui/tree/types.ts new file mode 100644 index 0000000..53118ba --- /dev/null +++ b/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/vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs b/vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs new file mode 100644 index 0000000..f17f556 --- /dev/null +++ b/vue/packages/@core/ui-kit/shadcn-ui/tailwind.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config'; diff --git a/vue/packages/@core/ui-kit/shadcn-ui/tsconfig.json b/vue/packages/@core/ui-kit/shadcn-ui/tsconfig.json new file mode 100644 index 0000000..0a46bc5 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/build.config.ts b/vue/packages/@core/ui-kit/tabs-ui/build.config.ts new file mode 100644 index 0000000..18eaa60 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/package.json b/vue/packages/@core/ui-kit/tabs-ui/package.json new file mode 100644 index 0000000..0bb4dc4 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs b/vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs new file mode 100644 index 0000000..3d80704 --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config/postcss'; diff --git a/vue/packages/@core/ui-kit/tabs-ui/src/components/index.ts b/vue/packages/@core/ui-kit/tabs-ui/src/components/index.ts new file mode 100644 index 0000000..eafeaa6 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue b/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue new file mode 100644 index 0000000..faa1b94 --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue b/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue new file mode 100644 index 0000000..effa93c --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue @@ -0,0 +1,148 @@ + + + diff --git a/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts b/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/index.ts new file mode 100644 index 0000000..a26899e --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue b/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue new file mode 100644 index 0000000..24f43a9 --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-more.vue @@ -0,0 +1,18 @@ + + + diff --git a/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue b/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue new file mode 100644 index 0000000..acbf14e --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/src/components/widgets/tool-screen.vue @@ -0,0 +1,19 @@ + + + diff --git a/vue/packages/@core/ui-kit/tabs-ui/src/index.ts b/vue/packages/@core/ui-kit/tabs-ui/src/index.ts new file mode 100644 index 0000000..6d562db --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue b/vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue new file mode 100644 index 0000000..7549419 --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/src/tabs-view.vue @@ -0,0 +1,106 @@ + + + diff --git a/vue/packages/@core/ui-kit/tabs-ui/src/types.ts b/vue/packages/@core/ui-kit/tabs-ui/src/types.ts new file mode 100644 index 0000000..19ecf03 --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts b/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-drag.ts new file mode 100644 index 0000000..b9c2e8a --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts b/vue/packages/@core/ui-kit/tabs-ui/src/use-tabs-view-scroll.ts new file mode 100644 index 0000000..aef32df --- /dev/null +++ b/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/vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs b/vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs new file mode 100644 index 0000000..f17f556 --- /dev/null +++ b/vue/packages/@core/ui-kit/tabs-ui/tailwind.config.mjs @@ -0,0 +1 @@ +export { default } from '@vben/tailwind-config'; diff --git a/vue/packages/@core/ui-kit/tabs-ui/tsconfig.json b/vue/packages/@core/ui-kit/tabs-ui/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/constants/README.md b/vue/packages/constants/README.md new file mode 100644 index 0000000..67936a6 --- /dev/null +++ b/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/vue/packages/constants/package.json b/vue/packages/constants/package.json new file mode 100644 index 0000000..249418f --- /dev/null +++ b/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/vue/packages/constants/src/core.ts b/vue/packages/constants/src/core.ts new file mode 100644 index 0000000..7d56375 --- /dev/null +++ b/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/vue/packages/constants/src/dict-enum.ts b/vue/packages/constants/src/dict-enum.ts new file mode 100644 index 0000000..8a3d3e7 --- /dev/null +++ b/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/vue/packages/constants/src/index.ts b/vue/packages/constants/src/index.ts new file mode 100644 index 0000000..8870dbb --- /dev/null +++ b/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/vue/packages/constants/tsconfig.json b/vue/packages/constants/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/effects/README.md b/vue/packages/effects/README.md new file mode 100644 index 0000000..4965b51 --- /dev/null +++ b/vue/packages/effects/README.md @@ -0,0 +1,10 @@ +## Effects 目录 + +`effects` 目录专门用于存放与轻微耦合相关的代码和逻辑。如果你的包具有以下特点,建议将其放置在 `effects` 目录下: + +- **状态管理**:使用状态管理框架 `pinia`,并包含处理副作用(如异步操作、API 调用)的部分。 +- **用户偏好设置**:使用 `@vben-core/preferences` 处理用户偏好设置,涉及本地存储或浏览器缓存逻辑(如使用 `localStorage`)。 +- **导航和路由**:处理导航、页面跳转等场景,需要管理路由变化的逻辑。 +- **组件库依赖**:包含与特定组件库紧密耦合或依赖大型仓库的部分。 + +通过将相关代码归类到 `effects` 目录,可以使项目结构更加清晰,便于维护和扩展。 diff --git a/vue/packages/effects/access/package.json b/vue/packages/effects/access/package.json new file mode 100644 index 0000000..c23018a --- /dev/null +++ b/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/vue/packages/effects/access/src/access-control.vue b/vue/packages/effects/access/src/access-control.vue new file mode 100644 index 0000000..370e995 --- /dev/null +++ b/vue/packages/effects/access/src/access-control.vue @@ -0,0 +1,47 @@ + + + + diff --git a/vue/packages/effects/access/src/accessible.ts b/vue/packages/effects/access/src/accessible.ts new file mode 100644 index 0000000..eb90814 --- /dev/null +++ b/vue/packages/effects/access/src/accessible.ts @@ -0,0 +1,156 @@ +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 = router.getRoutes().find((item) => item.path === '/'); + + // 获取已有的路由名称列表 + 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 }; +} + +/** + * 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/vue/packages/effects/access/src/directive.ts b/vue/packages/effects/access/src/directive.ts new file mode 100644 index 0000000..35d9d51 --- /dev/null +++ b/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/vue/packages/effects/access/src/index.ts b/vue/packages/effects/access/src/index.ts new file mode 100644 index 0000000..392aa53 --- /dev/null +++ b/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/vue/packages/effects/access/src/use-access.ts b/vue/packages/effects/access/src/use-access.ts new file mode 100644 index 0000000..939cdbe --- /dev/null +++ b/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/vue/packages/effects/access/tsconfig.json b/vue/packages/effects/access/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/effects/common-ui/package.json b/vue/packages/effects/common-ui/package.json new file mode 100644 index 0000000..5a34a26 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/api-component/api-component.vue b/vue/packages/effects/common-ui/src/components/api-component/api-component.vue new file mode 100644 index 0000000..38419a7 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/api-component/api-component.vue @@ -0,0 +1,299 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/api-component/index.ts b/vue/packages/effects/common-ui/src/components/api-component/index.ts new file mode 100644 index 0000000..9815763 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts b/vue/packages/effects/common-ui/src/components/captcha/hooks/useCaptchaPoints.ts new file mode 100644 index 0000000..a3f61fd --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue b/vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/image-captcha/index.vue @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vue/packages/effects/common-ui/src/components/captcha/index.ts b/vue/packages/effects/common-ui/src/components/captcha/index.ts new file mode 100644 index 0000000..13634cd --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue b/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue new file mode 100644 index 0000000..ece28d0 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/index.vue @@ -0,0 +1,176 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue b/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/vue/packages/effects/common-ui/src/components/captcha/point-selection-captcha/point-selection-captcha-card.vue @@ -0,0 +1,84 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue new file mode 100644 index 0000000..cad3cdd --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/index.vue @@ -0,0 +1,244 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue new file mode 100644 index 0000000..7f97bdc --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-action.vue @@ -0,0 +1,65 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue new file mode 100644 index 0000000..0884ccb --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-bar.vue @@ -0,0 +1,40 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue new file mode 100644 index 0000000..0e79f7b --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/slider-captcha/slider-captcha-content.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue b/vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue new file mode 100644 index 0000000..8894589 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/slider-rotate-captcha/index.vue @@ -0,0 +1,213 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue b/vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue new file mode 100644 index 0000000..81b7342 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/captcha/slider-translate-captcha/index.vue @@ -0,0 +1,311 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/captcha/types.ts b/vue/packages/effects/common-ui/src/components/captcha/types.ts new file mode 100644 index 0000000..cd1efdf --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/col-page/col-page.vue b/vue/packages/effects/common-ui/src/components/col-page/col-page.vue new file mode 100644 index 0000000..c3f9d68 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/col-page/col-page.vue @@ -0,0 +1,107 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/col-page/index.ts b/vue/packages/effects/common-ui/src/components/col-page/index.ts new file mode 100644 index 0000000..11b3305 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/col-page/types.ts b/vue/packages/effects/common-ui/src/components/col-page/types.ts new file mode 100644 index 0000000..491d1e6 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/count-to/count-to.vue b/vue/packages/effects/common-ui/src/components/count-to/count-to.vue new file mode 100644 index 0000000..d6b0943 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/count-to/count-to.vue @@ -0,0 +1,123 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/count-to/index.ts b/vue/packages/effects/common-ui/src/components/count-to/index.ts new file mode 100644 index 0000000..d942796 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/count-to/types.ts b/vue/packages/effects/common-ui/src/components/count-to/types.ts new file mode 100644 index 0000000..0b3bd82 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue b/vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue new file mode 100644 index 0000000..12f44bd --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue @@ -0,0 +1,232 @@ + + + + diff --git a/vue/packages/effects/common-ui/src/components/ellipsis-text/index.ts b/vue/packages/effects/common-ui/src/components/ellipsis-text/index.ts new file mode 100644 index 0000000..67a236c --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue b/vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue new file mode 100644 index 0000000..c602274 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue @@ -0,0 +1,318 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/icon-picker/icons.ts b/vue/packages/effects/common-ui/src/components/icon-picker/icons.ts new file mode 100644 index 0000000..694e904 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/icon-picker/index.ts b/vue/packages/effects/common-ui/src/components/icon-picker/index.ts new file mode 100644 index 0000000..3dabc86 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/index.ts b/vue/packages/effects/common-ui/src/components/index.ts new file mode 100644 index 0000000..9ff0d5e --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/json-preview/index.ts b/vue/packages/effects/common-ui/src/components/json-preview/index.ts new file mode 100644 index 0000000..332d22c --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue b/vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue new file mode 100644 index 0000000..58c7aaa --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/json-preview/json-preview.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/vue/packages/effects/common-ui/src/components/json-viewer/index.ts b/vue/packages/effects/common-ui/src/components/json-viewer/index.ts new file mode 100644 index 0000000..1aec78b --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/json-viewer/index.vue b/vue/packages/effects/common-ui/src/components/json-viewer/index.vue new file mode 100644 index 0000000..f66c318 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/json-viewer/index.vue @@ -0,0 +1,112 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/json-viewer/style.scss b/vue/packages/effects/common-ui/src/components/json-viewer/style.scss new file mode 100644 index 0000000..47acb89 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/json-viewer/types.ts b/vue/packages/effects/common-ui/src/components/json-viewer/types.ts new file mode 100644 index 0000000..8f3a206 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/loading/directive.ts b/vue/packages/effects/common-ui/src/components/loading/directive.ts new file mode 100644 index 0000000..973a605 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/loading/index.ts b/vue/packages/effects/common-ui/src/components/loading/index.ts new file mode 100644 index 0000000..2fbfb04 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/loading/loading.vue b/vue/packages/effects/common-ui/src/components/loading/loading.vue new file mode 100644 index 0000000..faf49e6 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/loading/loading.vue @@ -0,0 +1,39 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/loading/spinner.vue b/vue/packages/effects/common-ui/src/components/loading/spinner.vue new file mode 100644 index 0000000..caee2bb --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/loading/spinner.vue @@ -0,0 +1,28 @@ + + diff --git a/vue/packages/effects/common-ui/src/components/page/__tests__/page.test.ts b/vue/packages/effects/common-ui/src/components/page/__tests__/page.test.ts new file mode 100644 index 0000000..a89061f --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/page/index.ts b/vue/packages/effects/common-ui/src/components/page/index.ts new file mode 100644 index 0000000..fd9e02f --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/page/page.vue b/vue/packages/effects/common-ui/src/components/page/page.vue new file mode 100644 index 0000000..4a0ea54 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/page/page.vue @@ -0,0 +1,100 @@ + + + diff --git a/vue/packages/effects/common-ui/src/components/page/types.ts b/vue/packages/effects/common-ui/src/components/page/types.ts new file mode 100644 index 0000000..c7331ae --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/resize/index.ts b/vue/packages/effects/common-ui/src/components/resize/index.ts new file mode 100644 index 0000000..f937522 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/resize/index.ts @@ -0,0 +1 @@ +export { default as VResize } from './resize.vue'; diff --git a/vue/packages/effects/common-ui/src/components/resize/resize.vue b/vue/packages/effects/common-ui/src/components/resize/resize.vue new file mode 100644 index 0000000..68be4d9 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/resize/resize.vue @@ -0,0 +1,1120 @@ + + + + + diff --git a/vue/packages/effects/common-ui/src/components/tippy/directive.ts b/vue/packages/effects/common-ui/src/components/tippy/directive.ts new file mode 100644 index 0000000..ed277d6 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/tippy/index.ts b/vue/packages/effects/common-ui/src/components/tippy/index.ts new file mode 100644 index 0000000..6080e58 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/components/tree/index.ts b/vue/packages/effects/common-ui/src/components/tree/index.ts new file mode 100644 index 0000000..ce3bc5c --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/tree/index.ts @@ -0,0 +1 @@ +export { default as Tree } from './tree.vue'; diff --git a/vue/packages/effects/common-ui/src/components/tree/tree.vue b/vue/packages/effects/common-ui/src/components/tree/tree.vue new file mode 100644 index 0000000..1f2fcc1 --- /dev/null +++ b/vue/packages/effects/common-ui/src/components/tree/tree.vue @@ -0,0 +1,25 @@ + + + diff --git a/vue/packages/effects/common-ui/src/index.ts b/vue/packages/effects/common-ui/src/index.ts new file mode 100644 index 0000000..27bd718 --- /dev/null +++ b/vue/packages/effects/common-ui/src/index.ts @@ -0,0 +1,2 @@ +export * from './components'; +export * from './ui'; diff --git a/vue/packages/effects/common-ui/src/ui/about/about.ts b/vue/packages/effects/common-ui/src/ui/about/about.ts new file mode 100644 index 0000000..c4cf957 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/about/about.vue b/vue/packages/effects/common-ui/src/ui/about/about.vue new file mode 100644 index 0000000..bee8b34 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/about/about.vue @@ -0,0 +1,183 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/about/index.ts b/vue/packages/effects/common-ui/src/ui/about/index.ts new file mode 100644 index 0000000..5860f5b --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/about/index.ts @@ -0,0 +1 @@ +export { default as About } from './about.vue'; diff --git a/vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue b/vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue new file mode 100644 index 0000000..3ed9a6b --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/auth-title.vue @@ -0,0 +1,13 @@ + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/code-login.vue b/vue/packages/effects/common-ui/src/ui/authentication/code-login.vue new file mode 100644 index 0000000..d7563d8 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/code-login.vue @@ -0,0 +1,127 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue b/vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue new file mode 100644 index 0000000..80b123c --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/dingding-login.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue b/vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue new file mode 100644 index 0000000..9c82df4 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/forget-password.vue @@ -0,0 +1,116 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/index.ts b/vue/packages/effects/common-ui/src/ui/authentication/index.ts new file mode 100644 index 0000000..ac5e1e0 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue b/vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue new file mode 100644 index 0000000..ef5e6a0 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/login-expired-modal.vue @@ -0,0 +1,95 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/login.vue b/vue/packages/effects/common-ui/src/ui/authentication/login.vue new file mode 100644 index 0000000..bcb8f21 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/login.vue @@ -0,0 +1,186 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue b/vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue new file mode 100644 index 0000000..c8f235c --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/qrcode-login.vue @@ -0,0 +1,105 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/register.vue b/vue/packages/effects/common-ui/src/ui/authentication/register.vue new file mode 100644 index 0000000..69a69d4 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/register.vue @@ -0,0 +1,121 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue b/vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue new file mode 100644 index 0000000..8c39ebf --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/authentication/third-party-login.vue @@ -0,0 +1,71 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/authentication/types.ts b/vue/packages/effects/common-ui/src/ui/authentication/types.ts new file mode 100644 index 0000000..cb297e2 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue new file mode 100644 index 0000000..294d517 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-chart-card.vue @@ -0,0 +1,24 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue new file mode 100644 index 0000000..453ee5c --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-charts-tabs.vue @@ -0,0 +1,40 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue new file mode 100644 index 0000000..18c4929 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/analysis-overview.vue @@ -0,0 +1,55 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts b/vue/packages/effects/common-ui/src/ui/dashboard/analysis/index.ts new file mode 100644 index 0000000..7c67b87 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/dashboard/index.ts b/vue/packages/effects/common-ui/src/ui/dashboard/index.ts new file mode 100644 index 0000000..bc74424 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/dashboard/typing.ts b/vue/packages/effects/common-ui/src/ui/dashboard/typing.ts new file mode 100644 index 0000000..48fc9c7 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/index.ts new file mode 100644 index 0000000..76b7af1 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue new file mode 100644 index 0000000..a3ea3eb --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-header.vue @@ -0,0 +1,46 @@ + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue new file mode 100644 index 0000000..590c334 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-project.vue @@ -0,0 +1,65 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue new file mode 100644 index 0000000..86dc5c6 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-quick-nav.vue @@ -0,0 +1,56 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue new file mode 100644 index 0000000..ef34cd0 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-todo.vue @@ -0,0 +1,63 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue new file mode 100644 index 0000000..06f2a5e --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/dashboard/workbench/workbench-trends.vue @@ -0,0 +1,64 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/fallback.ts b/vue/packages/effects/common-ui/src/ui/fallback/fallback.ts new file mode 100644 index 0000000..5f8e193 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/fallback/fallback.vue b/vue/packages/effects/common-ui/src/ui/fallback/fallback.vue new file mode 100644 index 0000000..76eafca --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/fallback.vue @@ -0,0 +1,164 @@ + + + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue new file mode 100644 index 0000000..e390867 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-403.vue @@ -0,0 +1,151 @@ + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue new file mode 100644 index 0000000..385cf6a --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-404.vue @@ -0,0 +1,154 @@ + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue new file mode 100644 index 0000000..97326b7 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-500.vue @@ -0,0 +1,215 @@ + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue new file mode 100644 index 0000000..e511c43 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-coming-soon.vue @@ -0,0 +1,262 @@ + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue new file mode 100644 index 0000000..9e50b19 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/icons/icon-offline.vue @@ -0,0 +1,112 @@ + diff --git a/vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg b/vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg new file mode 100644 index 0000000..951a905 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/fallback/icons/warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vue/packages/effects/common-ui/src/ui/fallback/index.ts b/vue/packages/effects/common-ui/src/ui/fallback/index.ts new file mode 100644 index 0000000..f56f665 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/index.ts b/vue/packages/effects/common-ui/src/ui/index.ts new file mode 100644 index 0000000..8b1db55 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/profile/base-setting.vue b/vue/packages/effects/common-ui/src/ui/profile/base-setting.vue new file mode 100644 index 0000000..1ef1c1a --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/profile/base-setting.vue @@ -0,0 +1,56 @@ + + diff --git a/vue/packages/effects/common-ui/src/ui/profile/index.ts b/vue/packages/effects/common-ui/src/ui/profile/index.ts new file mode 100644 index 0000000..209a2e8 --- /dev/null +++ b/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/vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue b/vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue new file mode 100644 index 0000000..9a3e488 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/profile/notification-setting.vue @@ -0,0 +1,53 @@ + + diff --git a/vue/packages/effects/common-ui/src/ui/profile/password-setting.vue b/vue/packages/effects/common-ui/src/ui/profile/password-setting.vue new file mode 100644 index 0000000..1d90e08 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/profile/password-setting.vue @@ -0,0 +1,56 @@ + + diff --git a/vue/packages/effects/common-ui/src/ui/profile/profile.vue b/vue/packages/effects/common-ui/src/ui/profile/profile.vue new file mode 100644 index 0000000..5ab39e6 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/profile/profile.vue @@ -0,0 +1,62 @@ + + diff --git a/vue/packages/effects/common-ui/src/ui/profile/security-setting.vue b/vue/packages/effects/common-ui/src/ui/profile/security-setting.vue new file mode 100644 index 0000000..9a3e488 --- /dev/null +++ b/vue/packages/effects/common-ui/src/ui/profile/security-setting.vue @@ -0,0 +1,53 @@ + + diff --git a/vue/packages/effects/common-ui/src/ui/profile/types.ts b/vue/packages/effects/common-ui/src/ui/profile/types.ts new file mode 100644 index 0000000..e600bde --- /dev/null +++ b/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/vue/packages/effects/common-ui/tsconfig.json b/vue/packages/effects/common-ui/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/effects/hooks/README.md b/vue/packages/effects/hooks/README.md new file mode 100644 index 0000000..54d9ff7 --- /dev/null +++ b/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/vue/packages/effects/hooks/package.json b/vue/packages/effects/hooks/package.json new file mode 100644 index 0000000..76d83a5 --- /dev/null +++ b/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/vue/packages/effects/hooks/src/index.ts b/vue/packages/effects/hooks/src/index.ts new file mode 100644 index 0000000..c189fd7 --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-app-config.ts b/vue/packages/effects/hooks/src/use-app-config.ts new file mode 100644 index 0000000..41f383c --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-content-maximize.ts b/vue/packages/effects/hooks/src/use-content-maximize.ts new file mode 100644 index 0000000..77d1fab --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-design-tokens.ts b/vue/packages/effects/hooks/src/use-design-tokens.ts new file mode 100644 index 0000000..6a076f3 --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-hover-toggle.ts b/vue/packages/effects/hooks/src/use-hover-toggle.ts new file mode 100644 index 0000000..0bed41d --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-pagination.ts b/vue/packages/effects/hooks/src/use-pagination.ts new file mode 100644 index 0000000..0115606 --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-refresh.ts b/vue/packages/effects/hooks/src/use-refresh.ts new file mode 100644 index 0000000..b3a5cae --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-tabs.ts b/vue/packages/effects/hooks/src/use-tabs.ts new file mode 100644 index 0000000..5267211 --- /dev/null +++ b/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/vue/packages/effects/hooks/src/use-watermark.ts b/vue/packages/effects/hooks/src/use-watermark.ts new file mode 100644 index 0000000..8484a08 --- /dev/null +++ b/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/vue/packages/effects/hooks/tsconfig.json b/vue/packages/effects/hooks/tsconfig.json new file mode 100644 index 0000000..b13aa7a --- /dev/null +++ b/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/vue/packages/effects/layouts/package.json b/vue/packages/effects/layouts/package.json new file mode 100644 index 0000000..3c195d3 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/authentication/authentication.vue b/vue/packages/effects/layouts/src/authentication/authentication.vue new file mode 100644 index 0000000..6d3bf8c --- /dev/null +++ b/vue/packages/effects/layouts/src/authentication/authentication.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/vue/packages/effects/layouts/src/authentication/form.vue b/vue/packages/effects/layouts/src/authentication/form.vue new file mode 100644 index 0000000..fa73e12 --- /dev/null +++ b/vue/packages/effects/layouts/src/authentication/form.vue @@ -0,0 +1,38 @@ + + + diff --git a/vue/packages/effects/layouts/src/authentication/icons/slogan.vue b/vue/packages/effects/layouts/src/authentication/icons/slogan.vue new file mode 100644 index 0000000..82cc119 --- /dev/null +++ b/vue/packages/effects/layouts/src/authentication/icons/slogan.vue @@ -0,0 +1,4568 @@ + diff --git a/vue/packages/effects/layouts/src/authentication/index.ts b/vue/packages/effects/layouts/src/authentication/index.ts new file mode 100644 index 0000000..d7c1c29 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/authentication/toolbar.vue b/vue/packages/effects/layouts/src/authentication/toolbar.vue new file mode 100644 index 0000000..94d321a --- /dev/null +++ b/vue/packages/effects/layouts/src/authentication/toolbar.vue @@ -0,0 +1,49 @@ + + + diff --git a/vue/packages/effects/layouts/src/authentication/types.ts b/vue/packages/effects/layouts/src/authentication/types.ts new file mode 100644 index 0000000..c4c1c7f --- /dev/null +++ b/vue/packages/effects/layouts/src/authentication/types.ts @@ -0,0 +1 @@ +export type ToolbarType = 'color' | 'language' | 'layout' | 'theme'; diff --git a/vue/packages/effects/layouts/src/basic/README.md b/vue/packages/effects/layouts/src/basic/README.md new file mode 100644 index 0000000..b1266ea --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/content/content-spinner.vue b/vue/packages/effects/layouts/src/basic/content/content-spinner.vue new file mode 100644 index 0000000..e97e4b6 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/content/content-spinner.vue @@ -0,0 +1,12 @@ + + diff --git a/vue/packages/effects/layouts/src/basic/content/content.vue b/vue/packages/effects/layouts/src/basic/content/content.vue new file mode 100644 index 0000000..8b8a639 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/content/content.vue @@ -0,0 +1,148 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/content/index.ts b/vue/packages/effects/layouts/src/basic/content/index.ts new file mode 100644 index 0000000..8372b20 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/content/use-content-spinner.ts b/vue/packages/effects/layouts/src/basic/content/use-content-spinner.ts new file mode 100644 index 0000000..dfe3c53 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/copyright/copyright.vue b/vue/packages/effects/layouts/src/basic/copyright/copyright.vue new file mode 100644 index 0000000..de49c7c --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/copyright/copyright.vue @@ -0,0 +1,48 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/copyright/index.ts b/vue/packages/effects/layouts/src/basic/copyright/index.ts new file mode 100644 index 0000000..e0620da --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/copyright/index.ts @@ -0,0 +1 @@ +export { default as Copyright } from './copyright.vue'; diff --git a/vue/packages/effects/layouts/src/basic/footer/footer.vue b/vue/packages/effects/layouts/src/basic/footer/footer.vue new file mode 100644 index 0000000..6fc256d --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/footer/footer.vue @@ -0,0 +1,11 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/footer/index.ts b/vue/packages/effects/layouts/src/basic/footer/index.ts new file mode 100644 index 0000000..7e149a2 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/footer/index.ts @@ -0,0 +1 @@ +export { default as LayoutFooter } from './footer.vue'; diff --git a/vue/packages/effects/layouts/src/basic/header/header.vue b/vue/packages/effects/layouts/src/basic/header/header.vue new file mode 100644 index 0000000..44ec671 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/header/header.vue @@ -0,0 +1,195 @@ + + + + diff --git a/vue/packages/effects/layouts/src/basic/header/index.ts b/vue/packages/effects/layouts/src/basic/header/index.ts new file mode 100644 index 0000000..44f0729 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/header/index.ts @@ -0,0 +1 @@ +export { default as LayoutHeader } from './header.vue'; diff --git a/vue/packages/effects/layouts/src/basic/index.ts b/vue/packages/effects/layouts/src/basic/index.ts new file mode 100644 index 0000000..b3a01cd --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/index.ts @@ -0,0 +1 @@ +export { default as BasicLayout } from './layout.vue'; diff --git a/vue/packages/effects/layouts/src/basic/layout.vue b/vue/packages/effects/layouts/src/basic/layout.vue new file mode 100644 index 0000000..605f3cf --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/layout.vue @@ -0,0 +1,412 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/menu/extra-menu.vue b/vue/packages/effects/layouts/src/basic/menu/extra-menu.vue new file mode 100644 index 0000000..5f194a7 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/menu/extra-menu.vue @@ -0,0 +1,41 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/menu/index.ts b/vue/packages/effects/layouts/src/basic/menu/index.ts new file mode 100644 index 0000000..72b87ad --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/menu/menu.vue b/vue/packages/effects/layouts/src/basic/menu/menu.vue new file mode 100644 index 0000000..cbb5cfb --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/menu/menu.vue @@ -0,0 +1,45 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue b/vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue new file mode 100644 index 0000000..ae12cc9 --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/menu/mixed-menu.vue @@ -0,0 +1,46 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/menu/use-extra-menu.ts b/vue/packages/effects/layouts/src/basic/menu/use-extra-menu.ts new file mode 100644 index 0000000..e2afb74 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts b/vue/packages/effects/layouts/src/basic/menu/use-mixed-menu.ts new file mode 100644 index 0000000..8424c38 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/menu/use-navigation.ts b/vue/packages/effects/layouts/src/basic/menu/use-navigation.ts new file mode 100644 index 0000000..daa6dc7 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/tabbar/index.ts b/vue/packages/effects/layouts/src/basic/tabbar/index.ts new file mode 100644 index 0000000..5cc2479 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue b/vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue new file mode 100644 index 0000000..8e4f33b --- /dev/null +++ b/vue/packages/effects/layouts/src/basic/tabbar/tabbar.vue @@ -0,0 +1,75 @@ + + + diff --git a/vue/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts b/vue/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts new file mode 100644 index 0000000..0f0ef34 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/iframe/iframe-router-view.vue b/vue/packages/effects/layouts/src/iframe/iframe-router-view.vue new file mode 100644 index 0000000..3f1f952 --- /dev/null +++ b/vue/packages/effects/layouts/src/iframe/iframe-router-view.vue @@ -0,0 +1,86 @@ + + diff --git a/vue/packages/effects/layouts/src/iframe/iframe-view.vue b/vue/packages/effects/layouts/src/iframe/iframe-view.vue new file mode 100644 index 0000000..7b8b46c --- /dev/null +++ b/vue/packages/effects/layouts/src/iframe/iframe-view.vue @@ -0,0 +1,3 @@ + diff --git a/vue/packages/effects/layouts/src/iframe/index.ts b/vue/packages/effects/layouts/src/iframe/index.ts new file mode 100644 index 0000000..1b8c131 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/index.ts b/vue/packages/effects/layouts/src/index.ts new file mode 100644 index 0000000..124a44a --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/breadcrumb.vue b/vue/packages/effects/layouts/src/widgets/breadcrumb.vue new file mode 100644 index 0000000..c041960 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/breadcrumb.vue @@ -0,0 +1,74 @@ + + diff --git a/vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue b/vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue new file mode 100644 index 0000000..4f3082f --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/check-updates/check-updates.vue @@ -0,0 +1,136 @@ + + diff --git a/vue/packages/effects/layouts/src/widgets/check-updates/index.ts b/vue/packages/effects/layouts/src/widgets/check-updates/index.ts new file mode 100644 index 0000000..fc20c66 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/check-updates/index.ts @@ -0,0 +1 @@ +export { default as CheckUpdates } from './check-updates.vue'; diff --git a/vue/packages/effects/layouts/src/widgets/color-toggle.vue b/vue/packages/effects/layouts/src/widgets/color-toggle.vue new file mode 100644 index 0000000..ae15cb8 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/color-toggle.vue @@ -0,0 +1,64 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/global-search/global-search.vue b/vue/packages/effects/layouts/src/widgets/global-search/global-search.vue new file mode 100644 index 0000000..bd8b334 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/global-search/global-search.vue @@ -0,0 +1,157 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/global-search/index.ts b/vue/packages/effects/layouts/src/widgets/global-search/index.ts new file mode 100644 index 0000000..cd490ae --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/global-search/index.ts @@ -0,0 +1 @@ +export { default as GlobalSearch } from './global-search.vue'; diff --git a/vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue b/vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue new file mode 100644 index 0000000..6e94049 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/global-search/search-panel.vue @@ -0,0 +1,288 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/index.ts b/vue/packages/effects/layouts/src/widgets/index.ts new file mode 100644 index 0000000..0f9e11a --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/language-toggle.vue b/vue/packages/effects/layouts/src/widgets/language-toggle.vue new file mode 100644 index 0000000..f92432f --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/language-toggle.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/layout-toggle.vue b/vue/packages/effects/layouts/src/widgets/layout-toggle.vue new file mode 100644 index 0000000..ae4eecb --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/layout-toggle.vue @@ -0,0 +1,64 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/lock-screen/index.ts b/vue/packages/effects/layouts/src/widgets/lock-screen/index.ts new file mode 100644 index 0000000..8ba1f16 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue b/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue new file mode 100644 index 0000000..908e670 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen-modal.vue @@ -0,0 +1,110 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue b/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue new file mode 100644 index 0000000..3f70033 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/lock-screen/lock-screen.vue @@ -0,0 +1,167 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/notification/index.ts b/vue/packages/effects/layouts/src/widgets/notification/index.ts new file mode 100644 index 0000000..e219b71 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/notification/notification.vue b/vue/packages/effects/layouts/src/widgets/notification/notification.vue new file mode 100644 index 0000000..8089dd7 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/notification/notification.vue @@ -0,0 +1,235 @@ + + + + diff --git a/vue/packages/effects/layouts/src/widgets/notification/types.ts b/vue/packages/effects/layouts/src/widgets/notification/types.ts new file mode 100644 index 0000000..4b684f2 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue new file mode 100644 index 0000000..c8cc9e6 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/block.vue @@ -0,0 +1,22 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue new file mode 100644 index 0000000..99940c6 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/checkbox-item.vue @@ -0,0 +1,63 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue new file mode 100644 index 0000000..b27d074 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/animation.vue @@ -0,0 +1,51 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue new file mode 100644 index 0000000..c69cd3a --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/general/general.vue @@ -0,0 +1,47 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/index.ts b/vue/packages/effects/layouts/src/widgets/preferences/blocks/index.ts new file mode 100644 index 0000000..cdd6bb1 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue new file mode 100644 index 0000000..8e9f09e --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/input-item.vue @@ -0,0 +1,63 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue new file mode 100644 index 0000000..51f1a40 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/breadcrumb.vue @@ -0,0 +1,56 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue new file mode 100644 index 0000000..75af1c3 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/content.vue @@ -0,0 +1,53 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue new file mode 100644 index 0000000..9389029 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/copyright.vue @@ -0,0 +1,44 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue new file mode 100644 index 0000000..8a77920 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/footer.vue @@ -0,0 +1,17 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue new file mode 100644 index 0000000..ee04ee2 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/header.vue @@ -0,0 +1,74 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue new file mode 100644 index 0000000..a46650b --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/layout.vue @@ -0,0 +1,112 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue new file mode 100644 index 0000000..23acb1f --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/navigation.vue @@ -0,0 +1,45 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue new file mode 100644 index 0000000..e8d84af --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/sidebar.vue @@ -0,0 +1,100 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue new file mode 100644 index 0000000..ea533da --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/tabbar.vue @@ -0,0 +1,94 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue new file mode 100644 index 0000000..82addb3 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/layout/widget.vue @@ -0,0 +1,71 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue new file mode 100644 index 0000000..3878f81 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/number-field-item.vue @@ -0,0 +1,74 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue new file mode 100644 index 0000000..fabc371 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/select-item.vue @@ -0,0 +1,68 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue new file mode 100644 index 0000000..f71a1f6 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/shortcut-keys/global.vue @@ -0,0 +1,50 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue new file mode 100644 index 0000000..33d99e9 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/switch-item.vue @@ -0,0 +1,55 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue new file mode 100644 index 0000000..d0dba8e --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/builtin.vue @@ -0,0 +1,163 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue new file mode 100644 index 0000000..9a41d4e --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/color-mode.vue @@ -0,0 +1,26 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue new file mode 100644 index 0000000..b1aaa2d --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/font-size.vue @@ -0,0 +1,62 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue new file mode 100644 index 0000000..4201ed6 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/radius.vue @@ -0,0 +1,38 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue new file mode 100644 index 0000000..1a5ca4b --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/theme/theme.vue @@ -0,0 +1,83 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue b/vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue new file mode 100644 index 0000000..3f2a4a2 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/blocks/toggle-item.vue @@ -0,0 +1,46 @@ + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue new file mode 100644 index 0000000..a1bcefd --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/content-compact.vue @@ -0,0 +1,119 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue new file mode 100644 index 0000000..5cbcaca --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/full-content.vue @@ -0,0 +1,50 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue new file mode 100644 index 0000000..d5c9367 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/header-mixed-nav.vue @@ -0,0 +1,202 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue new file mode 100644 index 0000000..18158b3 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/header-nav.vue @@ -0,0 +1,119 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue new file mode 100644 index 0000000..b44e249 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/header-sidebar-nav.vue @@ -0,0 +1,177 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/index.ts b/vue/packages/effects/layouts/src/widgets/preferences/icons/index.ts new file mode 100644 index 0000000..7eec1b4 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue new file mode 100644 index 0000000..d194383 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/mixed-nav.vue @@ -0,0 +1,161 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue new file mode 100644 index 0000000..d824e11 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/setting.vue @@ -0,0 +1,12 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue new file mode 100644 index 0000000..8fc0ba4 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-mixed-nav.vue @@ -0,0 +1,173 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue b/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue new file mode 100644 index 0000000..83ff399 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/icons/sidebar-nav.vue @@ -0,0 +1,153 @@ + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/index.ts b/vue/packages/effects/layouts/src/widgets/preferences/index.ts new file mode 100644 index 0000000..2c737d5 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue b/vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue new file mode 100644 index 0000000..8598bb2 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/preferences-button.vue @@ -0,0 +1,20 @@ + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue b/vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue new file mode 100644 index 0000000..c88a9bc --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/preferences-drawer.vue @@ -0,0 +1,493 @@ + + + + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/preferences.vue b/vue/packages/effects/layouts/src/widgets/preferences/preferences.vue new file mode 100644 index 0000000..8bf91eb --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/preferences/preferences.vue @@ -0,0 +1,72 @@ + + diff --git a/vue/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts b/vue/packages/effects/layouts/src/widgets/preferences/use-open-preferences.ts new file mode 100644 index 0000000..eb9d847 --- /dev/null +++ b/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/vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts b/vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts new file mode 100644 index 0000000..0673d21 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/theme-toggle/index.ts @@ -0,0 +1 @@ +export { default as ThemeToggle } from './theme-toggle.vue'; diff --git a/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue b/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue new file mode 100644 index 0000000..8d24b53 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-button.vue @@ -0,0 +1,188 @@ + + + + + diff --git a/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue b/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue new file mode 100644 index 0000000..19c132e --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/theme-toggle/theme-toggle.vue @@ -0,0 +1,83 @@ + + diff --git a/vue/packages/effects/layouts/src/widgets/timezone/index.ts b/vue/packages/effects/layouts/src/widgets/timezone/index.ts new file mode 100644 index 0000000..eef486d --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/timezone/index.ts @@ -0,0 +1 @@ +export { default as TimezoneButton } from './timezone-button.vue'; diff --git a/vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue b/vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue new file mode 100644 index 0000000..f426b94 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/timezone/timezone-button.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts b/vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts new file mode 100644 index 0000000..86429e9 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/user-dropdown/index.ts @@ -0,0 +1 @@ +export { default as UserDropdown } from './user-dropdown.vue'; diff --git a/vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue b/vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue new file mode 100644 index 0000000..8156324 --- /dev/null +++ b/vue/packages/effects/layouts/src/widgets/user-dropdown/user-dropdown.vue @@ -0,0 +1,262 @@ + + + diff --git a/vue/packages/effects/layouts/tsconfig.json b/vue/packages/effects/layouts/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/effects/plugins/README.md b/vue/packages/effects/plugins/README.md new file mode 100644 index 0000000..c394c9c --- /dev/null +++ b/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/vue/packages/effects/plugins/package.json b/vue/packages/effects/plugins/package.json new file mode 100644 index 0000000..add6e78 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/echarts/echarts-ui.vue b/vue/packages/effects/plugins/src/echarts/echarts-ui.vue new file mode 100644 index 0000000..70d1f20 --- /dev/null +++ b/vue/packages/effects/plugins/src/echarts/echarts-ui.vue @@ -0,0 +1,15 @@ + + + diff --git a/vue/packages/effects/plugins/src/echarts/echarts.ts b/vue/packages/effects/plugins/src/echarts/echarts.ts new file mode 100644 index 0000000..8e1b249 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/echarts/index.ts b/vue/packages/effects/plugins/src/echarts/index.ts new file mode 100644 index 0000000..80f36a1 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/echarts/use-echarts.ts b/vue/packages/effects/plugins/src/echarts/use-echarts.ts new file mode 100644 index 0000000..e7ceed3 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/motion/index.ts b/vue/packages/effects/plugins/src/motion/index.ts new file mode 100644 index 0000000..021465a --- /dev/null +++ b/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/vue/packages/effects/plugins/src/motion/types.ts b/vue/packages/effects/plugins/src/motion/types.ts new file mode 100644 index 0000000..f08bf21 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/api.ts b/vue/packages/effects/plugins/src/vxe-table/api.ts new file mode 100644 index 0000000..2b60d60 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/extends.ts b/vue/packages/effects/plugins/src/vxe-table/extends.ts new file mode 100644 index 0000000..a6cf4ca --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/index.ts b/vue/packages/effects/plugins/src/vxe-table/index.ts new file mode 100644 index 0000000..a19f2b8 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/init.ts b/vue/packages/effects/plugins/src/vxe-table/init.ts new file mode 100644 index 0000000..00e9d8a --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/style.css b/vue/packages/effects/plugins/src/vxe-table/style.css new file mode 100644 index 0000000..5b47fa2 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/types.ts b/vue/packages/effects/plugins/src/vxe-table/types.ts new file mode 100644 index 0000000..8b9aea4 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts b/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.ts new file mode 100644 index 0000000..6ab8769 --- /dev/null +++ b/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/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue b/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue new file mode 100644 index 0000000..7b002a2 --- /dev/null +++ b/vue/packages/effects/plugins/src/vxe-table/use-vxe-grid.vue @@ -0,0 +1,479 @@ + + + diff --git a/vue/packages/effects/plugins/tsconfig.json b/vue/packages/effects/plugins/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/effects/request/package.json b/vue/packages/effects/request/package.json new file mode 100644 index 0000000..0b557d3 --- /dev/null +++ b/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/vue/packages/effects/request/src/index.ts b/vue/packages/effects/request/src/index.ts new file mode 100644 index 0000000..fae1b05 --- /dev/null +++ b/vue/packages/effects/request/src/index.ts @@ -0,0 +1,2 @@ +export * from './request-client'; +export * from 'axios'; diff --git a/vue/packages/effects/request/src/request-client/index.ts b/vue/packages/effects/request/src/request-client/index.ts new file mode 100644 index 0000000..a44cd15 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/downloader.test.ts b/vue/packages/effects/request/src/request-client/modules/downloader.test.ts new file mode 100644 index 0000000..27e8a30 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/downloader.ts b/vue/packages/effects/request/src/request-client/modules/downloader.ts new file mode 100644 index 0000000..6c30005 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/interceptor.ts b/vue/packages/effects/request/src/request-client/modules/interceptor.ts new file mode 100644 index 0000000..f6d2ad8 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/sse.test.ts b/vue/packages/effects/request/src/request-client/modules/sse.test.ts new file mode 100644 index 0000000..4e8c6a9 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/sse.ts b/vue/packages/effects/request/src/request-client/modules/sse.ts new file mode 100644 index 0000000..09d1301 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/uploader.test.ts b/vue/packages/effects/request/src/request-client/modules/uploader.test.ts new file mode 100644 index 0000000..8306656 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/modules/uploader.ts b/vue/packages/effects/request/src/request-client/modules/uploader.ts new file mode 100644 index 0000000..1353222 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/preset-interceptors.ts b/vue/packages/effects/request/src/request-client/preset-interceptors.ts new file mode 100644 index 0000000..f8bfd43 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/request-client.test.ts b/vue/packages/effects/request/src/request-client/request-client.test.ts new file mode 100644 index 0000000..2d94525 --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/request-client.ts b/vue/packages/effects/request/src/request-client/request-client.ts new file mode 100644 index 0000000..453913b --- /dev/null +++ b/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/vue/packages/effects/request/src/request-client/types.ts b/vue/packages/effects/request/src/request-client/types.ts new file mode 100644 index 0000000..080468b --- /dev/null +++ b/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/vue/packages/effects/request/tsconfig.json b/vue/packages/effects/request/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/icons/README.md b/vue/packages/icons/README.md new file mode 100644 index 0000000..bc50d25 --- /dev/null +++ b/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/vue/packages/icons/package.json b/vue/packages/icons/package.json new file mode 100644 index 0000000..24680ea --- /dev/null +++ b/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/vue/packages/icons/src/iconify-offline/index.ts b/vue/packages/icons/src/iconify-offline/index.ts new file mode 100644 index 0000000..8c331ae --- /dev/null +++ b/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/vue/packages/icons/src/iconify/index.ts b/vue/packages/icons/src/iconify/index.ts new file mode 100644 index 0000000..e5aa9b0 --- /dev/null +++ b/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/vue/packages/icons/src/icons/empty-icon.vue b/vue/packages/icons/src/icons/empty-icon.vue new file mode 100644 index 0000000..444a765 --- /dev/null +++ b/vue/packages/icons/src/icons/empty-icon.vue @@ -0,0 +1,27 @@ + diff --git a/vue/packages/icons/src/index.ts b/vue/packages/icons/src/index.ts new file mode 100644 index 0000000..b224144 --- /dev/null +++ b/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/vue/packages/icons/src/svg/icons/antdv-logo.svg b/vue/packages/icons/src/svg/icons/antdv-logo.svg new file mode 100644 index 0000000..dbfcee7 --- /dev/null +++ b/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/vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg b/vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg new file mode 100644 index 0000000..80fd6d3 --- /dev/null +++ b/vue/packages/icons/src/svg/icons/arcticons--quark-browser.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/vue/packages/icons/src/svg/icons/avatar-1.svg b/vue/packages/icons/src/svg/icons/avatar-1.svg new file mode 100644 index 0000000..b05970d --- /dev/null +++ b/vue/packages/icons/src/svg/icons/avatar-1.svg @@ -0,0 +1 @@ +Asset 15 diff --git a/vue/packages/icons/src/svg/icons/avatar-2.svg b/vue/packages/icons/src/svg/icons/avatar-2.svg new file mode 100644 index 0000000..8e17b0b --- /dev/null +++ b/vue/packages/icons/src/svg/icons/avatar-2.svg @@ -0,0 +1 @@ +Asset 16 diff --git a/vue/packages/icons/src/svg/icons/avatar-3.svg b/vue/packages/icons/src/svg/icons/avatar-3.svg new file mode 100644 index 0000000..ca79178 --- /dev/null +++ b/vue/packages/icons/src/svg/icons/avatar-3.svg @@ -0,0 +1 @@ +Asset 17 diff --git a/vue/packages/icons/src/svg/icons/avatar-4.svg b/vue/packages/icons/src/svg/icons/avatar-4.svg new file mode 100644 index 0000000..d9138df --- /dev/null +++ b/vue/packages/icons/src/svg/icons/avatar-4.svg @@ -0,0 +1 @@ +Asset 120 diff --git a/vue/packages/icons/src/svg/icons/bell.svg b/vue/packages/icons/src/svg/icons/bell.svg new file mode 100644 index 0000000..90c34e1 --- /dev/null +++ b/vue/packages/icons/src/svg/icons/bell.svg @@ -0,0 +1 @@ +Asset 510 diff --git a/vue/packages/icons/src/svg/icons/cake.svg b/vue/packages/icons/src/svg/icons/cake.svg new file mode 100644 index 0000000..43901fb --- /dev/null +++ b/vue/packages/icons/src/svg/icons/cake.svg @@ -0,0 +1 @@ +Asset 480% diff --git a/vue/packages/icons/src/svg/icons/card.svg b/vue/packages/icons/src/svg/icons/card.svg new file mode 100644 index 0000000..40ff3e3 --- /dev/null +++ b/vue/packages/icons/src/svg/icons/card.svg @@ -0,0 +1 @@ + diff --git a/vue/packages/icons/src/svg/icons/download.svg b/vue/packages/icons/src/svg/icons/download.svg new file mode 100644 index 0000000..af9ff15 --- /dev/null +++ b/vue/packages/icons/src/svg/icons/download.svg @@ -0,0 +1 @@ + diff --git a/vue/packages/icons/src/svg/index.ts b/vue/packages/icons/src/svg/index.ts new file mode 100644 index 0000000..9573ef7 --- /dev/null +++ b/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/vue/packages/icons/src/svg/load.ts b/vue/packages/icons/src/svg/load.ts new file mode 100644 index 0000000..59098bd --- /dev/null +++ b/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/vue/packages/icons/tsconfig.json b/vue/packages/icons/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/locales/package.json b/vue/packages/locales/package.json new file mode 100644 index 0000000..7d47915 --- /dev/null +++ b/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/vue/packages/locales/src/i18n.ts b/vue/packages/locales/src/i18n.ts new file mode 100644 index 0000000..e3c75bd --- /dev/null +++ b/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/vue/packages/locales/src/index.ts b/vue/packages/locales/src/index.ts new file mode 100644 index 0000000..d4bfd81 --- /dev/null +++ b/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/vue/packages/locales/src/langs/en-US/authentication.json b/vue/packages/locales/src/langs/en-US/authentication.json new file mode 100644 index 0000000..7dd3462 --- /dev/null +++ b/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/vue/packages/locales/src/langs/en-US/common.json b/vue/packages/locales/src/langs/en-US/common.json new file mode 100644 index 0000000..08c20f7 --- /dev/null +++ b/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/vue/packages/locales/src/langs/en-US/preferences.json b/vue/packages/locales/src/langs/en-US/preferences.json new file mode 100644 index 0000000..977632a --- /dev/null +++ b/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/vue/packages/locales/src/langs/en-US/ui.json b/vue/packages/locales/src/langs/en-US/ui.json new file mode 100644 index 0000000..d6a6337 --- /dev/null +++ b/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/vue/packages/locales/src/langs/zh-CN/authentication.json b/vue/packages/locales/src/langs/zh-CN/authentication.json new file mode 100644 index 0000000..ade52ac --- /dev/null +++ b/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/vue/packages/locales/src/langs/zh-CN/common.json b/vue/packages/locales/src/langs/zh-CN/common.json new file mode 100644 index 0000000..6b3cad5 --- /dev/null +++ b/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/vue/packages/locales/src/langs/zh-CN/preferences.json b/vue/packages/locales/src/langs/zh-CN/preferences.json new file mode 100644 index 0000000..f8e390f --- /dev/null +++ b/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/vue/packages/locales/src/langs/zh-CN/ui.json b/vue/packages/locales/src/langs/zh-CN/ui.json new file mode 100644 index 0000000..ef9d101 --- /dev/null +++ b/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/vue/packages/locales/src/typing.ts b/vue/packages/locales/src/typing.ts new file mode 100644 index 0000000..fdebac2 --- /dev/null +++ b/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/vue/packages/locales/tsconfig.json b/vue/packages/locales/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/preferences/package.json b/vue/packages/preferences/package.json new file mode 100644 index 0000000..e6e52e2 --- /dev/null +++ b/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/vue/packages/preferences/src/index.ts b/vue/packages/preferences/src/index.ts new file mode 100644 index 0000000..75fab43 --- /dev/null +++ b/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/vue/packages/preferences/tsconfig.json b/vue/packages/preferences/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/stores/package.json b/vue/packages/stores/package.json new file mode 100644 index 0000000..72bcf49 --- /dev/null +++ b/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/vue/packages/stores/shim-pinia.d.ts b/vue/packages/stores/shim-pinia.d.ts new file mode 100644 index 0000000..558d0ba --- /dev/null +++ b/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/vue/packages/stores/src/index.ts b/vue/packages/stores/src/index.ts new file mode 100644 index 0000000..41b3662 --- /dev/null +++ b/vue/packages/stores/src/index.ts @@ -0,0 +1,3 @@ +export * from './modules'; +export * from './setup'; +export { defineStore, storeToRefs } from 'pinia'; diff --git a/vue/packages/stores/src/modules/access.test.ts b/vue/packages/stores/src/modules/access.test.ts new file mode 100644 index 0000000..211e256 --- /dev/null +++ b/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/vue/packages/stores/src/modules/access.ts b/vue/packages/stores/src/modules/access.ts new file mode 100644 index 0000000..b88242e --- /dev/null +++ b/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/vue/packages/stores/src/modules/index.ts b/vue/packages/stores/src/modules/index.ts new file mode 100644 index 0000000..bb9a66f --- /dev/null +++ b/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/vue/packages/stores/src/modules/tabbar.test.ts b/vue/packages/stores/src/modules/tabbar.test.ts new file mode 100644 index 0000000..0c850d6 --- /dev/null +++ b/vue/packages/stores/src/modules/tabbar.test.ts @@ -0,0 +1,325 @@ +import { createRouter, createWebHistory } from 'vue-router'; + +import { createPinia, setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +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); + }); +}); diff --git a/vue/packages/stores/src/modules/tabbar.ts b/vue/packages/stores/src/modules/tabbar.ts new file mode 100644 index 0000000..b1b4060 --- /dev/null +++ b/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/vue/packages/stores/src/modules/timezone.ts b/vue/packages/stores/src/modules/timezone.ts new file mode 100644 index 0000000..24180c6 --- /dev/null +++ b/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/vue/packages/stores/src/modules/user.test.ts b/vue/packages/stores/src/modules/user.test.ts new file mode 100644 index 0000000..3d8a22c --- /dev/null +++ b/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/vue/packages/stores/src/modules/user.ts b/vue/packages/stores/src/modules/user.ts new file mode 100644 index 0000000..9d37433 --- /dev/null +++ b/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/vue/packages/stores/src/setup.ts b/vue/packages/stores/src/setup.ts new file mode 100644 index 0000000..b18c27e --- /dev/null +++ b/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/vue/packages/stores/tsconfig.json b/vue/packages/stores/tsconfig.json new file mode 100644 index 0000000..3057820 --- /dev/null +++ b/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/vue/packages/styles/README.md b/vue/packages/styles/README.md new file mode 100644 index 0000000..4826446 --- /dev/null +++ b/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/vue/packages/styles/package.json b/vue/packages/styles/package.json new file mode 100644 index 0000000..0716a5e --- /dev/null +++ b/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/vue/packages/styles/src/antd/index.css b/vue/packages/styles/src/antd/index.css new file mode 100644 index 0000000..4dec637 --- /dev/null +++ b/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/vue/packages/styles/src/ele/index.css b/vue/packages/styles/src/ele/index.css new file mode 100644 index 0000000..4ee8f7b --- /dev/null +++ b/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/vue/packages/styles/src/global/index.scss b/vue/packages/styles/src/global/index.scss new file mode 100644 index 0000000..c7af9bb --- /dev/null +++ b/vue/packages/styles/src/global/index.scss @@ -0,0 +1 @@ +@use '@vben-core/design/bem' as *; diff --git a/vue/packages/styles/src/index.ts b/vue/packages/styles/src/index.ts new file mode 100644 index 0000000..b375456 --- /dev/null +++ b/vue/packages/styles/src/index.ts @@ -0,0 +1 @@ +import '@vben-core/design'; diff --git a/vue/packages/styles/src/naive/index.css b/vue/packages/styles/src/naive/index.css new file mode 100644 index 0000000..a775116 --- /dev/null +++ b/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/vue/packages/styles/tsconfig.json b/vue/packages/styles/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/types/README.md b/vue/packages/types/README.md new file mode 100644 index 0000000..f796f31 --- /dev/null +++ b/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/vue/packages/types/global.d.ts b/vue/packages/types/global.d.ts new file mode 100644 index 0000000..d615b4c --- /dev/null +++ b/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/vue/packages/types/package.json b/vue/packages/types/package.json new file mode 100644 index 0000000..07dbca0 --- /dev/null +++ b/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/vue/packages/types/src/index.ts b/vue/packages/types/src/index.ts new file mode 100644 index 0000000..1e266c4 --- /dev/null +++ b/vue/packages/types/src/index.ts @@ -0,0 +1,2 @@ +export type * from './user'; +export type * from '@vben-core/typings'; diff --git a/vue/packages/types/src/user.ts b/vue/packages/types/src/user.ts new file mode 100644 index 0000000..c5167c0 --- /dev/null +++ b/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/vue/packages/types/tsconfig.json b/vue/packages/types/tsconfig.json new file mode 100644 index 0000000..ce1a891 --- /dev/null +++ b/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/vue/packages/utils/README.md b/vue/packages/utils/README.md new file mode 100644 index 0000000..f06068a --- /dev/null +++ b/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/vue/packages/utils/package.json b/vue/packages/utils/package.json new file mode 100644 index 0000000..811f64c --- /dev/null +++ b/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/vue/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts b/vue/packages/utils/src/helpers/__tests__/find-menu-by-path.test.ts new file mode 100644 index 0000000..fc0d76b --- /dev/null +++ b/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/vue/packages/utils/src/helpers/__tests__/generate-menus.test.ts b/vue/packages/utils/src/helpers/__tests__/generate-menus.test.ts new file mode 100644 index 0000000..9d98b5a --- /dev/null +++ b/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/vue/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts b/vue/packages/utils/src/helpers/__tests__/generate-routes-frontend.test.ts new file mode 100644 index 0000000..8e01853 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts b/vue/packages/utils/src/helpers/__tests__/merge-route-modules.test.ts new file mode 100644 index 0000000..3615556 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/file.ts b/vue/packages/utils/src/helpers/file.ts new file mode 100644 index 0000000..62bb7e5 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/find-menu-by-path.ts b/vue/packages/utils/src/helpers/find-menu-by-path.ts new file mode 100644 index 0000000..747cc7f --- /dev/null +++ b/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/vue/packages/utils/src/helpers/generate-menus.ts b/vue/packages/utils/src/helpers/generate-menus.ts new file mode 100644 index 0000000..f13d599 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/generate-routes-backend.ts b/vue/packages/utils/src/helpers/generate-routes-backend.ts new file mode 100644 index 0000000..c92b6d3 --- /dev/null +++ b/vue/packages/utils/src/helpers/generate-routes-backend.ts @@ -0,0 +1,86 @@ +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(menuRoutes, layoutMap, normalizePageMap); + + return routes; + } catch (error) { + console.error(error); + throw error; + } +} + +function convertRoutes( + routes: RouteRecordStringComponent[], + layoutMap: ComponentRecordType, + pageMap: ComponentRecordType, +): RouteRecordRaw[] { + return 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 { + console.error(`route component is invalid: ${pageKey}`, route); + route.component = pageMap['/_core/fallback/not-found.vue']; + } + } + + return route; + }); +} + +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/vue/packages/utils/src/helpers/generate-routes-frontend.ts b/vue/packages/utils/src/helpers/generate-routes-frontend.ts new file mode 100644 index 0000000..dafc8a7 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/get-popup-container.ts b/vue/packages/utils/src/helpers/get-popup-container.ts new file mode 100644 index 0000000..0640423 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/index.ts b/vue/packages/utils/src/helpers/index.ts new file mode 100644 index 0000000..e6292b8 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/merge-route-modules.ts b/vue/packages/utils/src/helpers/merge-route-modules.ts new file mode 100644 index 0000000..53e21f3 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/mitt.ts b/vue/packages/utils/src/helpers/mitt.ts new file mode 100644 index 0000000..52be313 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/reset-routes.ts b/vue/packages/utils/src/helpers/reset-routes.ts new file mode 100644 index 0000000..0d53a00 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/tree.ts b/vue/packages/utils/src/helpers/tree.ts new file mode 100644 index 0000000..9b0f4b7 --- /dev/null +++ b/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/vue/packages/utils/src/helpers/unmount-global-loading.ts b/vue/packages/utils/src/helpers/unmount-global-loading.ts new file mode 100644 index 0000000..10b88ea --- /dev/null +++ b/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/vue/packages/utils/src/helpers/uuid.ts b/vue/packages/utils/src/helpers/uuid.ts new file mode 100644 index 0000000..81c49a0 --- /dev/null +++ b/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/vue/packages/utils/src/index.ts b/vue/packages/utils/src/index.ts new file mode 100644 index 0000000..dd84fa7 --- /dev/null +++ b/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/vue/packages/utils/tsconfig.json b/vue/packages/utils/tsconfig.json new file mode 100644 index 0000000..255148a --- /dev/null +++ b/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/vue/pnpm-lock.yaml b/vue/pnpm-lock.yaml new file mode 100644 index 0000000..1673764 --- /dev/null +++ b/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/vue/pnpm-workspace.yaml b/vue/pnpm-workspace.yaml new file mode 100644 index 0000000..0e5d00e --- /dev/null +++ b/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/vue/private-folder-alias.json b/vue/private-folder-alias.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/vue/private-folder-alias.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/vue/scripts/clean.mjs b/vue/scripts/clean.mjs new file mode 100644 index 0000000..2049e45 --- /dev/null +++ b/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/vue/scripts/deploy/Dockerfile b/vue/scripts/deploy/Dockerfile new file mode 100644 index 0000000..86f439f --- /dev/null +++ b/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/vue/scripts/deploy/build-local-docker-image.sh b/vue/scripts/deploy/build-local-docker-image.sh new file mode 100644 index 0000000..4881487 --- /dev/null +++ b/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/vue/scripts/deploy/nginx.conf b/vue/scripts/deploy/nginx.conf new file mode 100644 index 0000000..8e6ab10 --- /dev/null +++ b/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/vue/scripts/turbo-run/README.md b/vue/scripts/turbo-run/README.md new file mode 100644 index 0000000..4f90a59 --- /dev/null +++ b/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/vue/scripts/turbo-run/bin/turbo-run.mjs b/vue/scripts/turbo-run/bin/turbo-run.mjs new file mode 100644 index 0000000..407754d --- /dev/null +++ b/vue/scripts/turbo-run/bin/turbo-run.mjs @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +import('../dist/index.mjs'); diff --git a/vue/scripts/turbo-run/build.config.ts b/vue/scripts/turbo-run/build.config.ts new file mode 100644 index 0000000..97e572c --- /dev/null +++ b/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/vue/scripts/turbo-run/package.json b/vue/scripts/turbo-run/package.json new file mode 100644 index 0000000..4db2313 --- /dev/null +++ b/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/vue/scripts/turbo-run/src/index.ts b/vue/scripts/turbo-run/src/index.ts new file mode 100644 index 0000000..2f8dad0 --- /dev/null +++ b/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/vue/scripts/turbo-run/src/run.ts b/vue/scripts/turbo-run/src/run.ts new file mode 100644 index 0000000..31f9f52 --- /dev/null +++ b/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/vue/scripts/turbo-run/tsconfig.json b/vue/scripts/turbo-run/tsconfig.json new file mode 100644 index 0000000..b2ec3b6 --- /dev/null +++ b/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/vue/scripts/vsh/README.md b/vue/scripts/vsh/README.md new file mode 100644 index 0000000..61140d6 --- /dev/null +++ b/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/vue/scripts/vsh/bin/vsh.mjs b/vue/scripts/vsh/bin/vsh.mjs new file mode 100644 index 0000000..407754d --- /dev/null +++ b/vue/scripts/vsh/bin/vsh.mjs @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +import('../dist/index.mjs'); diff --git a/vue/scripts/vsh/build.config.ts b/vue/scripts/vsh/build.config.ts new file mode 100644 index 0000000..97e572c --- /dev/null +++ b/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/vue/scripts/vsh/package.json b/vue/scripts/vsh/package.json new file mode 100644 index 0000000..89f47ea --- /dev/null +++ b/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/vue/scripts/vsh/src/check-circular/index.ts b/vue/scripts/vsh/src/check-circular/index.ts new file mode 100644 index 0000000..0642506 --- /dev/null +++ b/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/vue/scripts/vsh/src/check-dep/index.ts b/vue/scripts/vsh/src/check-dep/index.ts new file mode 100644 index 0000000..e600e1b --- /dev/null +++ b/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/vue/scripts/vsh/src/code-workspace/index.ts b/vue/scripts/vsh/src/code-workspace/index.ts new file mode 100644 index 0000000..d5ec4ee --- /dev/null +++ b/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/vue/scripts/vsh/src/index.ts b/vue/scripts/vsh/src/index.ts new file mode 100644 index 0000000..4943425 --- /dev/null +++ b/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/vue/scripts/vsh/src/lint/index.ts b/vue/scripts/vsh/src/lint/index.ts new file mode 100644 index 0000000..b95ead6 --- /dev/null +++ b/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/vue/scripts/vsh/src/publint/index.ts b/vue/scripts/vsh/src/publint/index.ts new file mode 100644 index 0000000..d078673 --- /dev/null +++ b/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/vue/scripts/vsh/tsconfig.json b/vue/scripts/vsh/tsconfig.json new file mode 100644 index 0000000..b2ec3b6 --- /dev/null +++ b/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/vue/stylelint.config.mjs b/vue/stylelint.config.mjs new file mode 100644 index 0000000..e380674 --- /dev/null +++ b/vue/stylelint.config.mjs @@ -0,0 +1,4 @@ +export default { + extends: ['@vben/stylelint-config'], + root: true, +}; diff --git a/vue/tea.yaml b/vue/tea.yaml new file mode 100644 index 0000000..6e56d6f --- /dev/null +++ b/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/vue/turbo.json b/vue/turbo.json new file mode 100644 index 0000000..3443e27 --- /dev/null +++ b/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/vue/vben-admin.code-workspace b/vue/vben-admin.code-workspace new file mode 100644 index 0000000..aa8205b --- /dev/null +++ b/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/vue/vitest.config.ts b/vue/vitest.config.ts new file mode 100644 index 0000000..a10b5fa --- /dev/null +++ b/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/vue/vitest.workspace.ts b/vue/vitest.workspace.ts new file mode 100644 index 0000000..f00d6f6 --- /dev/null +++ b/vue/vitest.workspace.ts @@ -0,0 +1,3 @@ +import { defineWorkspace } from 'vitest/config'; + +export default defineWorkspace(['vitest.config.ts']); From f754b27ac250d36482c52baad42199d86592ede6 Mon Sep 17 00:00:00 2001 From: MiFaZhan Date: Thu, 29 Oct 2026 13:33:25 +0800 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20Dockerfile=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E9=95=9C=E5=83=8F=E6=94=B9=E4=B8=BA=E5=85=AC=E5=85=B1=E4=BB=93?= =?UTF-8?q?=E5=BA=93=EF=BC=8C=E7=A7=BB=E9=99=A4=E7=A7=81=E6=9C=89=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FROM 改为 ${BASE_REGISTRY}/<镜像>:<版本>,默认 docker.io/library 内网可传 --build-arg BASE_REGISTRY=<自有仓库>/library 覆盖 - iotlcm-app: 删除 ENV GOPRIVATE=git.xiujie.cn - iotlcm-app: VITE_MP_SERVER_BASEURL 默认值由内网域名改为 /app/api/v1 - Alpine 基础镜像固定到 3.23(原来未锁版本) --- vue/build/Dockerfile | 8 ++++++-- vue/build/DockerfileNoBuild | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/vue/build/Dockerfile b/vue/build/Dockerfile index c24c17f..d58fafc 100644 --- a/vue/build/Dockerfile +++ b/vue/build/Dockerfile @@ -1,4 +1,8 @@ -FROM crpi-svwhn8x8nvask31h.cn-beijing.personal.cr.aliyuncs.com/xjzlpublic/node:24-alpine AS builder +# 基础镜像仓库。默认使用 Docker Hub 官方镜像;内网环境可替换为自己的仓库: +# docker build --build-arg BASE_REGISTRY=harbor.example.com/library ... +ARG BASE_REGISTRY=docker.io/library + +FROM ${BASE_REGISTRY}/node:24-alpine AS builder LABEL stage=gobuilder @@ -17,7 +21,7 @@ RUN npm config set registry https://registry.npmmirror.com/ && \ RUN CI=true pnpm install --frozen-lockfile RUN CI=true pnpm build -FROM crpi-svwhn8x8nvask31h.cn-beijing.personal.cr.aliyuncs.com/xjzlpublic/nginx:1.30.0-alpine AS alpine +FROM ${BASE_REGISTRY}/nginx:1.30-alpine AS alpine COPY --from=builder /build/vue/apps/web-antd/dist /usr/share/nginx/html COPY vue/build/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/vue/build/DockerfileNoBuild b/vue/build/DockerfileNoBuild index ccdc07e..6006856 100644 --- a/vue/build/DockerfileNoBuild +++ b/vue/build/DockerfileNoBuild @@ -1,4 +1,8 @@ -FROM crpi-svwhn8x8nvask31h.cn-beijing.personal.cr.aliyuncs.com/xjzlpublic/nginx:1.30.0-alpine AS alpine +# 基础镜像仓库。默认使用 Docker Hub 官方镜像;内网环境可替换为自己的仓库: +# docker build --build-arg BASE_REGISTRY=harbor.example.com/library ... +ARG BASE_REGISTRY=docker.io/library + +FROM ${BASE_REGISTRY}/nginx:1.30-alpine AS alpine COPY vue/apps/web-antd/dist /usr/share/nginx/html COPY vue/build/nginx.conf /etc/nginx/conf.d/default.conf From 59b307ca75feb3937ea24eb6b4b5fcee85d5e51f Mon Sep 17 00:00:00 2001 From: MiFaZhan Date: Thu, 29 Oct 2026 14:43:14 +0800 Subject: [PATCH 03/11] =?UTF-8?q?sync:=20=E5=90=8C=E6=AD=A5=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=89=8D=E7=AB=AF=20v1.0.4=20=E5=B9=B6=E8=84=B1?= =?UTF-8?q?=E6=95=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- vue/.husky/commit-msg | 0 vue/.husky/pre-commit | 0 vue/apps/web-antd/package.json | 2 +- vue/apps/web-antd/public/setting.json | 4 +- vue/apps/web-antd/src/adapter/vxe-table.ts | 3 +- vue/apps/web-antd/src/api/agent/index.ts | 59 ++- .../src/api/common/downloadCenter/index.ts | 98 ++++ .../src/api/common/tMessageLog/index.ts | 34 ++ vue/apps/web-antd/src/api/core/auth.ts | 2 +- vue/apps/web-antd/src/api/core/captcha.ts | 2 +- vue/apps/web-antd/src/api/core/index.ts | 2 +- vue/apps/web-antd/src/api/core/menu.ts | 2 +- vue/apps/web-antd/src/api/core/upload.ts | 2 +- vue/apps/web-antd/src/api/core/user.ts | 2 +- .../web-antd/src/api/gen/testDemo/index.ts | 2 +- .../web-antd/src/api/gen_codes/gen_table.ts | 2 +- vue/apps/web-antd/src/api/index.ts | 2 +- .../tCommunication/tSimCardInfo/index.ts | 5 + .../tCommunication/tSimCardQuery/index.ts | 107 ++++ .../tCommunication/tSimCardQuery/type.ts | 55 +++ .../tSimCardTrafficCutoff/type.ts | 1 + .../tSimCardUnsub/index.test.ts | 6 +- .../iotlcm/tLifeCycle/tBatch/index.test.ts | 50 ++ .../src/api/iotlcm/tLifeCycle/tBatch/index.ts | 14 + .../src/api/iotlcm/tLifeCycle/tBatch/type.ts | 6 +- .../tLifeCycle/tSimCardOutbound/index.test.ts | 14 +- .../iotlcm/tLifeCycle/tSimCardStock/type.ts | 2 + .../src/api/iotlcm/tOperationlog/index.ts | 10 + .../src/api/iotlcm/tOperationlog/type.ts | 38 ++ .../tWarnCenter/simWarningConfig/type.ts | 2 + vue/apps/web-antd/src/api/monitor/cache.ts | 2 +- vue/apps/web-antd/src/api/monitor/index.ts | 2 +- vue/apps/web-antd/src/api/monitor/online.ts | 2 +- vue/apps/web-antd/src/api/request.ts | 13 +- vue/apps/web-antd/src/api/system/client.ts | 2 +- vue/apps/web-antd/src/api/system/config.ts | 2 +- vue/apps/web-antd/src/api/system/dept.ts | 2 +- vue/apps/web-antd/src/api/system/dict.ts | 2 +- vue/apps/web-antd/src/api/system/index.ts | 2 +- vue/apps/web-antd/src/api/system/job.ts | 2 +- .../web-antd/src/api/system/logininfor.ts | 2 +- vue/apps/web-antd/src/api/system/menu.ts | 2 +- vue/apps/web-antd/src/api/system/notice.ts | 2 +- vue/apps/web-antd/src/api/system/oper-log.ts | 2 +- vue/apps/web-antd/src/api/system/oss.ts | 2 +- vue/apps/web-antd/src/api/system/post.ts | 2 +- vue/apps/web-antd/src/api/system/qrcode.ts | 2 +- vue/apps/web-antd/src/api/system/role.ts | 72 +-- vue/apps/web-antd/src/api/system/social.ts | 2 +- vue/apps/web-antd/src/api/system/user.ts | 2 +- vue/apps/web-antd/src/config/setting.ts | 4 +- vue/apps/web-antd/src/layouts/basic.vue | 430 +++++++++++++++- .../src/router/access-root-route.test.ts | 70 +++ vue/apps/web-antd/src/router/access.ts | 3 + .../src/router/guard-login-redirect.test.ts | 100 ++++ vue/apps/web-antd/src/router/guard.ts | 7 +- vue/apps/web-antd/src/store/auth.ts | 2 +- vue/apps/web-antd/src/utils/file/download.ts | 139 ++++++ .../web-antd/src/utils/role-template.test.ts | 33 ++ vue/apps/web-antd/src/utils/role-template.ts | 29 ++ .../web-antd/src/views/_core/about/index.vue | 2 +- .../authentication/components/img-captcha.vue | 2 +- .../_core/authentication/forget-password.vue | 2 +- .../src/views/_core/authentication/login.vue | 2 +- .../views/_core/authentication/mfa-verify.vue | 2 +- .../_core/authentication/qrcode-login.vue | 2 +- .../views/_core/authentication/register.vue | 2 +- .../src/views/_core/fallback/coming-soon.vue | 2 +- .../src/views/_core/fallback/forbidden.vue | 2 +- .../views/_core/fallback/internal-error.vue | 2 +- .../src/views/_core/fallback/not-found.vue | 2 +- .../src/views/_core/fallback/offline.vue | 2 +- .../web-antd/src/views/_core/oauth-common.ts | 2 +- .../_core/profile/components/account-bind.vue | 2 +- .../_core/profile/components/base-setting.vue | 2 +- .../profile/components/online-device.vue | 2 +- .../profile/components/secure-setting.vue | 2 +- .../src/views/_core/profile/index.vue | 2 +- .../web-antd/src/views/_core/profile/mitt.ts | 2 +- .../src/views/_core/profile/profile-panel.vue | 2 +- .../src/views/_core/profile/setting-panel.vue | 2 +- .../src/views/agent/roles/menu-select.test.ts | 138 ++++++ .../src/views/agent/roles/menu-select.vue | 48 +- .../src/views/agent/roles/role-drawer.test.ts | 205 ++++++++ .../src/views/agent/roles/role-drawer.vue | 79 ++- .../src/views/agent/structure/index.vue | 57 ++- .../views/agent/structure/pagination.test.ts | 83 ++++ .../src/views/agent/structure/pagination.ts | 29 ++ .../src/views/agent/tApiGroup/index.vue | 8 +- .../src/views/agent/tApiGroup/model.tsx | 3 +- .../src/views/agent/tApiResource/index.vue | 8 +- .../src/views/agent/tApiResource/model.tsx | 4 +- .../web-antd/src/views/agent/users/index.vue | 42 +- .../src/views/common/tBalanceDetail/index.vue | 8 +- .../src/views/common/tBalanceDetail/model.tsx | 4 + .../src/views/common/tCreditDetail/index.vue | 8 +- .../common/tFinCommissionDetail/index.vue | 8 +- .../common/tFinCommissionDetail/model.tsx | 3 +- .../common/tFinWithdrawableChange/index.vue | 8 +- .../common/tFinWithdrawableChange/model.tsx | 2 + .../src/views/common/tFinanceApply/index.vue | 8 +- .../src/views/common/tFinanceApply/model.tsx | 6 +- .../common/tFinanceAuditRecord/index.vue | 8 +- .../common/tFinanceAuditRecord/model.tsx | 1 + .../src/views/common/tMessageLog/index.vue | 72 +-- .../src/views/common/tMessageLog/model.tsx | 3 + .../src/views/common/tNotifyLog/index.vue | 40 +- .../src/views/common/tNotifyLog/model.tsx | 1 + .../src/views/common/tWoRecord/index.vue | 8 +- .../src/views/common/tWoRecord/model.test.ts | 75 +++ .../src/views/common/tWoRecord/model.tsx | 29 +- .../dashboard/analytics/analytics-trends.vue | 2 +- .../analytics/analytics-visits-data.vue | 2 +- .../analytics/analytics-visits-sales.vue | 2 +- .../src/views/gen/testCategory/index.vue | 2 - .../web-antd/src/views/gen/testDemo/index.vue | 2 - .../src/views/iotlcm/downloadCenter/index.vue | 258 ++++++++++ .../web-antd/src/views/iotlcm/tApi/index.vue | 8 +- .../tChannel/tSimChannelTemplate/index.vue | 8 +- .../tChannel/tSimChannelTemplate/model.tsx | 1 + .../iotlcm/tChannel/tSimChannels/index.vue | 8 +- .../iotlcm/tChannel/tSimChannels/model.tsx | 6 + .../components/cardSourceTabs.vue | 8 +- .../tBusinessAcceptance/index.vue | 233 ++++----- .../views/cardBaseQuery.vue | 379 ++++++++++++++ .../tBusinessAcceptance/views/lifecycle.vue | 28 +- .../views/trafficCutoff.vue | 23 +- .../views/usageHistoryQuery.vue | 467 ++++++++++++++++++ .../views/warningConfig.vue | 22 +- .../tCommunication/tSimCardInfo/index.vue | 104 +++- .../tCommunication/tSimCardInfo/model.tsx | 12 +- .../tSimCardTrafficCutoff/index.vue | 29 +- .../views/iotlcm/tFlowPackageConfig/index.vue | 8 +- .../iotlcm/tIntelligentDiagnosis/model.ts | 4 +- .../iotlcm/tLifeCycle/batchFeedback.test.ts | 61 +++ .../views/iotlcm/tLifeCycle/batchFeedback.ts | 57 +++ .../views/iotlcm/tLifeCycle/tBatch/cards.vue | 14 +- .../views/iotlcm/tLifeCycle/tBatch/model.tsx | 28 +- .../views/iotlcm/tLifeCycle/tBatch/view.vue | 5 + .../components/fileDownloadButton.tsx | 46 +- .../tBatchExecutionLog/detailList.vue | 3 +- .../tLifeCycle/tBatchExecutionLog/index.vue | 48 +- .../tBatchExecutionLog/model.test.tsx | 107 +++- .../tLifeCycle/tBatchExecutionLog/model.tsx | 74 ++- .../tLifeCycle/tBatchExecutionLog/view.vue | 5 + .../tLifeCycle/tSimCardCancellation/index.vue | 13 +- .../tSimCardCancellation/model.test.ts | 43 ++ .../tLifeCycle/tSimCardCancellation/model.tsx | 17 + .../iotlcm/tLifeCycle/tSimCardStock/model.tsx | 28 ++ .../iotlcm/tLifeCycle/tWarehousing/index.vue | 29 +- .../tLifeCycle/tWarehousing/model.test.ts | 59 +++ .../iotlcm/tLifeCycle/tWarehousing/model.tsx | 17 +- .../src/views/iotlcm/tOrder/display.tsx | 4 + .../src/views/iotlcm/tOrder/index.vue | 7 +- .../src/views/iotlcm/tOrder/indexTwo.vue | 7 +- .../tSimFlowPackageInfo/index.vue | 11 +- .../tSimFlowPackageInfo/model.tsx | 3 + .../tSimFlowPackagePrice/index.vue | 27 +- .../tSimFlowPackagePrice/model.tsx | 1 + .../tSimPackageCategory/index.vue | 8 +- .../tSimPackageCategory/model.tsx | 1 + .../tSimUpstreamPackage/index.vue | 8 +- .../tSimUpstreamPackage/model.tsx | 1 + .../iotlcm/tWarnCenter/cardConfig/edit.vue | 65 ++- .../tWarnCenter/flowPoolConfig/edit.vue | 8 +- .../views/iotlcm/tWarnCenter/shared/model.tsx | 26 - .../zAnother/tAgentEnterprise/index.vue | 8 +- .../zAnother/tCustWithdrawAccount/index.vue | 8 +- .../zAnother/tCustWithdrawAccount/model.tsx | 1 + .../iotlcm/zAnother/tDivisionCode/index.vue | 8 +- .../cache/components/command-chart.vue | 2 +- .../views/monitor/cache/components/index.ts | 2 +- .../monitor/cache/components/memory-chart.vue | 2 +- .../cache/components/redis-description.vue | 2 +- .../src/views/monitor/cache/index.vue | 2 +- .../src/views/monitor/online/index.vue | 2 +- .../src/views/monitor/server/index.vue | 6 +- .../src/views/system/client/edit-drawer.vue | 2 +- .../src/views/system/client/index.vue | 2 +- .../src/views/system/client/model.tsx | 2 +- .../src/views/system/config/config-drawer.vue | 76 +-- .../src/views/system/config/index.vue | 2 +- .../web-antd/src/views/system/config/model.ts | 2 +- .../src/views/system/dept/dept-drawer.vue | 30 +- .../src/views/system/dept/dept-select.vue | 2 +- .../web-antd/src/views/system/dept/index.vue | 2 +- .../web-antd/src/views/system/dept/model.ts | 2 +- .../views/system/dept/supplement-modal.vue | 2 +- .../system/dict-data/dict-data-drawer.vue | 2 +- .../src/views/system/dict-data/index.vue | 2 +- .../src/views/system/dict-data/model.ts | 2 +- .../src/views/system/dict/dict-drawer.vue | 2 +- .../web-antd/src/views/system/dict/index.vue | 2 +- .../web-antd/src/views/system/dict/model.ts | 2 +- .../src/views/system/job/edit-drawer.vue | 2 +- .../web-antd/src/views/system/job/index.vue | 2 +- .../src/views/system/job/job-cron-model.vue | 2 +- .../web-antd/src/views/system/job/model.tsx | 2 +- .../src/views/system/job/view-drawer.vue | 2 +- .../src/views/system/logininfor/index.vue | 2 +- .../src/views/system/logininfor/model.tsx | 2 +- .../views/system/logininfor/view-drawer.vue | 2 +- .../web-antd/src/views/system/menu/index.vue | 2 +- .../src/views/system/menu/menu-drawer.vue | 2 +- .../src/views/system/menu/menu-select.vue | 2 +- .../web-antd/src/views/system/menu/model.ts | 2 +- .../src/views/system/notice/index.vue | 2 +- .../src/views/system/notice/model.tsx | 2 +- .../src/views/system/notice/notice-drawer.vue | 2 +- .../web-antd/src/views/system/oss/index.vue | 2 +- .../web-antd/src/views/system/post/index.vue | 11 +- .../web-antd/src/views/system/post/model.ts | 2 +- .../src/views/system/post/post-drawer.vue | 2 +- .../web-antd/src/views/system/role/index.vue | 33 +- .../web-antd/src/views/system/role/model.ts | 2 +- .../system/role/role-data-scope-modal.vue | 49 +- .../src/views/system/role/role-drawer.test.ts | 147 ++++++ .../src/views/system/role/role-drawer.vue | 42 +- .../src/views/system/sysNoticeUser/index.vue | 8 +- .../src/views/system/sysNoticeUser/model.tsx | 1 + .../web-antd/src/views/system/user/index.vue | 2 +- .../web-antd/src/views/system/user/model.ts | 2 +- .../src/views/system/user/user-drawer.vue | 2 +- .../web-antd/src/views/tool/gen/develop.vue | 2 +- .../web-antd/src/views/tool/gen/index.vue | 2 +- vue/build/nginx.conf | 2 +- .../vite-config/src/plugins/license.ts | 2 +- vue/package.json | 2 +- vue/packages/effects/access/src/accessible.ts | 30 +- .../stores/src/modules/tabbar.test.ts | 10 + .../__tests__/generate-routes-backend.test.ts | 125 +++++ .../src/helpers/generate-routes-backend.ts | 79 ++- .../deploy/build-local-docker-image.sh | 0 vue/scripts/turbo-run/bin/turbo-run.mjs | 0 vue/scripts/vsh/bin/vsh.mjs | 0 236 files changed, 5013 insertions(+), 708 deletions(-) mode change 100644 => 100755 vue/.husky/commit-msg mode change 100644 => 100755 vue/.husky/pre-commit create mode 100644 vue/apps/web-antd/src/api/common/downloadCenter/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/index.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/type.ts create mode 100644 vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.test.ts create mode 100644 vue/apps/web-antd/src/router/access-root-route.test.ts create mode 100644 vue/apps/web-antd/src/router/guard-login-redirect.test.ts create mode 100644 vue/apps/web-antd/src/utils/role-template.test.ts create mode 100644 vue/apps/web-antd/src/utils/role-template.ts create mode 100644 vue/apps/web-antd/src/views/agent/roles/menu-select.test.ts create mode 100644 vue/apps/web-antd/src/views/agent/roles/role-drawer.test.ts create mode 100644 vue/apps/web-antd/src/views/agent/structure/pagination.test.ts create mode 100644 vue/apps/web-antd/src/views/agent/structure/pagination.ts create mode 100644 vue/apps/web-antd/src/views/common/tWoRecord/model.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/downloadCenter/index.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/cardBaseQuery.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tCommunication/tBusinessAcceptance/views/usageHistoryQuery.vue create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/batchFeedback.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/batchFeedback.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tSimCardCancellation/model.test.ts create mode 100644 vue/apps/web-antd/src/views/iotlcm/tLifeCycle/tWarehousing/model.test.ts create mode 100644 vue/apps/web-antd/src/views/system/role/role-drawer.test.ts create mode 100644 vue/packages/utils/src/helpers/__tests__/generate-routes-backend.test.ts mode change 100644 => 100755 vue/scripts/deploy/build-local-docker-image.sh mode change 100644 => 100755 vue/scripts/turbo-run/bin/turbo-run.mjs mode change 100644 => 100755 vue/scripts/vsh/bin/vsh.mjs diff --git a/Makefile b/Makefile index c1d5861..1170237 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,4 @@ dockerbuild: build-no-build echo "docker build success" dockerpush: docker tag docker_iotlcmadminui:v0 ${REGISTRY}/docker_iotlcmadminui:v0 - docker push ${REGISTRY}/$1:$2 \ No newline at end of file + docker push ${REGISTRY}/docker_iotlcmadminui:v0 \ No newline at end of file diff --git a/vue/.husky/commit-msg b/vue/.husky/commit-msg old mode 100644 new mode 100755 diff --git a/vue/.husky/pre-commit b/vue/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/vue/apps/web-antd/package.json b/vue/apps/web-antd/package.json index 9d3f8b7..f04c7ef 100644 --- a/vue/apps/web-antd/package.json +++ b/vue/apps/web-antd/package.json @@ -11,7 +11,7 @@ "license": "MIT", "author": { "name": "vben", - "email": "annvben@example.com", + "email": "xxx@example.com", "url": "https://github.com/anncwb" }, "type": "module", diff --git a/vue/apps/web-antd/public/setting.json b/vue/apps/web-antd/public/setting.json index 7ec7815..7ea1074 100644 --- a/vue/apps/web-antd/public/setting.json +++ b/vue/apps/web-antd/public/setting.json @@ -6,9 +6,9 @@ "loginSloganImage": "", "copyright": { "companyName": "示例智联", - "companySiteLink": "https://www.xiujiezhilian.cn", + "companySiteLink": "https://example.com", "date": "2024-2025", - "icp": "鲁ICP备2024117944号-1", + "icp": "", "icpLink": "https://beian.miit.gov.cn/" } } diff --git a/vue/apps/web-antd/src/adapter/vxe-table.ts b/vue/apps/web-antd/src/adapter/vxe-table.ts index b0a1f00..e0e0d69 100644 --- a/vue/apps/web-antd/src/adapter/vxe-table.ts +++ b/vue/apps/web-antd/src/adapter/vxe-table.ts @@ -2,12 +2,11 @@ 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'; -import { useVbenForm } from './form'; - setupVbenVxeTable({ configVxeTable: (vxeUI) => { vxeUI.setConfig({ diff --git a/vue/apps/web-antd/src/api/agent/index.ts b/vue/apps/web-antd/src/api/agent/index.ts index 55e4ddc..f17e913 100644 --- a/vue/apps/web-antd/src/api/agent/index.ts +++ b/vue/apps/web-antd/src/api/agent/index.ts @@ -1,4 +1,4 @@ -import { requestClient } from '#/api/request'; +import { requestClient } from '#/api/request'; export interface AgentDept { deptId: number; @@ -60,6 +60,8 @@ export interface MenuTreeItem { } export interface AgentRoleView extends AgentRole { + isTemplateRole: boolean; + isDeptDefaultRole: boolean; menuIds: number[]; deptIds: number[]; allowedMenuIds: number[]; @@ -89,11 +91,35 @@ export interface AgentUser { isDefaultUser?: boolean; } -export function getAgentDeptListApi(params?: Record) { - return requestClient.get<{ items: AgentDept[]; total: number }>( - '/agent/dept/list', - { params }, - ); +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 }) { @@ -110,7 +136,10 @@ export function deleteAgentDeptApi(params: { deptId: number }) { return requestClient.post('/agent/dept/delete', { ...params }); } -export function resetAgentDeptPasswordApi(params: { deptId: number; password: string }) { +export function resetAgentDeptPasswordApi(params: { + deptId: number; + password: string; +}) { return requestClient.post('/agent/dept/resetPassword', { ...params }); } @@ -133,11 +162,17 @@ export function updateAgentUserApi(params: Record) { return requestClient.post('/agent/user/update', { ...params }); } -export function deleteAgentUserApi(params: { userId?: number; userIds?: number[] }) { +export function deleteAgentUserApi(params: { + userId?: number; + userIds?: number[]; +}) { return requestClient.post('/agent/user/delete', { ...params }); } -export function resetAgentUserPasswordApi(params: { userId: number; password: string }) { +export function resetAgentUserPasswordApi(params: { + password: string; + userId: number; +}) { return requestClient.post('/agent/user/resetPassword', { ...params }); } @@ -158,7 +193,10 @@ export function saveAgentRoleApi(params: Record) { }); } -export function deleteAgentRoleApi(params: { roleId?: number; roleIds?: number[] }) { +export function deleteAgentRoleApi(params: { + roleId?: number; + roleIds?: number[]; +}) { return requestClient.post('/agent/role/delete', { ...params }); } @@ -167,4 +205,3 @@ export function getAgentMenuTreeApi() { '/agent/menu/tree', ); } - diff --git a/vue/apps/web-antd/src/api/common/downloadCenter/index.ts b/vue/apps/web-antd/src/api/common/downloadCenter/index.ts new file mode 100644 index 0000000..5d4b936 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/common/tMessageLog/index.ts b/vue/apps/web-antd/src/api/common/tMessageLog/index.ts index 28ca887..467075f 100644 --- a/vue/apps/web-antd/src/api/common/tMessageLog/index.ts +++ b/vue/apps/web-antd/src/api/common/tMessageLog/index.ts @@ -27,3 +27,37 @@ export function Export(params:any) { 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/vue/apps/web-antd/src/api/core/auth.ts b/vue/apps/web-antd/src/api/core/auth.ts index 6500ca4..b15abf2 100644 --- a/vue/apps/web-antd/src/api/core/auth.ts +++ b/vue/apps/web-antd/src/api/core/auth.ts @@ -2,7 +2,7 @@ * @description 认证相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/core/captcha.ts b/vue/apps/web-antd/src/api/core/captcha.ts index b4c809b..bead42e 100644 --- a/vue/apps/web-antd/src/api/core/captcha.ts +++ b/vue/apps/web-antd/src/api/core/captcha.ts @@ -2,7 +2,7 @@ * @description 验证码相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/core/index.ts b/vue/apps/web-antd/src/api/core/index.ts index 949e7b6..fdb5dfe 100644 --- a/vue/apps/web-antd/src/api/core/index.ts +++ b/vue/apps/web-antd/src/api/core/index.ts @@ -2,7 +2,7 @@ * @description 核心模块接口导出 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/core/menu.ts b/vue/apps/web-antd/src/api/core/menu.ts index 94cf36e..ac62587 100644 --- a/vue/apps/web-antd/src/api/core/menu.ts +++ b/vue/apps/web-antd/src/api/core/menu.ts @@ -2,7 +2,7 @@ * @description 菜单相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/core/upload.ts b/vue/apps/web-antd/src/api/core/upload.ts index 3615ff6..0684294 100644 --- a/vue/apps/web-antd/src/api/core/upload.ts +++ b/vue/apps/web-antd/src/api/core/upload.ts @@ -2,7 +2,7 @@ * @description 文件上传相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/core/user.ts b/vue/apps/web-antd/src/api/core/user.ts index c1756af..6b98722 100644 --- a/vue/apps/web-antd/src/api/core/user.ts +++ b/vue/apps/web-antd/src/api/core/user.ts @@ -2,7 +2,7 @@ * @description 用户信息相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/gen/testDemo/index.ts b/vue/apps/web-antd/src/api/gen/testDemo/index.ts index 7f38cb8..ac15492 100644 --- a/vue/apps/web-antd/src/api/gen/testDemo/index.ts +++ b/vue/apps/web-antd/src/api/gen/testDemo/index.ts @@ -2,7 +2,7 @@ * @description 测试单表相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/gen_codes/gen_table.ts b/vue/apps/web-antd/src/api/gen_codes/gen_table.ts index b2dbb41..c898490 100644 --- a/vue/apps/web-antd/src/api/gen_codes/gen_table.ts +++ b/vue/apps/web-antd/src/api/gen_codes/gen_table.ts @@ -2,7 +2,7 @@ * @description 代码生成器表格相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/index.ts b/vue/apps/web-antd/src/api/index.ts index 5bcebc9..e826da0 100644 --- a/vue/apps/web-antd/src/api/index.ts +++ b/vue/apps/web-antd/src/api/index.ts @@ -2,7 +2,7 @@ * @description API接口统一导出 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts index ffa20e6..71231a1 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardInfo/index.ts @@ -5,6 +5,11 @@ 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 }); diff --git a/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/index.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/index.ts new file mode 100644 index 0000000..dcb0ebb --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardQuery/type.ts new file mode 100644 index 0000000..4be8b04 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts index ebc120a..b6f4df8 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardTrafficCutoff/type.ts @@ -37,6 +37,7 @@ export interface TSimCardTrafficCutoffModel { } export interface TSimCardTrafficCutoffListParam { + includeUnconfigured?: boolean; page: number; pageSize: number; cardValue?: string; diff --git a/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts index 7234f53..34fcd20 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tCommunication/tSimCardUnsub/index.test.ts @@ -1,3 +1,5 @@ +import type { TSimCardUnsubSubmitRes } from './type'; + import { beforeEach, describe, expect, it, vi } from 'vitest'; const download = vi.fn(); @@ -80,8 +82,7 @@ describe('tSimCardUnsub api', () => { }); it('exposes batchAsyncStatus on the submit response type so async Pending is representable', async () => { - const typeModule = await import('./type'); - const res: typeof typeModule.TSimCardUnsubSubmitRes.prototype = { + const res: TSimCardUnsubSubmitRes = { batchAsyncStatus: 0, batchNo: 'B202607210001', batchType: 1, @@ -123,4 +124,3 @@ describe('tSimCardUnsub api', () => { ); }); }); - diff --git a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.test.ts new file mode 100644 index 0000000..3a7f1c3 --- /dev/null +++ b/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/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts index 915e199..9fe6797 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/index.ts @@ -52,6 +52,20 @@ export function View(params: BatchMainViewParam) { }); } +// 导出入库批次列表(数据与入库管理页一致) +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( diff --git a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts index 26d4f6d..91b72e9 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tBatch/type.ts @@ -147,13 +147,16 @@ export interface BatchMainListParam { export type BatchMainWarehousingListParam = Omit< BatchMainListParam, 'batchType' ->; +> & { + chanKey?: string; +}; /** 获取批次主表列表 响应 */ export type BatchMainListRes = GlobalListRes; /** 批次卡清单列表项 */ export interface BatchCardListModel extends AllocationUnits { + errorReason?: string; /** 明细状态 */ detailStatus?: number; /** ICCID */ @@ -169,6 +172,7 @@ export interface BatchCardListModel extends AllocationUnits { /** 获取批次卡清单请求参数 */ export interface BatchMainCardsParam { + detailStatus?: number; /** 批次编号 */ batchNo: string; /** 批次类型 */ diff --git a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts index 1f8b0d4..7965934 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardOutbound/index.test.ts @@ -45,7 +45,7 @@ describe('tSimCardOutbound api', () => { '/iot/tSimCardOutbound/excel/submit', { file }, { - timeout: 60_000, + timeout: 180_000, }, ); }); @@ -71,6 +71,7 @@ describe('tSimCardOutbound api', () => { expect(post).toHaveBeenCalledWith( '/iot/tSimCardOutbound/range/submit', params, + { timeout: 180_000 }, ); }); @@ -117,12 +118,9 @@ describe('tSimCardOutbound api', () => { CustomerBalance(params); - expect(get).toHaveBeenCalledWith( - '/iot/tSimCardOutbound/customerBalance', - { - params, - }, - ); + expect(get).toHaveBeenCalledWith('/iot/tSimCardOutbound/customerBalance', { + params, + }); }); it('submits inbound batch outbound with backend-supported payload', async () => { @@ -141,6 +139,7 @@ describe('tSimCardOutbound api', () => { expect(post).toHaveBeenCalledWith( '/iot/tSimCardOutbound/batch/submit', params, + { timeout: 180_000 }, ); }); @@ -160,6 +159,7 @@ describe('tSimCardOutbound api', () => { expect(post).toHaveBeenCalledWith( '/iot/tSimCardOutbound/input/submit', params, + { timeout: 180_000 }, ); }); }); diff --git a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts index f7e5a5a..294c0c6 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tLifeCycle/tSimCardStock/type.ts @@ -31,6 +31,8 @@ export interface TSimCardStockModel { tenantId: string; /** 创建部门 */ createdDept: number; + /** 创建部门名称 */ + createdDeptName?: string; /** 创建者 */ createdBy: number; /** 创建者摘要信息 */ diff --git a/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts index 6058dda..322a49f 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/index.ts @@ -5,6 +5,8 @@ import type { BatchExecutionLogListRes, BatchExecutionLogSummaryParam, BatchExecutionLogSummaryRes, + BatchExecutionLogSyncReviewParam, + BatchExecutionLogSyncReviewRes, } from './type'; import { requestClient } from '#/api/request'; @@ -38,3 +40,11 @@ export function DetailList(params: BatchExecutionLogDetailListParam) { }, ); } + +// 手动同步待核查批次的上游执行结果(只读补查既有受理号,不重发办理) +export function SyncReview(data: BatchExecutionLogSyncReviewParam) { + return requestClient.post( + 'common/batchExecutionLog/syncReview', + { ...data }, + ); +} diff --git a/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts index af8092a..8544cfc 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tOperationlog/type.ts @@ -20,12 +20,18 @@ export interface BatchExecutionLogModel extends AllocationUnits { batchNo?: string; /** 异步处理状态 */ batchAsyncStatus?: number; + /** 重启阶段:waiting_resume 表示停机后等待复机 */ + restartPhase?: string; + /** 计划复机时间 */ + restartResumeAt?: string; /** 批次类型 */ batchType?: number; /** 来源方式 */ sourceType?: null | number; /** 总数量 */ totalCount?: number; + /** 待核查数量 */ + unknownCount?: number; /** 运行结果 */ runResult?: number; /** 开始时间 */ @@ -52,12 +58,18 @@ export interface BatchExecutionLogSummaryRes extends AllocationUnits { batchNo?: string; /** 异步处理状态 */ batchAsyncStatus?: number; + /** 重启阶段:waiting_resume 表示停机后等待复机 */ + restartPhase?: string; + /** 计划复机时间 */ + restartResumeAt?: string; /** 批次类型 */ batchType?: number; /** 来源方式 */ sourceType?: null | number; /** 总数量 */ totalCount?: number; + /** 待核查数量 */ + unknownCount?: number; /** 运行结果 */ runResult?: number; /** 失败原因 */ @@ -74,6 +86,8 @@ export interface BatchExecutionLogSummaryRes extends AllocationUnits { /** 批次执行日志文件信息 */ export interface BatchExecutionLogFileModel { + /** 导出任务ID;与历史批次下载任务ID分开,走下载中心鉴权 */ + exportTaskId?: number; /** OSS文件ID */ ossId?: number; /** 文件URL */ @@ -82,6 +96,8 @@ export interface BatchExecutionLogFileModel { /** 批次执行日志结果文件信息 */ export interface BatchExecutionLogResultFileModel extends BatchExecutionLogFileModel { + /** 原始下载文件名 */ + originalName?: string; /** 下载任务ID */ downloadId?: number; /** 下载状态 */ @@ -113,6 +129,28 @@ export interface BatchExecutionLogListParam { /** 获取批次执行日志列表响应 */ 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 { /** 协议到期时间 */ diff --git a/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts b/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts index 113819d..2d6f71a 100644 --- a/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts +++ b/vue/apps/web-antd/src/api/iotlcm/tWarnCenter/simWarningConfig/type.ts @@ -16,6 +16,7 @@ export interface SimWarningConfigModel { warnPhones?: string; warnEmails?: string; autoAction?: number; + isEnabled: number; wxTemplateId?: string; remark?: string; @@ -60,6 +61,7 @@ export interface SimWarningConfigSaveParam { warnPhones?: string; warnEmails?: string; autoAction?: number; + isEnabled?: number; remark?: string; } diff --git a/vue/apps/web-antd/src/api/monitor/cache.ts b/vue/apps/web-antd/src/api/monitor/cache.ts index 47a4d2d..cbfc13b 100644 --- a/vue/apps/web-antd/src/api/monitor/cache.ts +++ b/vue/apps/web-antd/src/api/monitor/cache.ts @@ -2,7 +2,7 @@ * @description 缓存监控相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/monitor/index.ts b/vue/apps/web-antd/src/api/monitor/index.ts index 8a9ace0..acc6496 100644 --- a/vue/apps/web-antd/src/api/monitor/index.ts +++ b/vue/apps/web-antd/src/api/monitor/index.ts @@ -2,7 +2,7 @@ * @description 监控模块接口导出 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/monitor/online.ts b/vue/apps/web-antd/src/api/monitor/online.ts index 3c6027d..7e47af3 100644 --- a/vue/apps/web-antd/src/api/monitor/online.ts +++ b/vue/apps/web-antd/src/api/monitor/online.ts @@ -2,7 +2,7 @@ * @description 在线用户监控相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/request.ts b/vue/apps/web-antd/src/api/request.ts index c574682..122c3d7 100644 --- a/vue/apps/web-antd/src/api/request.ts +++ b/vue/apps/web-antd/src/api/request.ts @@ -2,7 +2,7 @@ * @description 请求客户端配置 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ @@ -116,12 +116,11 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) { if (config.responseReturn === 'body') { return responseData; } else if (headers['content-type']?.includes?.('application/json')) { - if (config.responseType === 'blob' && Reflect.has(responseData, 'data')) - { - // 这时候的data为blob类型 - const blob = responseData.data as unknown as Blob; - // 拿到字符串转json对象 - responseData.data = JSON.parse(await blob.text()); + // 导出/下载类接口用 blob 方式接收 JSON 回执(异步导出只回任务信息,没有文件流)。 + // 此时 axios 的 responseData 就是 Blob 本身,Blob 上没有 code 字段, + // 若继续走下面的业务码判断会被误判为失败并抛错,所以直接交给调用方解析。 + if (config.responseType === 'blob') { + return responseData; } } else if (headers['content-type']?.includes?.('application/octet-stream')) { // 下载文件 diff --git a/vue/apps/web-antd/src/api/system/client.ts b/vue/apps/web-antd/src/api/system/client.ts index 50bcd7b..72b51b4 100644 --- a/vue/apps/web-antd/src/api/system/client.ts +++ b/vue/apps/web-antd/src/api/system/client.ts @@ -2,7 +2,7 @@ * @description 客户端管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/config.ts b/vue/apps/web-antd/src/api/system/config.ts index 59232f3..cf5d7f4 100644 --- a/vue/apps/web-antd/src/api/system/config.ts +++ b/vue/apps/web-antd/src/api/system/config.ts @@ -2,7 +2,7 @@ * @description 系统配置相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/dept.ts b/vue/apps/web-antd/src/api/system/dept.ts index bfe71aa..ef98807 100644 --- a/vue/apps/web-antd/src/api/system/dept.ts +++ b/vue/apps/web-antd/src/api/system/dept.ts @@ -2,7 +2,7 @@ * @description 组织管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/dict.ts b/vue/apps/web-antd/src/api/system/dict.ts index 92ec7ed..080f1b8 100644 --- a/vue/apps/web-antd/src/api/system/dict.ts +++ b/vue/apps/web-antd/src/api/system/dict.ts @@ -2,7 +2,7 @@ * @description 字典管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/index.ts b/vue/apps/web-antd/src/api/system/index.ts index 210e362..6e32ecb 100644 --- a/vue/apps/web-antd/src/api/system/index.ts +++ b/vue/apps/web-antd/src/api/system/index.ts @@ -2,7 +2,7 @@ * @description 系统管理模块接口导出 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/job.ts b/vue/apps/web-antd/src/api/system/job.ts index 450fe00..033d9ee 100644 --- a/vue/apps/web-antd/src/api/system/job.ts +++ b/vue/apps/web-antd/src/api/system/job.ts @@ -2,7 +2,7 @@ * @description 定时任务相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/logininfor.ts b/vue/apps/web-antd/src/api/system/logininfor.ts index 3bd5fbc..45f0ba9 100644 --- a/vue/apps/web-antd/src/api/system/logininfor.ts +++ b/vue/apps/web-antd/src/api/system/logininfor.ts @@ -2,7 +2,7 @@ * @description 登录日志相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/menu.ts b/vue/apps/web-antd/src/api/system/menu.ts index 0f4047d..c9f042b 100644 --- a/vue/apps/web-antd/src/api/system/menu.ts +++ b/vue/apps/web-antd/src/api/system/menu.ts @@ -2,7 +2,7 @@ * @description 菜单管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/notice.ts b/vue/apps/web-antd/src/api/system/notice.ts index ac9fba2..96203d4 100644 --- a/vue/apps/web-antd/src/api/system/notice.ts +++ b/vue/apps/web-antd/src/api/system/notice.ts @@ -2,7 +2,7 @@ * @description 通知公告相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/oper-log.ts b/vue/apps/web-antd/src/api/system/oper-log.ts index 94a8dfb..2e1683e 100644 --- a/vue/apps/web-antd/src/api/system/oper-log.ts +++ b/vue/apps/web-antd/src/api/system/oper-log.ts @@ -2,7 +2,7 @@ * @description 操作日志相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/oss.ts b/vue/apps/web-antd/src/api/system/oss.ts index b540332..c06a882 100644 --- a/vue/apps/web-antd/src/api/system/oss.ts +++ b/vue/apps/web-antd/src/api/system/oss.ts @@ -2,7 +2,7 @@ * @description 对象存储管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/post.ts b/vue/apps/web-antd/src/api/system/post.ts index 15bf175..c64d9c2 100644 --- a/vue/apps/web-antd/src/api/system/post.ts +++ b/vue/apps/web-antd/src/api/system/post.ts @@ -2,7 +2,7 @@ * @description 岗位管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/qrcode.ts b/vue/apps/web-antd/src/api/system/qrcode.ts index 749054a..0f39baf 100644 --- a/vue/apps/web-antd/src/api/system/qrcode.ts +++ b/vue/apps/web-antd/src/api/system/qrcode.ts @@ -2,7 +2,7 @@ * @description 系统二维码管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/role.ts b/vue/apps/web-antd/src/api/system/role.ts index 7ce3da0..001aa90 100644 --- a/vue/apps/web-antd/src/api/system/role.ts +++ b/vue/apps/web-antd/src/api/system/role.ts @@ -2,7 +2,7 @@ * @description 角色管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ @@ -12,6 +12,7 @@ import { requestClient } from '#/api/request'; export interface SysRoleListParam { page?: number; pageSize?: number; + deptId?: number; roleName?: string; roleKey?: string; status?: string; @@ -19,22 +20,26 @@ export interface SysRoleListParam { } 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; + 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 { - roleId: number; + isTemplateRole: boolean; + isDeptDefaultRole: boolean; + roleMenuDataScopes: Record; + deptId: number; + roleId: number; tenantId: string; roleName: string; roleKey: string; @@ -96,14 +101,11 @@ export interface SysRoleDeleteParam { roleIds: number[]; } -export interface SysRoleAddRes { -} +export interface SysRoleAddRes {} -export interface SysRoleEditRes { -} +export interface SysRoleEditRes {} -export interface SysRoleDeleteRes { -} +export interface SysRoleDeleteRes {} export interface SysRoleDataScopeEditParam { roleId: number; @@ -111,26 +113,34 @@ export interface SysRoleDataScopeEditParam { deptCheckStrictly?: number; deptIds?: number[]; } -export interface SysRoleDataScopeEditRes { -} +export interface SysRoleDataScopeEditRes {} -export async function addSysRoleApi(params: SysRoleAddParam|any) { +export async function addSysRoleApi(params: SysRoleAddParam | any) { return requestClient.post('/system/role/add', { ...params }); } -export async function editSysRoleApi(params: SysRoleEditParam|any) { +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 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); +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 }); +export async function editSysRoleDataScopeApi( + params: SysRoleDataScopeEditParam | any, +) { + return requestClient.post('/system/role/dataScope', { + ...params, + }); } diff --git a/vue/apps/web-antd/src/api/system/social.ts b/vue/apps/web-antd/src/api/system/social.ts index 5dc5086..0183d38 100644 --- a/vue/apps/web-antd/src/api/system/social.ts +++ b/vue/apps/web-antd/src/api/system/social.ts @@ -2,7 +2,7 @@ * @description 社交账号管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/api/system/user.ts b/vue/apps/web-antd/src/api/system/user.ts index 97cead5..cbb301f 100644 --- a/vue/apps/web-antd/src/api/system/user.ts +++ b/vue/apps/web-antd/src/api/system/user.ts @@ -2,7 +2,7 @@ * @description 用户管理相关接口 * @Link https://github.com/xiujiecn/xiu-admin * @Copyright Copyright (c) 2025 LiXiujie - * @Author Lxj + * @Author Lxj * @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE * @date 2024-03-21 */ diff --git a/vue/apps/web-antd/src/config/setting.ts b/vue/apps/web-antd/src/config/setting.ts index e078aae..f5e857f 100644 --- a/vue/apps/web-antd/src/config/setting.ts +++ b/vue/apps/web-antd/src/config/setting.ts @@ -57,9 +57,9 @@ const DEFAULT_RUNTIME_SETTING: RuntimeSetting = { appTitle: '智联·云', copyright: { companyName: '示例智联', - companySiteLink: 'https://www.xiujiezhilian.cn', + companySiteLink: 'https://example.com', date: '2024-2025', - icp: '鲁ICP备2024117944号-1', + icp: '', icpLink: 'https://beian.miit.gov.cn/', }, loginPageDescription: '新一代物联网设备统一接入平台', diff --git a/vue/apps/web-antd/src/layouts/basic.vue b/vue/apps/web-antd/src/layouts/basic.vue index 070d18e..e59edb4 100644 --- a/vue/apps/web-antd/src/layouts/basic.vue +++ b/vue/apps/web-antd/src/layouts/basic.vue @@ -1,14 +1,14 @@ +