diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f7785bd --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = tab +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..873c9d8 --- /dev/null +++ b/.env.development @@ -0,0 +1,3 @@ +VITE_APP_TITLE=Gao Customer H5 +VITE_USE_LOCAL_TIMI_WEB=true +VITE_API_BASE_URL=http://localhost:8091 diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..dd8bb80 --- /dev/null +++ b/.env.production @@ -0,0 +1,2 @@ +VITE_APP_TITLE=Gao Customer H5 +VITE_API_BASE_URL=https://api.imyeyu.com diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..ae13a7c --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,44 @@ +module.exports = { + root: true, + env: { + browser: true, + es2022: true, + node: true + }, + extends: [ + "eslint:recommended", + "plugin:vue/vue3-essential", + "plugin:@typescript-eslint/recommended", + "./.eslintrc-auto-import.json" + ], + parser: "vue-eslint-parser", + parserOptions: { + parser: "@typescript-eslint/parser", + ecmaVersion: "latest", + sourceType: "module", + extraFileExtensions: [".vue"] + }, + plugins: ["vue", "@typescript-eslint"], + rules: { + "camelcase": "error", + "comma-dangle": ["error", "never"], + "eqeqeq": ["error", "always"], + "max-len": ["error", { code: 220 }], + "no-console": ["warn", { allow: ["warn", "error"] }], + "no-debugger": "warn", + "no-tabs": ["error", { allowIndentationTabs: true }], + "quotes": ["error", "double"], + "semi": ["error", "always"], + "space-before-function-paren": [ + "error", + { + "anonymous": "always", + "named": "never", + "asyncArrow": "always" + } + ], + "vue/multi-word-component-names": "off", + "vue/no-v-html": "off", + "@typescript-eslint/no-explicit-any": "off" + } +}; diff --git a/.gitignore b/.gitignore index 7f7e9bb..6fd4a3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +/AGENTS.md +/.npmrc +/.env.production + # ---> Maven target/ pom.xml.tag @@ -122,3 +126,13 @@ fabric.properties hs_err_pid* replay_pid* +# ---> Node / Vite +node_modules +dist +dist-ssr +coverage +*.local +auto-imports.d.ts +components.d.ts +.eslintrc-auto-import.json + diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..30cf57e --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/gao-customer-h5.iml b/.idea/gao-customer-h5.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/gao-customer-h5.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..9f87cb1 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,20 @@ + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9c28189 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.serena/.gitignore b/.serena/.gitignore new file mode 100644 index 0000000..2e510af --- /dev/null +++ b/.serena/.gitignore @@ -0,0 +1,2 @@ +/cache +/project.local.yml diff --git a/.serena/memories/project_overview.md b/.serena/memories/project_overview.md new file mode 100644 index 0000000..5ff99e2 --- /dev/null +++ b/.serena/memories/project_overview.md @@ -0,0 +1,4 @@ +- 项目用途:基于 Vue 3 + Vite + TypeScript + TDesign 的移动端 NAS 管理项目,包含文件管理、服务器状态、文件读取等功能。 +- 前端栈:Vue 3 Composition API(setup 语法糖)、Vite、TypeScript、Pinia、Vue Router、Axios、Less、TDesign。 +- 后端接口上下文:对接后端源码位于 E:\IDEAProject\TimiServerAPI\src\main\java\com\imyeyu\api\modules\system\controller。 +- 代码结构:主要业务页面位于 src/pages,下分 customer、management 等目录;入口与路由位于 src/main.ts、src/router/index.ts;存在 Pinia store。 \ No newline at end of file diff --git a/.serena/memories/style_conventions.md b/.serena/memories/style_conventions.md new file mode 100644 index 0000000..dae71a6 --- /dev/null +++ b/.serena/memories/style_conventions.md @@ -0,0 +1,6 @@ +- 所有沟通、文案、注释使用中文;文件编码使用 UTF-8。 +- 前端使用 Vue 3 Composition API + setup,代码按功能分块组织,公共变量/函数在前。 +- Vue 自定义组件标签使用全小写;模板中动态文本优先使用 v-text。 +- Less 必须使用层级写法,属性尽量缩写,单位优先 rem,小数写法如 .5。 +- 尽量定义 TypeScript 类型和必要的 JSDoc;Promise 写法优先 async/await。 +- 不轻易引入外部依赖,优先官方 API;需要兼容深色模式。 \ No newline at end of file diff --git a/.serena/memories/suggested_commands.md b/.serena/memories/suggested_commands.md new file mode 100644 index 0000000..d4b5c6e --- /dev/null +++ b/.serena/memories/suggested_commands.md @@ -0,0 +1,7 @@ +- 安装依赖:npm install +- 本地开发:npm run dev +- 生产构建:npm run build +- 预览构建:npm run preview +- ESLint 检查:npm run lint +- TypeScript 检查:npm run type-check +- Windows 常用命令:Get-ChildItem、Get-Content、rg、git status、git diff \ No newline at end of file diff --git a/.serena/memories/task_completion.md b/.serena/memories/task_completion.md new file mode 100644 index 0000000..80ed1c5 --- /dev/null +++ b/.serena/memories/task_completion.md @@ -0,0 +1,3 @@ +- 完成前端改动后,至少执行 npm run build 或 npm run type-check 验证没有明显编译错误。 +- 如涉及样式和交互,检查深色模式与移动端布局,避免固定底部按钮遮挡内容。 +- 不主动添加测试;若无法运行验证命令,需要在最终说明中明确指出。 \ No newline at end of file diff --git a/.serena/project.yml b/.serena/project.yml new file mode 100644 index 0000000..08e55a8 --- /dev/null +++ b/.serena/project.yml @@ -0,0 +1,153 @@ +# the name by which the project can be referenced within Serena +project_name: "gao-customer-h5" + + +# list of languages for which language servers are started; choose from: +# al bash clojure cpp csharp +# csharp_omnisharp dart elixir elm erlang +# fortran fsharp go groovy haskell +# haxe java julia kotlin lua +# markdown +# matlab nix pascal perl php +# php_phpactor powershell python python_jedi r +# rego ruby ruby_solargraph rust scala +# swift terraform toml typescript typescript_vts +# vue yaml zig +# (This list may be outdated. For the current list, see values of Language enum here: +# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py +# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) +# Note: +# - For C, use cpp +# - For JavaScript, use typescript +# - For Free Pascal/Lazarus, use pascal +# Special requirements: +# Some languages require additional setup/installations. +# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers +# When using multiple languages, the first language server that supports a given file will be used for that file. +# The first language is the default language and the respective language server will be used as a fallback. +# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. +languages: [] + +# the encoding used by text files in the project +# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings +encoding: "utf-8" + +# line ending convention to use when writing source files. +# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) +# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. +line_ending: + +# The language backend to use for this project. +# If not set, the global setting from serena_config.yml is used. +# Valid values: LSP, JetBrains +# Note: the backend is fixed at startup. If a project with a different backend +# is activated post-init, an error will be returned. +language_backend: + +# whether to use project's .gitignore files to ignore files +ignore_all_files_in_gitignore: true + +# advanced configuration option allowing to configure language server-specific options. +# Maps the language key to the options. +# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. +# No documentation on options means no options are available. +ls_specific_settings: {} + +# list of additional paths to ignore in this project. +# Same syntax as gitignore, so you can use * and **. +# Note: global ignored_paths from serena_config.yml are also applied additively. +ignored_paths: [] + +# whether the project is in read-only mode +# If set to true, all editing tools will be disabled and attempts to use them will result in an error +# Added on 2025-04-18 +read_only: false + +# list of tool names to exclude. +# This extends the existing exclusions (e.g. from the global configuration) +# +# Below is the complete list of tools for convenience. +# To make sure you have the latest list of tools, and to view their descriptions, +# execute `uv run scripts/print_tool_overview.py`. +# +# * `activate_project`: Activates a project based on the project name or path. +# * `check_onboarding_performed`: Checks whether project onboarding was already performed. +# * `create_text_file`: Creates/overwrites a file in the project directory. +# * `delete_memory`: Delete a memory file. Should only happen if a user asks for it explicitly, +# for example by saying that the information retrieved from a memory file is no longer correct +# or no longer relevant for the project. +# * `edit_memory`: Replaces content matching a regular expression in a memory. +# * `execute_shell_command`: Executes a shell command. +# * `find_file`: Finds files in the given relative paths +# * `find_referencing_symbols`: Finds symbols that reference the given symbol using the language server backend +# * `find_symbol`: Performs a global (or local) search using the language server backend. +# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes. +# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file. +# * `initial_instructions`: Provides instructions Serena usage (i.e. the 'Serena Instructions Manual') +# for clients that do not read the initial instructions when the MCP server is connected. +# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol. +# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol. +# * `list_dir`: Lists files and directories in the given directory (optionally with recursion). +# * `list_memories`: List available memories. Any memory can be read using the `read_memory` tool. +# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building). +# * `read_file`: Reads a file within the project directory. +# * `read_memory`: Read the content of a memory file. This tool should only be used if the information +# is relevant to the current task. You can infer whether the information +# is relevant from the memory file name. +# You should not read the same memory file multiple times in the same conversation. +# * `rename_memory`: Renames or moves a memory. Moving between project and global scope is supported +# (e.g., renaming "global/foo" to "bar" moves it from global to project scope). +# * `rename_symbol`: Renames a symbol throughout the codebase using language server refactoring capabilities. +# For JB, we use a separate tool. +# * `replace_content`: Replaces content in a file (optionally using regular expressions). +# * `replace_symbol_body`: Replaces the full definition of a symbol using the language server backend. +# * `safe_delete_symbol`: +# * `search_for_pattern`: Performs a search for a pattern in the project. +# * `write_memory`: Write some information (utf-8-encoded) about this project that can be useful for future tasks to a memory in md format. +# The memory name should be meaningful. +excluded_tools: [] + +# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). +# This extends the existing inclusions (e.g. from the global configuration). +included_optional_tools: [] + +# fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. +# This cannot be combined with non-empty excluded_tools or included_optional_tools. +fixed_tools: [] + +# list of mode names to that are always to be included in the set of active modes +# The full set of modes to be activated is base_modes + default_modes. +# If the setting is undefined, the base_modes from the global configuration (serena_config.yml) apply. +# Otherwise, this setting overrides the global configuration. +# Set this to [] to disable base modes for this project. +# Set this to a list of mode names to always include the respective modes for this project. +base_modes: + +# list of mode names that are to be activated by default. +# The full set of modes to be activated is base_modes + default_modes. +# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply. +# Otherwise, this overrides the setting from the global configuration (serena_config.yml). +# This setting can, in turn, be overridden by CLI parameters (--mode). +default_modes: + +# initial prompt for the project. It will always be given to the LLM upon activating the project +# (contrary to the memories, which are loaded on demand). +initial_prompt: "" + +# time budget (seconds) per tool call for the retrieval of additional symbol information +# such as docstrings or parameter information. +# This overrides the corresponding setting in the global configuration; see the documentation there. +# If null or missing, use the setting from the global configuration. +symbol_info_budget: + +# list of regex patterns which, when matched, mark a memory entry as read‑only. +# Extends the list from the global configuration, merging the two lists. +read_only_memory_patterns: [] + +# list of regex patterns for memories to completely ignore. +# Matching memories will not appear in list_memories or activate_project output +# and cannot be accessed via read_memory or write_memory. +# To access ignored memory files, use the read_file tool on the raw file path. +# Extends the list from the global configuration, merging the two lists. +# Example: ["_archive/.*", "_episodes/.*"] +ignored_memory_patterns: [] diff --git a/README.md b/README.md index d9d6670..2291917 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -# dtgao-customer-h5 +# gao-customer-h5 + +基于 Vue 3、Vite、TypeScript、Pinia、Vue Router、TDesign Mobile Vue 的移动端项目初始化骨架。 diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..7f0be18 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,79 @@ +import tsParser from "@typescript-eslint/parser"; +import tsPlugin from "@typescript-eslint/eslint-plugin"; +import vuePlugin from "eslint-plugin-vue"; +import vueParser from "vue-eslint-parser"; +import autoImportConfig from "./.eslintrc-auto-import.json" with { type: "json" }; + +const browserGlobals = { + document: "readonly", + File: "readonly", + HTMLCanvasElement: "readonly", + HTMLInputElement: "readonly", + HTMLElement: "readonly", + localStorage: "readonly", + MouseEvent: "readonly", + Touch: "readonly", + TouchEvent: "readonly", + URL: "readonly", + window: "readonly" +}; + +const nodeGlobals = { + console: "readonly", + process: "readonly" +}; + +export default [ + { + ignores: [ + "dist/**", + "node_modules/**", + "auto-imports.d.ts", + "components.d.ts" + ] + }, + ...vuePlugin.configs["flat/essential"], + { + files: ["**/*.ts", "**/*.vue"], + languageOptions: { + parser: vueParser, + parserOptions: { + parser: tsParser, + ecmaVersion: "latest", + sourceType: "module", + extraFileExtensions: [".vue"] + }, + globals: { + ...browserGlobals, + ...nodeGlobals, + ...autoImportConfig.globals + } + }, + plugins: { + "@typescript-eslint": tsPlugin + }, + rules: { + ...tsPlugin.configs.recommended.rules, + camelcase: "error", + "comma-dangle": ["error", "never"], + eqeqeq: ["error", "always"], + "max-len": ["error", { code: 220 }], + "no-console": ["warn", { allow: ["warn", "error"] }], + "no-debugger": "warn", + "no-tabs": ["error", { allowIndentationTabs: true }], + quotes: ["error", "double"], + semi: ["error", "always"], + "space-before-function-paren": [ + "error", + { + anonymous: "always", + named: "never", + asyncArrow: "always" + } + ], + "vue/multi-word-component-names": "off", + "vue/no-v-html": "off", + "@typescript-eslint/no-explicit-any": "off" + } + } +]; diff --git a/index.html b/index.html new file mode 100644 index 0000000..4bb048e --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + Gao Customer H5 + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..7272345 --- /dev/null +++ b/package.json @@ -0,0 +1,49 @@ +{ + "name": "gao-customer-h5", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite --host", + "build": "pnpm run type-check:publish && vite build", + "preview": "vite preview", + "lint": "eslint . --ext .ts,.vue", + "type-check": "vue-tsc -p tsconfig.app.json --noEmit", + "type-check:publish": "vue-tsc -p tsconfig.publish.json --noEmit" + }, + "dependencies": { + "@zxing/browser": "^0.1.5", + "@zxing/library": "^0.21.3", + "echarts": "^6.0.0", + "vue-echarts": "^8.0.1", + "axios": "1.15.0", + "less": "^4.3.0", + "pinia": "^3.0.2", + "tdesign-mobile-vue": "^1.16.0", + "timi-tdesign-mobile": "0.0.10", + "browser-image-compression": "^2.0.2", + "timi-web": "0.0.24", + "ts-node": "^10.9.2", + "vue": "^3.5.16", + "vue-router": "4.5.1", + "vue-virtual-scroller": "2.0.0-beta.8" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^24.2.0", + "@typescript-eslint/eslint-plugin": "^8.29.0", + "@typescript-eslint/parser": "^8.29.0", + "@vitejs/plugin-vue": "^5.2.4", + "@vue/compiler-sfc": "^3.5.16", + "@vue/eslint-config-typescript": "^14.5.0", + "@vue/tsconfig": "^0.7.0", + "eslint": "9.26.0", + "eslint-plugin-vue": "^9.33.0", + "typescript": "~5.8.3", + "unplugin-auto-import": "^19.1.1", + "unplugin-vue-components": "^28.4.1", + "vite": "^6.3.5", + "vue-eslint-parser": "^9.4.3", + "vue-tsc": "^2.2.12" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..05ff868 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4181 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@zxing/browser': + specifier: ^0.1.5 + version: 0.1.5(@zxing/library@0.21.3) + '@zxing/library': + specifier: ^0.21.3 + version: 0.21.3 + axios: + specifier: 1.15.0 + version: 1.15.0 + browser-image-compression: + specifier: ^2.0.2 + version: 2.0.2 + echarts: + specifier: ^6.0.0 + version: 6.1.0 + less: + specifier: ^4.3.0 + version: 4.8.0 + pinia: + specifier: ^3.0.2 + version: 3.0.4(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3)) + tdesign-mobile-vue: + specifier: ^1.16.0 + version: 1.16.0(vue@3.5.40(typescript@5.8.3)) + timi-tdesign-mobile: + specifier: 0.0.10 + version: 0.0.10(typescript@5.8.3) + timi-web: + specifier: 0.0.24 + version: 0.0.24(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3)) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@24.13.3)(typescript@5.8.3) + vue: + specifier: ^3.5.16 + version: 3.5.40(typescript@5.8.3) + vue-echarts: + specifier: ^8.0.1 + version: 8.0.1(echarts@6.1.0)(vue@3.5.40(typescript@5.8.3)) + vue-router: + specifier: 4.5.1 + version: 4.5.1(vue@3.5.40(typescript@5.8.3)) + vue-virtual-scroller: + specifier: 2.0.0-beta.8 + version: 2.0.0-beta.8(vue@3.5.40(typescript@5.8.3)) + devDependencies: + '@tsconfig/node20': + specifier: ^20.1.4 + version: 20.1.9 + '@types/node': + specifier: ^24.2.0 + version: 24.13.3 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.0 + version: 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.29.0 + version: 8.65.0(eslint@9.26.0)(typescript@5.8.3) + '@vitejs/plugin-vue': + specifier: ^5.2.4 + version: 5.2.4(vite@6.4.3(@types/node@24.13.3)(less@4.8.0)(terser@5.49.0))(vue@3.5.40(typescript@5.8.3)) + '@vue/compiler-sfc': + specifier: ^3.5.16 + version: 3.5.40 + '@vue/eslint-config-typescript': + specifier: ^14.5.0 + version: 14.9.0(eslint-plugin-vue@9.33.0(eslint@9.26.0))(eslint@9.26.0)(typescript@5.8.3) + '@vue/tsconfig': + specifier: ^0.7.0 + version: 0.7.0(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3)) + eslint: + specifier: 9.26.0 + version: 9.26.0 + eslint-plugin-vue: + specifier: ^9.33.0 + version: 9.33.0(eslint@9.26.0) + typescript: + specifier: ~5.8.3 + version: 5.8.3 + unplugin-auto-import: + specifier: ^19.1.1 + version: 19.3.0(@vueuse/core@10.7.0(vue@3.5.40(typescript@5.8.3))) + unplugin-vue-components: + specifier: ^28.4.1 + version: 28.8.0(@babel/parser@7.29.7)(vue@3.5.40(typescript@5.8.3)) + vite: + specifier: ^6.3.5 + version: 6.4.3(@types/node@24.13.3)(less@4.8.0)(terser@5.49.0) + vue-eslint-parser: + specifier: ^9.4.3 + version: 9.4.3(eslint@9.26.0) + vue-tsc: + specifier: ^2.2.12 + version: 2.2.12(typescript@5.8.3) + +packages: + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + 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.20.1': + resolution: {integrity: sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.2.3': + resolution: {integrity: sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.13.0': + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.6': + resolution: {integrity: sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.26.0': + resolution: {integrity: sha512-I9XlJawFdSMvWjDt6wksMCrgns5ggLNfFwFvnShsleWruvXM514Qxk8V246efTw+eo9JABvVz+u3q2RiAowKxQ==} + 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.2.8': + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@hono/node-server@1.19.15': + resolution: {integrity: sha512-Za2ai6TLdKjUvnur+eenO6nuYYipVAEhyCAdaV8IRvmU9kK8crOZUSYvIXn72E4f8fJqyAbpcJuTsYYmZp9Deg==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + 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'} + + '@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==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@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'} + + '@rollup/rollup-android-arm-eabi@4.62.3': + resolution: {integrity: sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.3': + resolution: {integrity: sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.3': + resolution: {integrity: sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.3': + resolution: {integrity: sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.3': + resolution: {integrity: sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.3': + resolution: {integrity: sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.3': + resolution: {integrity: sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.62.3': + resolution: {integrity: sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.62.3': + resolution: {integrity: sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.62.3': + resolution: {integrity: sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.62.3': + resolution: {integrity: sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.62.3': + resolution: {integrity: sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.62.3': + resolution: {integrity: sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.62.3': + resolution: {integrity: sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.62.3': + resolution: {integrity: sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.62.3': + resolution: {integrity: sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.62.3': + resolution: {integrity: sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.62.3': + resolution: {integrity: sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.62.3': + resolution: {integrity: sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.62.3': + resolution: {integrity: sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.3': + resolution: {integrity: sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.3': + resolution: {integrity: sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.3': + resolution: {integrity: sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.3': + resolution: {integrity: sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.3': + resolution: {integrity: sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==} + cpu: [x64] + os: [win32] + + '@tsconfig/node10@1.0.12': + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@tsconfig/node20@20.1.9': + resolution: {integrity: sha512-IjlTv1RsvnPtUcjTqtVsZExKVq+KQx4g5pCP5tI7rAs6Xesl2qFwSz/tPDBC4JajkL/MlezBu3gPUwqRHl+RIg==} + + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@24.13.3': + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} + + '@types/web-bluetooth@0.0.20': + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + + '@typescript-eslint/eslint-plugin@8.65.0': + resolution: {integrity: sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.65.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.65.0': + resolution: {integrity: sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.65.0': + resolution: {integrity: sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.65.0': + resolution: {integrity: sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.65.0': + resolution: {integrity: sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.65.0': + resolution: {integrity: sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.65.0': + resolution: {integrity: sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.65.0': + resolution: {integrity: sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.65.0': + resolution: {integrity: sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.65.0': + resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@use-gesture/core@10.3.1': + resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==} + + '@use-gesture/vanilla@10.3.1': + resolution: {integrity: sha512-lT4scGLu59ovA3zmtUonukAGcA0AdOOh+iwNDS05Bsu7Lq9aZToDHhI6D8Q2qvsVraovtsLLYwPrWdG/noMAKw==} + + '@vitejs/plugin-vue@5.2.4': + resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 + vue: ^3.2.25 + + '@volar/language-core@2.4.15': + resolution: {integrity: sha512-3VHw+QZU0ZG9IuQmzT68IyN4hZNd9GchGPhbD9+pa8CVv7rnoOZwo7T8weIbrRmihqy3ATpdfXFnqRrfPVK6CA==} + + '@volar/source-map@2.4.15': + resolution: {integrity: sha512-CPbMWlUN6hVZJYGcU/GSoHu4EnCHiLaXI9n8c9la6RaI9W5JHX+NqG+GSQcB0JdC2FIBLdZJwGsfKyBB71VlTg==} + + '@volar/typescript@2.4.15': + resolution: {integrity: sha512-2aZ8i0cqPGjXb4BhkMsPYDkkuc2ZQ6yOpqwAuNwUoncELqoy5fRgOQtLR9gB0g902iS0NAkvpIzs27geVyVdPg==} + + '@vue/compiler-core@3.5.40': + resolution: {integrity: sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==} + + '@vue/compiler-dom@3.5.40': + resolution: {integrity: sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==} + + '@vue/compiler-sfc@3.5.40': + resolution: {integrity: sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==} + + '@vue/compiler-ssr@3.5.40': + resolution: {integrity: sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==} + + '@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.10': + resolution: {integrity: sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA==} + + '@vue/devtools-kit@7.7.10': + resolution: {integrity: sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw==} + + '@vue/devtools-shared@7.7.10': + resolution: {integrity: sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ==} + + '@vue/eslint-config-typescript@14.9.0': + resolution: {integrity: sha512-E3j9hDlfVf10F30MRcLTPY2IIhWIx1nsvkVukk14kTcuA+oBVot9zsP1hzsO+PAMDxV3Fd9FimBJtUBNBL5KFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + eslint: ^9.10.0 || ^10.0.0 + eslint-plugin-vue: ^9.28.0 || ^10.0.0 + typescript: '>=4.8.4' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/language-core@2.2.12': + resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/reactivity@3.5.40': + resolution: {integrity: sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==} + + '@vue/runtime-core@3.5.40': + resolution: {integrity: sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==} + + '@vue/runtime-dom@3.5.40': + resolution: {integrity: sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==} + + '@vue/server-renderer@3.5.40': + resolution: {integrity: sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==} + + '@vue/shared@3.5.40': + resolution: {integrity: sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==} + + '@vue/tsconfig@0.7.0': + resolution: {integrity: sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==} + peerDependencies: + typescript: 5.x + vue: ^3.4.0 + peerDependenciesMeta: + typescript: + optional: true + vue: + optional: true + + '@vueuse/core@10.7.0': + resolution: {integrity: sha512-4EUDESCHtwu44ZWK3Gc/hZUVhVo/ysvdtwocB5vcauSV4B7NiGY5972WnsojB3vRNdxvAt7kzJWE2h9h7C9d5w==} + + '@vueuse/metadata@10.7.0': + resolution: {integrity: sha512-GlaH7tKP2iBCZ3bHNZ6b0cl9g0CJK8lttkBNUX156gWvNYhTKEtbweWLm9rxCPIiwzYcr/5xML6T8ZUEt+DkvA==} + + '@vueuse/shared@10.7.0': + resolution: {integrity: sha512-kc00uV6CiaTdc3i1CDC4a3lBxzaBE9AgYNtFN87B5OOscqeWElj/uza8qVDmk7/U8JbqoONLbtqiLJ5LGRuqlw==} + + '@zxing/browser@0.1.5': + resolution: {integrity: sha512-4Lmrn/il4+UNb87Gk8h1iWnhj39TASEHpd91CwwSJtY5u+wa0iH9qS0wNLAWbNVYXR66WmT5uiMhZ7oVTrKfxw==} + peerDependencies: + '@zxing/library': ^0.21.0 + + '@zxing/library@0.21.3': + resolution: {integrity: sha512-hZHqFe2JyH/ZxviJZosZjV+2s6EDSY0O24R+FQmlWZBZXP9IqMo7S3nb3+2LBWxodJQkSurdQGnqE7KXqrYgow==} + engines: {node: '>= 10.4.0'} + + '@zxing/text-encoding@0.9.0': + resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + alien-signals@1.0.13: + resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.15.0: + resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} + + axios@1.18.0: + resolution: {integrity: sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} + + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.16: + resolution: {integrity: sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==} + + brace-expansion@2.1.2: + resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} + + brace-expansion@5.0.8: + resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + engines: {node: 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browser-image-compression@2.0.2: + resolution: {integrity: sha512-pBLlQyUf6yB8SmmngrcOw3EoS4RpQ1BcylI3T9Yqn7+4nrQTXJD4sJDe5ODnJdrvNMaio5OicFo75rDyJD2Ucw==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.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==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + + copy-anything@4.0.5: + resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + engines: {node: '>=18'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dayjs@1.11.21: + resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + echarts@6.1.0: + resolution: {integrity: sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + 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'} + + eslint-plugin-vue@9.33.0: + resolution: {integrity: sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + 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-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.26.0: + resolution: {integrity: sha512-Hx0MOjPh6uK9oq9nVsATZKE/Wlbai7KFjfCuw9UHaguDW3x+HF0O5nIi3ud39TWgrTjTO5nHxmL3R1eANinWHQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + 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@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + 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@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'} + + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + express-rate-limit@8.6.0: + resolution: {integrity: sha512-XKJXDsASUOo0LLtFwW5hCcQGH0N4WQc/Rn8/Pvoia+TJFOkkFPvrtW9lZOeeNcxQJspvOIERMwiRLsVFlhHEkA==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + exsolve@1.1.0: + resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + 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-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + + 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 + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.3: + resolution: {integrity: sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==} + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + 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'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + hono@4.12.32: + resolution: {integrity: sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg==} + engines: {node: '>=16.9.0'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} + 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 + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.3.1: + resolution: {integrity: sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + is-what@5.5.0: + resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} + engines: {node: '>=18'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jose@6.2.4: + resolution: {integrity: sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + 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-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + less@4.5.1: + resolution: {integrity: sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==} + engines: {node: '>=14'} + hasBin: true + + less@4.8.0: + resolution: {integrity: sha512-7Y7DJBMbsW29UGjOG6NGvxQEx71AaDcrryBwYCMaFwn0kj8FkSueKN9r9WexVOetKEhXh38kL++WJncfkEpS+g==} + engines: {node: '>=18'} + hasBin: true + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + make-dir@5.1.0: + resolution: {integrity: sha512-IfpFq6UM39dUNiphpA6uDezNx/AvWyhwfICWPR3t1VspkgkMZrL+Rk1RbN1bx+aeNYwOrqGJgEgV3yotk+ZUVw==} + engines: {node: '>=18'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + marked-gfm-heading-id@4.1.4: + resolution: {integrity: sha512-CspnvVfHSkb/znqdPS4jUR8HtCjq3M/DnrsJCrfLBLvdrgbemmoINKpeWKQYkBiXAoBGejw0cV7xzqrPdup3WA==} + peerDependencies: + marked: '>=13 <19' + + marked-highlight@2.2.4: + resolution: {integrity: sha512-PZxisNMJDduSjc0q6uvjsnqqHCXc9s0eyzxDO9sB1eNGJnd/H1/Fu+z6g/liC1dfJdFW4SftMwMlLvsBhUPrqQ==} + peerDependencies: + marked: '>=4 <19' + + marked-mangle@1.1.13: + resolution: {integrity: sha512-phz1W/nYMr1T08Q7wqH2aj+PPiK85E69WQGfId+prvryfgjY/Idibx4YUvKaYMDV9rK1qo+/yC+Quu/3gdaBeA==} + peerDependencies: + marked: '>=4 <19' + + marked@17.0.6: + resolution: {integrity: sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==} + engines: {node: '>= 20'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + 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 + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + mitt@2.1.0: + resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==} + + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + needle@2.9.1: + resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + + needle@3.5.0: + resolution: {integrity: sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==} + engines: {node: '>= 4.4.x'} + hasBin: true + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + 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-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pinia@3.0.4: + resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==} + peerDependencies: + typescript: '>=4.5.0' + vue: ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + + postcss-selector-parser@6.1.4: + resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} + engines: {node: '>=4'} + + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + probe-image-size@7.3.0: + resolution: {integrity: sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + 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==} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + 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==} + + rollup@4.62.3: + resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + 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'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + 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.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + 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'} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + stream-parser@0.3.1: + resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} + + 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==} + + superjson@2.2.6: + resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==} + engines: {node: '>=16'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + tdesign-icons-vue-next@0.4.7: + resolution: {integrity: sha512-0TRVH0L9O7vAMQ7j2vU/VYBMzS5FI+OVf7bWjwAVMmWXArsAyJI8mzpNWThZok96B6hsRY+2hK/NSOFZy8hMqA==} + peerDependencies: + vue: ^3.0.0 + + tdesign-mobile-vue@1.16.0: + resolution: {integrity: sha512-Msn9PRrOkJD22hGFqSS3l0gvoaXTB2a5CTyvzazzPTITJmkY4CnC7ySbOsGxlA2qT/HyL44v+JJYauzUycQ1Fg==} + engines: {node: '>=12.0.0'} + peerDependencies: + vue: ^3.2.6 + + terser@5.49.0: + resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} + engines: {node: '>=10'} + hasBin: true + + timi-tdesign-mobile@0.0.10: + resolution: {integrity: sha512-fv83++YkMkeKTkReR/2+RoaSacj6fv5JHJfJ1P3C4p/KmLn9XTe+3jHYlFEWjQdxbehz9BifX1L8rVHmgScP5g==} + engines: {node: '>=16.0.0'} + + timi-web@0.0.24: + resolution: {integrity: sha512-qzcm72W9EE3BrYiUzc8a20J8xqxH17moEm/ovdijhRbIJtJUr81sslXFe2+OjNtx14meEIPJm3IfRooFzRswLg==} + engines: {node: '>=16.0.0'} + + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-custom-error@3.3.1: + resolution: {integrity: sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==} + engines: {node: '>=14.0.0'} + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + typescript-eslint@8.65.0: + resolution: {integrity: sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unimport@4.2.0: + resolution: {integrity: sha512-mYVtA0nmzrysnYnyb3ALMbByJ+Maosee2+WyE0puXl+Xm2bUwPorPaaeZt0ETfuroPOtG8jj1g/qeFZ6buFnag==} + engines: {node: '>=18.12.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unplugin-auto-import@19.3.0: + resolution: {integrity: sha512-iIi0u4Gq2uGkAOGqlPJOAMI8vocvjh1clGTfSK4SOrJKrt+tirrixo/FjgBwXQNNdS7ofcr7OxzmOb/RjWxeEQ==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': ^3.2.2 + '@vueuse/core': '*' + peerDependenciesMeta: + '@nuxt/kit': + optional: true + '@vueuse/core': + optional: true + + unplugin-utils@0.2.5: + resolution: {integrity: sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==} + engines: {node: '>=18.12.0'} + + unplugin-vue-components@28.8.0: + resolution: {integrity: sha512-2Q6ZongpoQzuXDK0ZsVzMoshH0MWZQ1pzVL538G7oIDKRTVzHjppBDS8aB99SADGHN3lpGU7frraCG6yWNoL5Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/parser': ^7.15.8 + '@nuxt/kit': ^3.2.2 || ^4.0.0 + vue: 2 || 3 + peerDependenciesMeta: + '@babel/parser': + optional: true + '@nuxt/kit': + optional: true + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uzip@0.20201231.0: + resolution: {integrity: sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng==} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} + engines: {node: '>= 0.10'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite@6.4.3: + resolution: {integrity: sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + 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 + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + 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.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-echarts@8.0.1: + resolution: {integrity: sha512-23rJTFLu1OUEGRWjJGmdGt8fP+8+ja1gVgzMYPIPaHWpXegcO1viIAaeu2H4QHESlVeHzUAHIxKXGrwjsyXAaA==} + peerDependencies: + echarts: ^6.0.0 + vue: ^3.3.0 + + vue-eslint-parser@10.4.1: + resolution: {integrity: sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + + vue-eslint-parser@9.4.3: + resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==} + engines: {node: ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '>=6.0.0' + + vue-observe-visibility@2.0.0-alpha.1: + resolution: {integrity: sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==} + peerDependencies: + vue: ^3.0.0 + + vue-resize@2.0.0-alpha.1: + resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} + peerDependencies: + vue: ^3.0.0 + + vue-router@4.5.0: + resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==} + peerDependencies: + vue: ^3.2.0 + + vue-router@4.5.1: + resolution: {integrity: sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==} + peerDependencies: + vue: ^3.2.0 + + vue-tsc@2.2.12: + resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + + vue-virtual-scroller@2.0.0-beta.8: + resolution: {integrity: sha512-b8/f5NQ5nIEBRTNi6GcPItE4s7kxNHw2AIHLtDp+2QvqdTjVN0FgONwX9cr53jWRgnu+HRLPaWDOR2JPI5MTfQ==} + peerDependencies: + vue: ^3.2.0 + + vue@3.5.40: + resolution: {integrity: sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zrender@6.1.0: + resolution: {integrity: sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==} + +snapshots: + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/runtime@7.29.7': {} + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-utils@4.10.1(eslint@9.26.0)': + dependencies: + eslint: 9.26.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.20.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.2.3': {} + + '@eslint/core@0.13.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.6': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.3.0 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.26.0': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.2.8': + dependencies: + '@eslint/core': 0.13.0 + levn: 0.4.1 + + '@hono/node-server@1.19.15(hono@4.12.32)': + dependencies: + hono: 4.12.32 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@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 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.15(hono@4.12.32) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.6.0(express@5.2.1) + hono: 4.12.32 + jose: 6.2.4 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@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 + + '@rollup/rollup-android-arm-eabi@4.62.3': + optional: true + + '@rollup/rollup-android-arm64@4.62.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.3': + optional: true + + '@rollup/rollup-darwin-x64@4.62.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.3': + optional: true + + '@tsconfig/node10@1.0.12': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@tsconfig/node20@20.1.9': {} + + '@types/esrecurse@4.3.1': {} + + '@types/estree@1.0.9': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@24.13.3': + dependencies: + undici-types: 7.18.2 + + '@types/web-bluetooth@0.0.20': {} + + '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/type-utils': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.65.0 + eslint: 9.26.0 + ignore: 7.0.6 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.65.0(eslint@9.26.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.65.0 + debug: 4.4.3 + eslint: 9.26.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.65.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.8.3) + '@typescript-eslint/types': 8.65.0 + debug: 4.4.3 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.65.0': + dependencies: + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/visitor-keys': 8.65.0 + + '@typescript-eslint/tsconfig-utils@8.65.0(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@typescript-eslint/type-utils@8.65.0(eslint@9.26.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + debug: 4.4.3 + eslint: 9.26.0 + ts-api-utils: 2.5.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.65.0': {} + + '@typescript-eslint/typescript-estree@8.65.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/project-service': 8.65.0(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.8.3) + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/visitor-keys': 8.65.0 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.65.0(eslint@9.26.0)(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.26.0) + '@typescript-eslint/scope-manager': 8.65.0 + '@typescript-eslint/types': 8.65.0 + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.8.3) + eslint: 9.26.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.65.0': + dependencies: + '@typescript-eslint/types': 8.65.0 + eslint-visitor-keys: 5.0.1 + + '@use-gesture/core@10.3.1': {} + + '@use-gesture/vanilla@10.3.1': + dependencies: + '@use-gesture/core': 10.3.1 + + '@vitejs/plugin-vue@5.2.4(vite@6.4.3(@types/node@24.13.3)(less@4.8.0)(terser@5.49.0))(vue@3.5.40(typescript@5.8.3))': + dependencies: + vite: 6.4.3(@types/node@24.13.3)(less@4.8.0)(terser@5.49.0) + vue: 3.5.40(typescript@5.8.3) + + '@volar/language-core@2.4.15': + dependencies: + '@volar/source-map': 2.4.15 + + '@volar/source-map@2.4.15': {} + + '@volar/typescript@2.4.15': + dependencies: + '@volar/language-core': 2.4.15 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/compiler-core@3.5.40': + dependencies: + '@babel/parser': 7.29.7 + '@vue/shared': 3.5.40 + entities: 7.0.1 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.40': + dependencies: + '@vue/compiler-core': 3.5.40 + '@vue/shared': 3.5.40 + + '@vue/compiler-sfc@3.5.40': + dependencies: + '@babel/parser': 7.29.7 + '@vue/compiler-core': 3.5.40 + '@vue/compiler-dom': 3.5.40 + '@vue/compiler-ssr': 3.5.40 + '@vue/shared': 3.5.40 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.23 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.40': + dependencies: + '@vue/compiler-dom': 3.5.40 + '@vue/shared': 3.5.40 + + '@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.10': + dependencies: + '@vue/devtools-kit': 7.7.10 + + '@vue/devtools-kit@7.7.10': + dependencies: + '@vue/devtools-shared': 7.7.10 + 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-shared@7.7.10': + dependencies: + rfdc: 1.4.1 + + '@vue/eslint-config-typescript@14.9.0(eslint-plugin-vue@9.33.0(eslint@9.26.0))(eslint@9.26.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/utils': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + eslint: 9.26.0 + eslint-plugin-vue: 9.33.0(eslint@9.26.0) + fast-glob: 3.3.3 + typescript-eslint: 8.65.0(eslint@9.26.0)(typescript@5.8.3) + vue-eslint-parser: 10.4.1(eslint@9.26.0) + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@vue/language-core@2.2.12(typescript@5.8.3)': + dependencies: + '@volar/language-core': 2.4.15 + '@vue/compiler-dom': 3.5.40 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.40 + alien-signals: 1.0.13 + minimatch: 9.0.9 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.8.3 + + '@vue/reactivity@3.5.40': + dependencies: + '@vue/shared': 3.5.40 + + '@vue/runtime-core@3.5.40': + dependencies: + '@vue/reactivity': 3.5.40 + '@vue/shared': 3.5.40 + + '@vue/runtime-dom@3.5.40': + dependencies: + '@vue/reactivity': 3.5.40 + '@vue/runtime-core': 3.5.40 + '@vue/shared': 3.5.40 + csstype: 3.2.3 + + '@vue/server-renderer@3.5.40': + dependencies: + '@vue/compiler-ssr': 3.5.40 + '@vue/runtime-dom': 3.5.40 + '@vue/shared': 3.5.40 + + '@vue/shared@3.5.40': {} + + '@vue/tsconfig@0.7.0(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3))': + optionalDependencies: + typescript: 5.8.3 + vue: 3.5.40(typescript@5.8.3) + + '@vueuse/core@10.7.0(vue@3.5.40(typescript@5.8.3))': + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.7.0 + '@vueuse/shared': 10.7.0(vue@3.5.40(typescript@5.8.3)) + vue-demi: 0.14.10(vue@3.5.40(typescript@5.8.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@vueuse/metadata@10.7.0': {} + + '@vueuse/shared@10.7.0(vue@3.5.40(typescript@5.8.3))': + dependencies: + vue-demi: 0.14.10(vue@3.5.40(typescript@5.8.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@zxing/browser@0.1.5(@zxing/library@0.21.3)': + dependencies: + '@zxing/library': 0.21.3 + optionalDependencies: + '@zxing/text-encoding': 0.9.0 + + '@zxing/library@0.21.3': + dependencies: + ts-custom-error: 3.3.1 + optionalDependencies: + '@zxing/text-encoding': 0.9.0 + + '@zxing/text-encoding@0.9.0': + optional: true + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn-walk@8.3.5: + dependencies: + acorn: 8.17.0 + + acorn@8.17.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@6.15.0: + 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.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.4 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + alien-signals@1.0.13: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + arg@4.1.3: {} + + argparse@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.15.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.6 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + + axios@1.18.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + binary-extensions@2.3.0: {} + + birpc@2.9.0: {} + + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + boolbase@1.0.0: {} + + brace-expansion@1.1.16: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.1.2: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.8: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browser-image-compression@2.0.2: + dependencies: + uzip: 0.20201231.0 + + buffer-from@1.1.2: {} + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.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 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + copy-anything@2.0.6: + dependencies: + is-what: 3.14.1 + + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + + copy-anything@4.0.5: + dependencies: + is-what: 5.5.0 + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + create-require@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cssesc@3.0.0: {} + + csstype@3.2.3: {} + + dayjs@1.11.21: {} + + de-indent@1.0.2: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + optional: true + + debug@3.2.7: + dependencies: + ms: 2.1.3 + optional: true + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + diff@4.0.4: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + echarts@6.1.0: + dependencies: + tslib: 2.3.0 + zrender: 6.1.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + entities@7.0.1: {} + + errno@0.1.8: + dependencies: + prr: 1.0.1 + optional: true + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + 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.4 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-plugin-vue@9.33.0(eslint@9.26.0): + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.26.0) + eslint: 9.26.0 + globals: 13.24.0 + natural-compare: 1.4.0 + nth-check: 2.1.1 + postcss-selector-parser: 6.1.4 + semver: 7.8.5 + vue-eslint-parser: 9.4.3(eslint@9.26.0) + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - supports-color + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-scope@9.1.2: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.26.0: + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.26.0) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.20.1 + '@eslint/config-helpers': 0.2.3 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.6 + '@eslint/js': 9.26.0 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + ajv: 6.15.0 + 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.7.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.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 4.2.1 + + espree@11.2.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 5.0.1 + + espree@9.6.1: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + + express-rate-limit@8.6.0(express@5.2.1): + dependencies: + debug: 4.4.3 + express: 5.2.1 + ip-address: 10.3.1 + transitivePeerDependencies: + - supports-color + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.3 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + exsolve@1.1.0: {} + + fast-deep-equal@3.1.3: {} + + 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-uri@3.1.4: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.3 + keyv: 4.5.4 + + flatted@3.4.3: {} + + follow-redirects@1.16.0: {} + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + github-slugger@2.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globals@14.0.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: + optional: true + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hono@4.12.32: {} + + hookable@5.5.3: {} + + 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 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + optional: true + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + optional: true + + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + ignore@7.0.6: {} + + image-size@0.5.5: + optional: true + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + ip-address@10.3.1: {} + + ipaddr.js@1.9.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-promise@4.0.0: {} + + is-what@3.14.1: {} + + is-what@4.1.16: {} + + is-what@5.5.0: {} + + isexe@2.0.0: {} + + jose@6.2.4: {} + + js-tokens@9.0.1: {} + + js-yaml@4.3.0: + dependencies: + argparse: 2.0.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + 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.5.0 + source-map: 0.6.1 + + less@4.8.0: + dependencies: + copy-anything: 3.0.5 + parse-node-version: 1.0.1 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + make-dir: 5.1.0 + mime: 1.6.0 + needle: 3.5.0 + probe-image-size: 7.3.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash-es@4.18.1: {} + + lodash.merge@4.6.2: {} + + lodash@4.18.1: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-dir@2.1.0: + dependencies: + pify: 4.0.1 + semver: 5.7.2 + optional: true + + make-dir@5.1.0: + optional: true + + make-error@1.3.6: {} + + marked-gfm-heading-id@4.1.4(marked@17.0.6): + dependencies: + github-slugger: 2.0.0 + marked: 17.0.6 + + marked-highlight@2.2.4(marked@17.0.6): + dependencies: + marked: 17.0.6 + + marked-mangle@1.1.13(marked@17.0.6): + dependencies: + marked: 17.0.6 + + marked@17.0.6: {} + + math-intrinsics@1.1.0: {} + + media-typer@1.1.1: {} + + merge-descriptors@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + 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 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.8 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.16 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.2 + + mitt@2.1.0: {} + + mitt@3.0.1: {} + + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + ms@2.0.0: + optional: true + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + nanoid@3.3.16: {} + + natural-compare@1.4.0: {} + + needle@2.9.1: + dependencies: + debug: 3.2.7 + iconv-lite: 0.4.24 + sax: 1.6.1 + transitivePeerDependencies: + - supports-color + optional: true + + needle@3.5.0: + dependencies: + iconv-lite: 0.6.3 + sax: 1.6.1 + optional: true + + negotiator@1.0.0: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + 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 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-node-version@1.0.1: {} + + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-to-regexp@8.4.2: {} + + pathe@2.0.3: {} + + perfect-debounce@1.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.5: {} + + pify@4.0.1: + optional: true + + pinia@3.0.4(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3)): + dependencies: + '@vue/devtools-api': 7.7.10 + vue: 3.5.40(typescript@5.8.3) + optionalDependencies: + typescript: 5.8.3 + + pkce-challenge@5.0.1: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.1.0 + pathe: 2.0.3 + + postcss-selector-parser@6.1.4: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss@8.5.23: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prismjs@1.30.0: {} + + probe-image-size@7.3.0: + dependencies: + lodash.merge: 4.6.2 + needle: 2.9.1 + stream-parser: 0.3.1 + transitivePeerDependencies: + - supports-color + optional: true + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + proxy-from-env@2.1.0: {} + + prr@1.0.1: + optional: true + + punycode@2.3.1: {} + + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + + quansync@0.2.11: {} + + queue-microtask@1.2.3: {} + + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.2 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rollup@4.62.3: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.3 + '@rollup/rollup-android-arm64': 4.62.3 + '@rollup/rollup-darwin-arm64': 4.62.3 + '@rollup/rollup-darwin-x64': 4.62.3 + '@rollup/rollup-freebsd-arm64': 4.62.3 + '@rollup/rollup-freebsd-x64': 4.62.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.3 + '@rollup/rollup-linux-arm-musleabihf': 4.62.3 + '@rollup/rollup-linux-arm64-gnu': 4.62.3 + '@rollup/rollup-linux-arm64-musl': 4.62.3 + '@rollup/rollup-linux-loong64-gnu': 4.62.3 + '@rollup/rollup-linux-loong64-musl': 4.62.3 + '@rollup/rollup-linux-ppc64-gnu': 4.62.3 + '@rollup/rollup-linux-ppc64-musl': 4.62.3 + '@rollup/rollup-linux-riscv64-gnu': 4.62.3 + '@rollup/rollup-linux-riscv64-musl': 4.62.3 + '@rollup/rollup-linux-s390x-gnu': 4.62.3 + '@rollup/rollup-linux-x64-gnu': 4.62.3 + '@rollup/rollup-linux-x64-musl': 4.62.3 + '@rollup/rollup-openbsd-x64': 4.62.3 + '@rollup/rollup-openharmony-arm64': 4.62.3 + '@rollup/rollup-win32-arm64-msvc': 4.62.3 + '@rollup/rollup-win32-ia32-msvc': 4.62.3 + '@rollup/rollup-win32-x64-gnu': 4.62.3 + '@rollup/rollup-win32-x64-msvc': 4.62.3 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safer-buffer@2.1.2: {} + + sax@1.6.1: + optional: true + + scule@1.3.0: {} + + semver@5.7.2: + optional: true + + semver@7.8.5: {} + + 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.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + 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 + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + 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.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + 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: {} + + speakingurl@14.0.1: {} + + statuses@2.0.2: {} + + stream-parser@0.3.1: + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + optional: true + + strip-json-comments@3.1.1: {} + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + superjson@2.2.6: + dependencies: + copy-anything: 4.0.5 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + tdesign-icons-vue-next@0.4.7(vue@3.5.40(typescript@5.8.3)): + dependencies: + '@babel/runtime': 7.29.7 + vue: 3.5.40(typescript@5.8.3) + + tdesign-mobile-vue@1.16.0(vue@3.5.40(typescript@5.8.3)): + dependencies: + '@babel/runtime': 7.29.7 + '@use-gesture/vanilla': 10.3.1 + '@vueuse/core': 10.7.0(vue@3.5.40(typescript@5.8.3)) + dayjs: 1.11.21 + lodash-es: 4.18.1 + tdesign-icons-vue-next: 0.4.7(vue@3.5.40(typescript@5.8.3)) + tinycolor2: 1.6.0 + validator: 13.15.35 + vue: 3.5.40(typescript@5.8.3) + transitivePeerDependencies: + - '@vue/composition-api' + + terser@5.49.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.17.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + timi-tdesign-mobile@0.0.10(typescript@5.8.3): + dependencies: + vue: 3.5.40(typescript@5.8.3) + vue-router: 4.5.0(vue@3.5.40(typescript@5.8.3)) + transitivePeerDependencies: + - typescript + + timi-web@0.0.24(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3)): + dependencies: + axios: 1.18.0 + less: 4.5.1 + marked: 17.0.6 + marked-gfm-heading-id: 4.1.4(marked@17.0.6) + marked-highlight: 2.2.4(marked@17.0.6) + marked-mangle: 1.1.13(marked@17.0.6) + pinia: 3.0.4(typescript@5.8.3)(vue@3.5.40(typescript@5.8.3)) + prismjs: 1.30.0 + terser: 5.49.0 + transitivePeerDependencies: + - debug + - supports-color + - typescript + - vue + + tinycolor2@1.6.0: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + ts-api-utils@2.5.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + + ts-custom-error@3.3.1: {} + + ts-node@10.9.2(@types/node@24.13.3)(typescript@5.8.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.12 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 24.13.3 + acorn: 8.17.0 + acorn-walk: 8.3.5 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.4 + make-error: 1.3.6 + typescript: 5.8.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tslib@2.3.0: {} + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-fest@0.20.2: {} + + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.1 + mime-types: 3.0.2 + + typescript-eslint@8.65.0(eslint@9.26.0)(typescript@5.8.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.65.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.65.0(eslint@9.26.0)(typescript@5.8.3) + eslint: 9.26.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + typescript@5.8.3: {} + + ufo@1.6.4: {} + + undici-types@7.18.2: {} + + unimport@4.2.0: + dependencies: + acorn: 8.17.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + pathe: 2.0.3 + picomatch: 4.0.5 + pkg-types: 2.3.1 + scule: 1.3.0 + strip-literal: 3.1.0 + tinyglobby: 0.2.17 + unplugin: 2.3.11 + unplugin-utils: 0.2.5 + + unpipe@1.0.0: {} + + unplugin-auto-import@19.3.0(@vueuse/core@10.7.0(vue@3.5.40(typescript@5.8.3))): + dependencies: + local-pkg: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.5 + unimport: 4.2.0 + unplugin: 2.3.11 + unplugin-utils: 0.2.5 + optionalDependencies: + '@vueuse/core': 10.7.0(vue@3.5.40(typescript@5.8.3)) + + unplugin-utils@0.2.5: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.5 + + unplugin-vue-components@28.8.0(@babel/parser@7.29.7)(vue@3.5.40(typescript@5.8.3)): + dependencies: + chokidar: 3.6.0 + debug: 4.4.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + tinyglobby: 0.2.17 + unplugin: 2.3.11 + unplugin-utils: 0.2.5 + vue: 3.5.40(typescript@5.8.3) + optionalDependencies: + '@babel/parser': 7.29.7 + transitivePeerDependencies: + - supports-color + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.17.0 + picomatch: 4.0.5 + webpack-virtual-modules: 0.6.2 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + uzip@0.20201231.0: {} + + v8-compile-cache-lib@3.0.1: {} + + validator@13.15.35: {} + + vary@1.1.2: {} + + vite@6.4.3(@types/node@24.13.3)(less@4.8.0)(terser@5.49.0): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + postcss: 8.5.23 + rollup: 4.62.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.3 + fsevents: 2.3.3 + less: 4.8.0 + terser: 5.49.0 + + vscode-uri@3.1.0: {} + + vue-demi@0.14.10(vue@3.5.40(typescript@5.8.3)): + dependencies: + vue: 3.5.40(typescript@5.8.3) + + vue-echarts@8.0.1(echarts@6.1.0)(vue@3.5.40(typescript@5.8.3)): + dependencies: + echarts: 6.1.0 + vue: 3.5.40(typescript@5.8.3) + + vue-eslint-parser@10.4.1(eslint@9.26.0): + dependencies: + debug: 4.4.3 + eslint: 9.26.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + vue-eslint-parser@9.4.3(eslint@9.26.0): + dependencies: + debug: 4.4.3 + eslint: 9.26.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.7.0 + lodash: 4.18.1 + semver: 7.8.5 + transitivePeerDependencies: + - supports-color + + vue-observe-visibility@2.0.0-alpha.1(vue@3.5.40(typescript@5.8.3)): + dependencies: + vue: 3.5.40(typescript@5.8.3) + + vue-resize@2.0.0-alpha.1(vue@3.5.40(typescript@5.8.3)): + dependencies: + vue: 3.5.40(typescript@5.8.3) + + vue-router@4.5.0(vue@3.5.40(typescript@5.8.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.40(typescript@5.8.3) + + vue-router@4.5.1(vue@3.5.40(typescript@5.8.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.40(typescript@5.8.3) + + vue-tsc@2.2.12(typescript@5.8.3): + dependencies: + '@volar/typescript': 2.4.15 + '@vue/language-core': 2.2.12(typescript@5.8.3) + typescript: 5.8.3 + + vue-virtual-scroller@2.0.0-beta.8(vue@3.5.40(typescript@5.8.3)): + dependencies: + mitt: 2.1.0 + vue: 3.5.40(typescript@5.8.3) + vue-observe-visibility: 2.0.0-alpha.1(vue@3.5.40(typescript@5.8.3)) + vue-resize: 2.0.0-alpha.1(vue@3.5.40(typescript@5.8.3)) + + vue@3.5.40(typescript@5.8.3): + dependencies: + '@vue/compiler-dom': 3.5.40 + '@vue/compiler-sfc': 3.5.40 + '@vue/runtime-dom': 3.5.40 + '@vue/server-renderer': 3.5.40 + '@vue/shared': 3.5.40 + optionalDependencies: + typescript: 5.8.3 + + webpack-virtual-modules@0.6.2: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + xml-name-validator@4.0.0: {} + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + + zrender@6.1.0: + dependencies: + tslib: 2.3.0 diff --git a/public/icons/icon-192.png b/public/icons/icon-192.png new file mode 100644 index 0000000..76ecc99 Binary files /dev/null and b/public/icons/icon-192.png differ diff --git a/public/icons/icon-512.png b/public/icons/icon-512.png new file mode 100644 index 0000000..0ee7cce Binary files /dev/null and b/public/icons/icon-512.png differ diff --git a/public/icons/icon-maskable-512.png b/public/icons/icon-maskable-512.png new file mode 100644 index 0000000..ed07f1c Binary files /dev/null and b/public/icons/icon-maskable-512.png differ diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest new file mode 100644 index 0000000..16cdf94 --- /dev/null +++ b/public/manifest.webmanifest @@ -0,0 +1,27 @@ +{ + "name": "Gao Customer H5", + "short_name": "Gao H5", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#ffffff", + "start_url": "/", + "scope": "/", + "icons": [ + { + "src": "/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "/icons/icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/src/Root.vue b/src/Root.vue new file mode 100644 index 0000000..92f3bdf --- /dev/null +++ b/src/Root.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/api/CustomerAPI.ts b/src/api/CustomerAPI.ts new file mode 100644 index 0000000..88b77d8 --- /dev/null +++ b/src/api/CustomerAPI.ts @@ -0,0 +1,107 @@ +import { axios, type Page, type PageResult } from "timi-web"; +import type { Customer, CustomerDailyStatView, CustomerGenderStatView, CustomerInviteUpdateReq, CustomerSearchReq, CustomerTrendStatReq, QuickRegisterReq } from "@/types/Customer"; +import type { RegistrationEventRecord } from "@/types/RegistrationEventRecord"; + +const BASE_URI = "/gao/customer"; + +async function list(req: Page): Promise> { + return await axios.post(`${BASE_URI}/list`, req); +} + +async function search(req: CustomerSearchReq): Promise { + return await axios.post(`${BASE_URI}/search`, req); +} + +async function searchPage(req: Page): Promise> { + return await axios.post(`${BASE_URI}/search/page`, req); +} + +async function exportExcel(req: CustomerSearchReq): Promise { + return await axios.post(`${BASE_URI}/export`, req, { + responseType: "blob" + }); +} + +async function detail(id: string): Promise { + return await axios.post(`${BASE_URI}/detail`, undefined, { + params: { id } + }); +} + +async function detailByCode(code: string): Promise { + return await axios.post(`${BASE_URI}/detail/code`, undefined, { + params: { code } + }); +} + +async function nullableDetailByCode(code: string): Promise { + return await axios.post(`${BASE_URI}/detail/code/nullable`, undefined, { + params: { code } + }); +} + +async function invitedList(introducerCustomerId: string): Promise { + return await axios.post(`${BASE_URI}/invited/list`, undefined, { + params: { introducerCustomerId } + }); +} + +async function create(req: Customer): Promise { + return await axios.post(`${BASE_URI}/create`, req); +} + +async function quickRegister(req: QuickRegisterReq): Promise { + return await axios.post(`${BASE_URI}/quick/register`, req); +} + +async function update(req: Customer): Promise { + return await axios.post(`${BASE_URI}/update`, req); +} + +async function remove(id: string): Promise { + return await axios.post(`${BASE_URI}/delete`, undefined, { + params: { id } + }); +} + +async function createInvite(req: CustomerInviteUpdateReq): Promise { + return await axios.post(`${BASE_URI}/invite/create`, req); +} + +async function updateInvite(req: CustomerInviteUpdateReq): Promise { + return await axios.post(`${BASE_URI}/invite/update`, req); +} + +async function deleteInvite(customerId: string): Promise { + return await axios.post(`${BASE_URI}/invite/delete`, undefined, { + params: { customerId } + }); +} + +async function dailyStat(req: CustomerTrendStatReq): Promise { + return await axios.post(`${BASE_URI}/stat/daily`, req); +} + +async function genderStat(): Promise { + return await axios.post(`${BASE_URI}/stat/gender`); +} + +export default { + list, + search, + searchPage, + exportExcel, + detail, + detailByCode, + nullableDetailByCode, + invitedList, + create, + quickRegister, + update, + remove, + createInvite, + updateInvite, + deleteInvite, + dailyStat, + genderStat +}; diff --git a/src/api/GaoUserAPI.ts b/src/api/GaoUserAPI.ts new file mode 100644 index 0000000..21733bc --- /dev/null +++ b/src/api/GaoUserAPI.ts @@ -0,0 +1,41 @@ +import { axios, type Page, type PageResult, type Role } from "timi-web"; +import type { GaoUser } from "@/types/GaoUser"; + +const BASE_URI = "/gao/user"; + +async function list(req: Page): Promise> { + return await axios.post(`${BASE_URI}/list`, req); +} + +async function detail(id: string): Promise { + return await axios.post(`${BASE_URI}/detail`, undefined, { + params: { id } + }); +} + +async function create(req: GaoUser): Promise { + return await axios.post(`${BASE_URI}/create`, req); +} + +async function update(req: GaoUser): Promise { + return await axios.post(`${BASE_URI}/update`, req); +} + +async function remove(id: string): Promise { + return await axios.post(`${BASE_URI}/delete`, undefined, { + params: { id } + }); +} + +async function roleList(): Promise { + return await axios.post(`${BASE_URI}/role/list`); +} + +export default { + list, + detail, + create, + update, + remove, + roleList +}; diff --git a/src/api/RegistrationEventAPI.ts b/src/api/RegistrationEventAPI.ts new file mode 100644 index 0000000..c75f2ad --- /dev/null +++ b/src/api/RegistrationEventAPI.ts @@ -0,0 +1,41 @@ +import { axios, type Page, type PageResult } from "timi-web"; +import type { RegistrationEvent } from "@/types/RegistrationEvent"; + +const BASE_URI = "/gao/registration-event"; + +async function list(req: Page): Promise> { + return await axios.post(`${BASE_URI}/list`, req); +} + +async function enabledList(): Promise { + return await axios.post(`${BASE_URI}/enabled/list`); +} + +async function detail(id: string): Promise { + return await axios.post(`${BASE_URI}/detail`, undefined, { + params: { id } + }); +} + +async function create(req: RegistrationEvent): Promise { + return await axios.post(`${BASE_URI}/create`, req); +} + +async function update(req: RegistrationEvent): Promise { + return await axios.post(`${BASE_URI}/update`, req); +} + +async function remove(id: string): Promise { + return await axios.post(`${BASE_URI}/delete`, undefined, { + params: { id } + }); +} + +export default { + list, + enabledList, + detail, + create, + update, + remove +}; diff --git a/src/api/RegistrationEventRecordAPI.ts b/src/api/RegistrationEventRecordAPI.ts new file mode 100644 index 0000000..190d4a9 --- /dev/null +++ b/src/api/RegistrationEventRecordAPI.ts @@ -0,0 +1,88 @@ +import { axios, type Page, type PageResult } from "timi-web"; +import type { + CustomerRegisterStatView, + RegistrationEventRecordCalendarView, + RegistrationEventRecord, + RegistrationEventRecordCreateReq, + RegistrationEventRecordDailyStatView, + RegistrationEventRecordListItemView, + RegistrationEventRecordRangeReq, + RegistrationEventRecordStatReq, + RegistrationEventRecordTrendStatReq +} from "@/types/RegistrationEventRecord"; + +const BASE_URI = "/gao/registration-event-record"; + +async function list(req: Page): Promise> { + return await axios.post(`${BASE_URI}/list`, req); +} + +async function detail(id: string): Promise { + return await axios.post(`${BASE_URI}/detail`, undefined, { + params: { id } + }); +} + +async function rangeList(req: RegistrationEventRecordRangeReq): Promise { + return await axios.post(`${BASE_URI}/range/list`, req); +} + +async function calendarRangeList(req: RegistrationEventRecordRangeReq): Promise { + return await axios.post(`${BASE_URI}/range/calendar/list`, req); +} + +async function rangePage(req: Page): Promise> { + return await axios.post(`${BASE_URI}/range/page`, req); +} + +async function rangeExport(req: RegistrationEventRecordRangeReq): Promise { + return await axios.post(`${BASE_URI}/range/export`, req, { + responseType: "blob" + }); +} + +async function create(req: RegistrationEventRecordCreateReq): Promise { + return await axios.post(`${BASE_URI}/create`, req); +} + +async function update(req: RegistrationEventRecord): Promise { + await axios.post(`${BASE_URI}/update`, req); +} + +async function remove(id: string): Promise { + await axios.post(`${BASE_URI}/delete`, undefined, { + params: { id } + }); +} + +async function customerRangeStat(req: RegistrationEventRecordStatReq): Promise { + return await axios.post(`${BASE_URI}/customer/range/stat`, req); +} + +async function allCustomerRangeStat(req: RegistrationEventRecordStatReq): Promise { + return await axios.post(`${BASE_URI}/all-customer/range/stat`, req); +} + +async function customerRegistrationEventDailyStat(req: RegistrationEventRecordTrendStatReq): Promise { + return await axios.post(`${BASE_URI}/customer/registration-event/daily/stat`, req); +} + +async function allCustomerRegistrationEventDailyStat(req: RegistrationEventRecordTrendStatReq): Promise { + return await axios.post(`${BASE_URI}/all-customer/registration-event/daily/stat`, req); +} + +export default { + list, + detail, + rangeList, + calendarRangeList, + rangePage, + rangeExport, + create, + update, + remove, + customerRangeStat, + allCustomerRangeStat, + customerRegistrationEventDailyStat, + allCustomerRegistrationEventDailyStat +}; diff --git a/src/assets/sound/registration-success.mp3 b/src/assets/sound/registration-success.mp3 new file mode 100644 index 0000000..1d8167c Binary files /dev/null and b/src/assets/sound/registration-success.mp3 differ diff --git a/src/assets/sound/scan-success.mp3 b/src/assets/sound/scan-success.mp3 new file mode 100644 index 0000000..6aaf001 Binary files /dev/null and b/src/assets/sound/scan-success.mp3 differ diff --git a/src/components/BodyAreaSelector.vue b/src/components/BodyAreaSelector.vue new file mode 100644 index 0000000..f1224ab --- /dev/null +++ b/src/components/BodyAreaSelector.vue @@ -0,0 +1,313 @@ + + + + + diff --git a/src/components/CodeScanner.vue b/src/components/CodeScanner.vue new file mode 100644 index 0000000..b7063e1 --- /dev/null +++ b/src/components/CodeScanner.vue @@ -0,0 +1,529 @@ + + + + + diff --git a/src/components/CustomerProfileCard.vue b/src/components/CustomerProfileCard.vue new file mode 100644 index 0000000..ec729fd --- /dev/null +++ b/src/components/CustomerProfileCard.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/src/components/CustomerSelector.vue b/src/components/CustomerSelector.vue new file mode 100644 index 0000000..165f008 --- /dev/null +++ b/src/components/CustomerSelector.vue @@ -0,0 +1,288 @@ + + + + + diff --git a/src/components/GenderIcon.vue b/src/components/GenderIcon.vue new file mode 100644 index 0000000..5f3f213 --- /dev/null +++ b/src/components/GenderIcon.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/components/PageTransition.vue b/src/components/PageTransition.vue new file mode 100644 index 0000000..2a5d93b --- /dev/null +++ b/src/components/PageTransition.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/src/components/PhotoField.vue b/src/components/PhotoField.vue new file mode 100644 index 0000000..af7a6fe --- /dev/null +++ b/src/components/PhotoField.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/src/components/PhotoScroller.vue b/src/components/PhotoScroller.vue new file mode 100644 index 0000000..fabe38a --- /dev/null +++ b/src/components/PhotoScroller.vue @@ -0,0 +1,206 @@ + + + + + diff --git a/src/components/RegistrationEventRecordCalendar.vue b/src/components/RegistrationEventRecordCalendar.vue new file mode 100644 index 0000000..9af4e88 --- /dev/null +++ b/src/components/RegistrationEventRecordCalendar.vue @@ -0,0 +1,425 @@ + + + + + diff --git a/src/components/RegistrationEventSelector.vue b/src/components/RegistrationEventSelector.vue new file mode 100644 index 0000000..13d6aaf --- /dev/null +++ b/src/components/RegistrationEventSelector.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/components/SegmentedSlider.vue b/src/components/SegmentedSlider.vue new file mode 100644 index 0000000..e8701ca --- /dev/null +++ b/src/components/SegmentedSlider.vue @@ -0,0 +1,186 @@ + + + + + diff --git a/src/layout/MainLayout.vue b/src/layout/MainLayout.vue new file mode 100644 index 0000000..2a67630 --- /dev/null +++ b/src/layout/MainLayout.vue @@ -0,0 +1,251 @@ + + + + + diff --git a/src/layout/RootLayout.vue b/src/layout/RootLayout.vue new file mode 100644 index 0000000..dd020cb --- /dev/null +++ b/src/layout/RootLayout.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..eb7ba86 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,77 @@ +import {createApp} from "vue"; +import {createPinia} from "pinia"; +import router from "@/router"; +import Root from "@/Root.vue"; + +import "tdesign-mobile-vue/es/style/index.css"; +import "timi-web/style.css"; +import "timi-tdesign-mobile/style.css"; +import "vue-virtual-scroller/dist/vue-virtual-scroller.css"; +import "@/styles/tdesign-custom.css"; +import "@/styles/global.less"; +import {configureUserStore, type ApiResponse, Network, useUserStore, VCan, VRole} from "timi-web"; +import {Toast} from "tdesign-mobile-vue"; + +export const pinia = createPinia(); +const apiBaseURL = import.meta.env.VITE_API_BASE_URL as string | undefined; + +if (apiBaseURL) { + Network.axios.defaults.baseURL = apiBaseURL; +} + +configureUserStore({ + storageKey: "gao-customer-h5:user" +}); + +Network.setGlobalRequestInterceptor((config: any) => { + const userStore = useUserStore(pinia); + if (apiBaseURL && !config.baseURL) { + config.baseURL = apiBaseURL; + } + + config.headers.set({ + "Accept-Language": "zh-CN" + }); + + if (userStore.token) { + config.headers.set({ + "Token": userStore.token + }); + } + return config; +}); +async function bootstrap(): Promise { + const app = createApp(Root); + app.use(pinia); + app.directive("can", VCan); + app.directive("role", VRole); + + const userStore = useUserStore(pinia); + await userStore.loginByStorage(); + + Network.setGlobalErrorCallback((resp: ApiResponse) => { + Toast({ + theme: "error", + direction: "row", + message: resp.message + }); + }); + + app.use(router); + app.mount("#root"); +} + +async function start(): Promise { + try { + await bootstrap(); + } catch (error) { + console.error(error); + Toast({ + theme: "error", + direction: "row", + message: "应用启动失败" + }); + } +} + +void start(); diff --git a/src/pages/Login.vue b/src/pages/Login.vue new file mode 100644 index 0000000..653d66a --- /dev/null +++ b/src/pages/Login.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/src/pages/customer/QuickEntryPage.vue b/src/pages/customer/QuickEntryPage.vue new file mode 100644 index 0000000..8127b0a --- /dev/null +++ b/src/pages/customer/QuickEntryPage.vue @@ -0,0 +1,576 @@ + + + + + diff --git a/src/pages/customer/QuickSignInPage.vue b/src/pages/customer/QuickSignInPage.vue new file mode 100644 index 0000000..7c38886 --- /dev/null +++ b/src/pages/customer/QuickSignInPage.vue @@ -0,0 +1,445 @@ + + + + + diff --git a/src/pages/management/CustomerDataCharts.vue b/src/pages/management/CustomerDataCharts.vue new file mode 100644 index 0000000..94ac4bf --- /dev/null +++ b/src/pages/management/CustomerDataCharts.vue @@ -0,0 +1,670 @@ + + + + + diff --git a/src/pages/management/CustomerDetail.vue b/src/pages/management/CustomerDetail.vue new file mode 100644 index 0000000..d3f643d --- /dev/null +++ b/src/pages/management/CustomerDetail.vue @@ -0,0 +1,564 @@ + + + + + diff --git a/src/pages/management/CustomerEdit.vue b/src/pages/management/CustomerEdit.vue new file mode 100644 index 0000000..7789398 --- /dev/null +++ b/src/pages/management/CustomerEdit.vue @@ -0,0 +1,541 @@ + + + + + diff --git a/src/pages/management/CustomerList.vue b/src/pages/management/CustomerList.vue new file mode 100644 index 0000000..e6b12b1 --- /dev/null +++ b/src/pages/management/CustomerList.vue @@ -0,0 +1,374 @@ + + + + + diff --git a/src/pages/management/ManagementDataCharts.vue b/src/pages/management/ManagementDataCharts.vue new file mode 100644 index 0000000..1d6d006 --- /dev/null +++ b/src/pages/management/ManagementDataCharts.vue @@ -0,0 +1,521 @@ + + + + + diff --git a/src/pages/management/ManagementPassword.vue b/src/pages/management/ManagementPassword.vue new file mode 100644 index 0000000..a004f49 --- /dev/null +++ b/src/pages/management/ManagementPassword.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/pages/management/ManagementProfile.vue b/src/pages/management/ManagementProfile.vue new file mode 100644 index 0000000..25112a1 --- /dev/null +++ b/src/pages/management/ManagementProfile.vue @@ -0,0 +1,279 @@ + + + + + diff --git a/src/pages/management/ManagementQrCode.vue b/src/pages/management/ManagementQrCode.vue new file mode 100644 index 0000000..a492ca8 --- /dev/null +++ b/src/pages/management/ManagementQrCode.vue @@ -0,0 +1,360 @@ + + + + + diff --git a/src/pages/management/ManagementSettings.vue b/src/pages/management/ManagementSettings.vue new file mode 100644 index 0000000..668e651 --- /dev/null +++ b/src/pages/management/ManagementSettings.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/src/pages/management/PermissionEdit.vue b/src/pages/management/PermissionEdit.vue new file mode 100644 index 0000000..3d1cece --- /dev/null +++ b/src/pages/management/PermissionEdit.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/src/pages/management/PermissionList.vue b/src/pages/management/PermissionList.vue new file mode 100644 index 0000000..7154015 --- /dev/null +++ b/src/pages/management/PermissionList.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/src/pages/management/PermissionSettings.vue b/src/pages/management/PermissionSettings.vue new file mode 100644 index 0000000..386a0d6 --- /dev/null +++ b/src/pages/management/PermissionSettings.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/src/pages/management/RegistrationEventEdit.vue b/src/pages/management/RegistrationEventEdit.vue new file mode 100644 index 0000000..c434964 --- /dev/null +++ b/src/pages/management/RegistrationEventEdit.vue @@ -0,0 +1,314 @@ + + + + + diff --git a/src/pages/management/RegistrationEventList.vue b/src/pages/management/RegistrationEventList.vue new file mode 100644 index 0000000..4cce3fd --- /dev/null +++ b/src/pages/management/RegistrationEventList.vue @@ -0,0 +1,297 @@ + + + + + diff --git a/src/pages/management/RegistrationEventRecordDetail.vue b/src/pages/management/RegistrationEventRecordDetail.vue new file mode 100644 index 0000000..98dac8a --- /dev/null +++ b/src/pages/management/RegistrationEventRecordDetail.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/pages/management/RegistrationEventRecordEdit.vue b/src/pages/management/RegistrationEventRecordEdit.vue new file mode 100644 index 0000000..459a796 --- /dev/null +++ b/src/pages/management/RegistrationEventRecordEdit.vue @@ -0,0 +1,630 @@ + + + + + diff --git a/src/pages/management/RegistrationEventRecordList.vue b/src/pages/management/RegistrationEventRecordList.vue new file mode 100644 index 0000000..3d8eff9 --- /dev/null +++ b/src/pages/management/RegistrationEventRecordList.vue @@ -0,0 +1,629 @@ + + + + + diff --git a/src/pages/management/RoleEdit.vue b/src/pages/management/RoleEdit.vue new file mode 100644 index 0000000..ba12d44 --- /dev/null +++ b/src/pages/management/RoleEdit.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/src/pages/management/RoleList.vue b/src/pages/management/RoleList.vue new file mode 100644 index 0000000..f554e64 --- /dev/null +++ b/src/pages/management/RoleList.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/pages/management/RolePermissionAssign.vue b/src/pages/management/RolePermissionAssign.vue new file mode 100644 index 0000000..ddffb83 --- /dev/null +++ b/src/pages/management/RolePermissionAssign.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/src/pages/management/UserDetail.vue b/src/pages/management/UserDetail.vue new file mode 100644 index 0000000..0bb6395 --- /dev/null +++ b/src/pages/management/UserDetail.vue @@ -0,0 +1,240 @@ + + + + + diff --git a/src/pages/management/UserEdit.vue b/src/pages/management/UserEdit.vue new file mode 100644 index 0000000..13e3443 --- /dev/null +++ b/src/pages/management/UserEdit.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/src/pages/management/UserList.vue b/src/pages/management/UserList.vue new file mode 100644 index 0000000..b2fab42 --- /dev/null +++ b/src/pages/management/UserList.vue @@ -0,0 +1,195 @@ + + + + + diff --git a/src/pages/management/UserRoleAssign.vue b/src/pages/management/UserRoleAssign.vue new file mode 100644 index 0000000..c8b4dc4 --- /dev/null +++ b/src/pages/management/UserRoleAssign.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/src/pages/tabs/CustomerTab.vue b/src/pages/tabs/CustomerTab.vue new file mode 100644 index 0000000..d172a39 --- /dev/null +++ b/src/pages/tabs/CustomerTab.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/src/pages/tabs/ManagementTab.vue b/src/pages/tabs/ManagementTab.vue new file mode 100644 index 0000000..f6e123d --- /dev/null +++ b/src/pages/tabs/ManagementTab.vue @@ -0,0 +1,233 @@ + + + + + diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..356b533 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,108 @@ +import { createRouter, createWebHistory } from "vue-router"; +import RootLayout from "@/layout/RootLayout.vue"; +import MainLayout from "@/layout/MainLayout.vue"; +import Login from "@/pages/Login.vue"; +import chartRoutes from "@/router/routes/chartRoutes"; +import customerRoutes from "@/router/routes/customerRoutes"; +import { managementAccountRoutes, managementSettingRoutes } from "@/router/routes/managementRoutes"; +import permissionRoutes from "@/router/routes/permissionRoutes"; +import registrationRoutes from "@/router/routes/registrationRoutes"; +import tabRoutes from "@/router/routes/tabRoutes"; +import userRoutes from "@/router/routes/userRoutes"; +import { useGlobalUIStore } from "@/store/globalUI"; +import { useUserStore } from "timi-web"; + +const detailRoutes = [ + ...customerRoutes, + ...userRoutes, + ...registrationRoutes, + ...managementSettingRoutes, + ...permissionRoutes, + ...chartRoutes, + ...managementAccountRoutes +]; + +const router = createRouter({ + history: createWebHistory("/"), + scrollBehavior(_to, _from, savedPosition) { + if (savedPosition) { + return savedPosition; + } + + return { + left: 0, + top: 0 + }; + }, + routes: [ + { + path: "/", + component: RootLayout, + children: [ + { + path: "", + redirect: "/customers" + }, + { + path: "login", + name: "Login", + component: Login, + meta: { + depth: 1, + navBarVisible: false, + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "", + component: MainLayout, + meta: { + depth: 1, + navBarVisible: false, + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + }, + children: [ + ...tabRoutes, + ...detailRoutes + ] + } + ] + }, + { + path: "/:pathMatch(.*)*", + redirect: "/customers" + } + ] +}); + +router.beforeEach((to) => { + const userStore = useUserStore(); + if (to.path === "/login") { + return userStore.isLogged() ? "/management" : true; + } + + if (!userStore.isLogged()) { + return { + path: "/login", + query: { + redirect: to.fullPath + } + }; + } + + return true; +}); + +router.afterEach((to) => { + const globalUIStore = useGlobalUIStore(); + const isDarkMode = globalUIStore.themeMode === "dark"; + const fallbackBackground = isDarkMode ? "#10161f" : "#F5F5F8"; + const targetBackground = isDarkMode ? to.meta.darkBodyBackground : to.meta.bodyBackground; + globalUIStore.setBodyBackground(typeof targetBackground === "string" ? targetBackground : fallbackBackground); +}); + +export default router; diff --git a/src/router/routes/chartRoutes.ts b/src/router/routes/chartRoutes.ts new file mode 100644 index 0000000..2c4ee56 --- /dev/null +++ b/src/router/routes/chartRoutes.ts @@ -0,0 +1,48 @@ +import type { RouteRecordRaw } from "vue-router"; + +const chartRoutes: RouteRecordRaw[] = [ + { + path: "/management/data-charts", + name: "ManagementDataCharts", + component: () => import("@/pages/management/ManagementDataCharts.vue"), + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "全局数据图表", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/customer-data-charts", + name: "CustomerDataCharts", + component: () => import("@/pages/management/CustomerDataCharts.vue"), + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "客户数据图表", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/customers/:id/data-charts", + name: "CustomerDataChartsFromCustomer", + component: () => import("@/pages/management/CustomerDataCharts.vue"), + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "客户数据图表", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export default chartRoutes; diff --git a/src/router/routes/customerRoutes.ts b/src/router/routes/customerRoutes.ts new file mode 100644 index 0000000..e5313fb --- /dev/null +++ b/src/router/routes/customerRoutes.ts @@ -0,0 +1,110 @@ +import type { RouteRecordRaw } from "vue-router"; +import QuickEntryPage from "@/pages/customer/QuickEntryPage.vue"; +import QuickSignInPage from "@/pages/customer/QuickSignInPage.vue"; +import RegistrationEventRecordEdit from "@/pages/management/RegistrationEventRecordEdit.vue"; +import CustomerList from "@/pages/management/CustomerList.vue"; +import CustomerDetail from "@/pages/management/CustomerDetail.vue"; +import CustomerEdit from "@/pages/management/CustomerEdit.vue"; + +const customerRoutes: RouteRecordRaw[] = [ + { + path: "/customer/quick-entry", + name: "QuickEntryPage", + component: QuickEntryPage, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "快速补录登记", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/customer/quick-sign-in", + name: "QuickSignInPage", + component: QuickSignInPage, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "快速扫码登记", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/customer/registration", + name: "CustomerRegistrationEventRecordCreate", + component: RegistrationEventRecordEdit, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "登记", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/customers", + name: "CustomerList", + component: CustomerList, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "客户管理", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/customers/create", + name: "CustomerCreate", + component: CustomerEdit, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "新增客户", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/customers/:id", + name: "CustomerDetail", + component: CustomerDetail, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "客户详情", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/customers/:id/edit", + name: "CustomerEdit", + component: CustomerEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "编辑客户", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export default customerRoutes; diff --git a/src/router/routes/managementRoutes.ts b/src/router/routes/managementRoutes.ts new file mode 100644 index 0000000..56cd7f9 --- /dev/null +++ b/src/router/routes/managementRoutes.ts @@ -0,0 +1,74 @@ +import type { RouteRecordRaw } from "vue-router"; +import ManagementSettings from "@/pages/management/ManagementSettings.vue"; +import ManagementProfile from "@/pages/management/ManagementProfile.vue"; +import ManagementPassword from "@/pages/management/ManagementPassword.vue"; +import ManagementQrCode from "@/pages/management/ManagementQrCode.vue"; + +export const managementSettingRoutes: RouteRecordRaw[] = [ + { + path: "/management/settings", + name: "ManagementSettings", + component: ManagementSettings, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "应用设置", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export const managementAccountRoutes: RouteRecordRaw[] = [ + { + path: "/management/profile", + name: "ManagementProfile", + component: ManagementProfile, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "当前用户", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/profile/password", + name: "ManagementPassword", + component: ManagementPassword, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "修改密码", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/qr-code", + name: "ManagementQrCode", + component: ManagementQrCode, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "生成二维码", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +const managementRoutes: RouteRecordRaw[] = [ + ...managementSettingRoutes, + ...managementAccountRoutes +]; + +export default managementRoutes; diff --git a/src/router/routes/permissionRoutes.ts b/src/router/routes/permissionRoutes.ts new file mode 100644 index 0000000..78c9aed --- /dev/null +++ b/src/router/routes/permissionRoutes.ts @@ -0,0 +1,139 @@ +import type { RouteRecordRaw } from "vue-router"; +import PermissionSettings from "@/pages/management/PermissionSettings.vue"; +import RoleList from "@/pages/management/RoleList.vue"; +import RoleEdit from "@/pages/management/RoleEdit.vue"; +import PermissionList from "@/pages/management/PermissionList.vue"; +import PermissionEdit from "@/pages/management/PermissionEdit.vue"; +import RolePermissionAssign from "@/pages/management/RolePermissionAssign.vue"; +import UserRoleAssign from "@/pages/management/UserRoleAssign.vue"; + +const permissionRoutes: RouteRecordRaw[] = [ + { + path: "/management/permissions", + name: "PermissionSettings", + component: PermissionSettings, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "权限设置", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/roles", + name: "RoleList", + component: RoleList, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "角色管理", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/roles/create", + name: "RoleCreate", + component: RoleEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "新增角色", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/roles/:id", + name: "RoleEdit", + component: RoleEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "编辑角色", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/items", + name: "PermissionList", + component: PermissionList, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "权限管理", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/items/create", + name: "PermissionCreate", + component: PermissionEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "新增权限", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/items/:id", + name: "PermissionEdit", + component: PermissionEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "编辑权限", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/assign", + name: "RolePermissionAssign", + component: RolePermissionAssign, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "角色授权权限", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/permissions/user-roles", + name: "UserRoleAssign", + component: UserRoleAssign, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "用户授权角色", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export default permissionRoutes; diff --git a/src/router/routes/registrationRoutes.ts b/src/router/routes/registrationRoutes.ts new file mode 100644 index 0000000..94bd9c1 --- /dev/null +++ b/src/router/routes/registrationRoutes.ts @@ -0,0 +1,109 @@ +import type { RouteRecordRaw } from "vue-router"; +import RegistrationEventEdit from "@/pages/management/RegistrationEventEdit.vue"; +import RegistrationEventList from "@/pages/management/RegistrationEventList.vue"; +import RegistrationEventRecordDetail from "@/pages/management/RegistrationEventRecordDetail.vue"; +import RegistrationEventRecordEdit from "@/pages/management/RegistrationEventRecordEdit.vue"; +import RegistrationEventRecordList from "@/pages/management/RegistrationEventRecordList.vue"; + +const registrationRoutes: RouteRecordRaw[] = [ + { + path: "/management/registration-events", + name: "RegistrationEventList", + component: RegistrationEventList, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "登记事件管理", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/registration-events/create", + name: "RegistrationEventCreate", + component: RegistrationEventEdit, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "新增登记事件", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/registration-events/:id/edit", + name: "RegistrationEventEdit", + component: RegistrationEventEdit, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "编辑登记事件", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/registration-event-records", + name: "RegistrationEventRecordList", + component: RegistrationEventRecordList, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "登记事件记录管理", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/registration-event-records/create", + name: "RegistrationEventRecordCreate", + component: RegistrationEventRecordEdit, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "新增登记事件记录", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/registration-event-records/:id", + name: "RegistrationEventRecordDetail", + component: RegistrationEventRecordDetail, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "登记事件记录详情", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/registration-event-records/:id/edit", + name: "RegistrationEventRecordEdit", + component: RegistrationEventRecordEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "编辑登记事件记录", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export default registrationRoutes; diff --git a/src/router/routes/tabRoutes.ts b/src/router/routes/tabRoutes.ts new file mode 100644 index 0000000..7981e89 --- /dev/null +++ b/src/router/routes/tabRoutes.ts @@ -0,0 +1,36 @@ +import type { RouteRecordRaw } from "vue-router"; +import CustomerTab from "@/pages/tabs/CustomerTab.vue"; +import ManagementTab from "@/pages/tabs/ManagementTab.vue"; + +const tabRoutes: RouteRecordRaw[] = [ + { + path: "/customers", + name: "CustomerTab", + component: CustomerTab, + meta: { + depth: 2, + navBarVisible: true, + navBarCanBack: false, + navBarTitle: "客户", + tabBarVisible: true, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management", + name: "ManagementTab", + component: ManagementTab, + meta: { + depth: 2, + navBarVisible: true, + navBarCanBack: false, + navBarTitle: "管理", + tabBarVisible: true, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export default tabRoutes; diff --git a/src/router/routes/userRoutes.ts b/src/router/routes/userRoutes.ts new file mode 100644 index 0000000..ac2c916 --- /dev/null +++ b/src/router/routes/userRoutes.ts @@ -0,0 +1,80 @@ +import type { RouteRecordRaw } from "vue-router"; +import UserList from "@/pages/management/UserList.vue"; +import UserDetail from "@/pages/management/UserDetail.vue"; +import UserEdit from "@/pages/management/UserEdit.vue"; +import UserRoleAssign from "@/pages/management/UserRoleAssign.vue"; + +const userRoutes: RouteRecordRaw[] = [ + { + path: "/management/users", + name: "UserList", + component: UserList, + meta: { + depth: 3, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "用户管理", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/users/create", + name: "UserCreatePage", + component: UserEdit, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "新增用户", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/users/:id", + name: "UserDetail", + component: UserDetail, + meta: { + depth: 4, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "用户详情", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/users/:id/edit", + name: "UserEdit", + component: UserEdit, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "编辑用户", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + }, + { + path: "/management/users/:id/roles", + name: "UserRoleAssignFromUser", + component: UserRoleAssign, + meta: { + depth: 5, + navBarVisible: true, + navBarCanBack: true, + navBarTitle: "配置角色", + tabBarVisible: false, + bodyBackground: "#F5F5F8", + darkBodyBackground: "#10161f" + } + } +]; + +export default userRoutes; diff --git a/src/store/globalUI.ts b/src/store/globalUI.ts new file mode 100644 index 0000000..3867558 --- /dev/null +++ b/src/store/globalUI.ts @@ -0,0 +1,41 @@ +import type { Pinia } from "pinia"; +import { defineStore } from "pinia"; + +export const DEFAULT_BODY_BACKGROUND = "#FFF"; +const THEME_STORAGE_KEY = "gao-customer-h5:theme-mode"; + +export type ThemeMode = "light" | "dark" | "system"; + +function readStoredThemeMode(): ThemeMode { + const rawValue = localStorage.getItem(THEME_STORAGE_KEY); + if (rawValue === "light" || rawValue === "dark" || rawValue === "system") { + return rawValue; + } + + return "system"; +} + +const store = defineStore("globalUI", () => { + const bodyBackground = ref(DEFAULT_BODY_BACKGROUND); + const themeMode = ref(readStoredThemeMode()); + + function setBodyBackground(color?: string): void { + bodyBackground.value = color || DEFAULT_BODY_BACKGROUND; + } + + function setThemeMode(mode: ThemeMode): void { + themeMode.value = mode; + localStorage.setItem(THEME_STORAGE_KEY, mode); + } + + return { + bodyBackground, + themeMode, + setBodyBackground, + setThemeMode + }; +}); + +export function useGlobalUIStore(pinia?: Pinia) { + return store(pinia); +} diff --git a/src/store/navBarStore.ts b/src/store/navBarStore.ts new file mode 100644 index 0000000..2047c8d --- /dev/null +++ b/src/store/navBarStore.ts @@ -0,0 +1,96 @@ +export const useNavBarStore = defineStore("nav-bar", () => { + const route = useRoute(); + const router = useRouter(); + + const height = ref(0); + const title = ref(""); + const backTo = ref(); + const rightIcon = ref(""); + const rightText = ref(""); + const rightTextColor = ref(""); + const rightAction = shallowRef<(() => void | Promise) | undefined>(); + const customTitleVisible = ref(false); + const customRightVisible = ref(false); + + const isShowing = computed(() => !!router.currentRoute.value.meta.navBarVisible); + const canBack = computed(() => !!router.currentRoute.value.meta.navBarCanBack); + + watch( + () => route.meta.navBarTitle, + (value) => { + title.value = typeof value === "string" ? value : ""; + }, + { immediate: true } + ); + + function setHeight(value: number): void { + height.value = value; + } + + function setBackTo(value?: string): void { + backTo.value = value; + } + + function setRightIcon(value?: string, action?: () => void | Promise): void { + rightIcon.value = value || ""; + rightAction.value = action; + if (value) { + rightText.value = ""; + rightTextColor.value = ""; + customRightVisible.value = false; + } + } + + function setRightText(value?: string, color?: string, action?: () => void | Promise): void { + rightText.value = value || ""; + rightTextColor.value = color || ""; + rightAction.value = action; + if (value) { + rightIcon.value = ""; + customRightVisible.value = false; + } + } + + function setCustomTitleVisible(value: boolean): void { + customTitleVisible.value = value; + } + + function setCustomRightVisible(value: boolean): void { + customRightVisible.value = value; + if (value) { + rightIcon.value = ""; + rightText.value = ""; + rightTextColor.value = ""; + rightAction.value = undefined; + } + } + + function clearRight(): void { + rightIcon.value = ""; + rightText.value = ""; + rightTextColor.value = ""; + rightAction.value = undefined; + customRightVisible.value = false; + } + + return { + height, + title, + backTo, + rightIcon, + rightText, + rightTextColor, + rightAction, + customTitleVisible, + customRightVisible, + isShowing, + canBack, + setHeight, + setBackTo, + setRightIcon, + setRightText, + setCustomTitleVisible, + setCustomRightVisible, + clearRight + }; +}); diff --git a/src/store/permissionSettingsStore.ts b/src/store/permissionSettingsStore.ts new file mode 100644 index 0000000..5c625d4 --- /dev/null +++ b/src/store/permissionSettingsStore.ts @@ -0,0 +1,339 @@ +import { defineStore } from "pinia"; +import { + OrderType, + PermissionAPI, + RoleAPI, + type ModuleCode, + type Permission as UserPermission, + type PermissionPayload, + type Role as UserRole, + type RolePayload +} from "timi-web"; + +export const gaoModuleCode: ModuleCode = "GAO"; +const pageSize = 1000; + +export type Permission = UserPermission; +export type Role = UserRole & { + permissionIdList: string[]; + childRoleIdList: string[]; +}; + +export type RoleDraft = { + id?: string; + code: string; + name: string; + description: string; + nameLangId?: string; + moduleCode?: ModuleCode; + permissionIdList: string[]; + childRoleIdList: string[]; +}; +export type PermissionDraft = { + id?: string; + code: string; + name: string; + description: string; + nameLangId?: string; + moduleCode?: ModuleCode; +}; + +function normalizeRole(role: UserRole): Role { + return { + ...role, + moduleCode: role.moduleCode || gaoModuleCode, + description: role.description || "", + permissionIdList: role.permissionIdList || role.permissionList?.map(item => item.id) || [], + childRoleIdList: role.childRoleIdList || role.childRoleList?.map(item => item.id) || [] + }; +} + +function createEmptyRole(): Role { + return { + id: "", + moduleCode: gaoModuleCode, + code: "", + name: "", + description: "", + permissionIdList: [], + childRoleIdList: [] + }; +} + +function createEmptyPermission(): Permission { + return { + id: "", + moduleCode: gaoModuleCode, + code: "", + name: "", + description: "" + }; +} + +export const usePermissionSettingsStore = defineStore("permission-settings", () => { + const roleList = ref([]); + const permissionList = ref([]); + const loading = ref(false); + const loaded = ref(false); + let loadTask: Promise | null = null; + + const roleTree = computed>(() => { + const childIdSet = new Set(roleList.value.flatMap(item => item.childRoleIdList)); + const roots = roleList.value.filter(item => !childIdSet.has(item.id)); + return roots.flatMap(item => buildRoleTree(item.id, 0, new Set())); + }); + + // ---------- 基础数据 ---------- + + async function loadAll(force = false): Promise { + if (loaded.value && !force) { + return; + } + + if (loadTask && !force) { + await loadTask; + return; + } + + loading.value = true; + loadTask = (async () => { + const [roleResult, permissionResult] = await Promise.all([ + RoleAPI.list({ + index: 0, + size: pageSize, + equalsExample: { + moduleCode: gaoModuleCode + }, + orderMap: { + code: OrderType.ASC + } + }), + PermissionAPI.list({ + index: 0, + size: pageSize, + equalsExample: { + moduleCode: gaoModuleCode + }, + orderMap: { + code: OrderType.ASC + } + }) + ]); + roleList.value = roleResult.list.map(normalizeRole); + permissionList.value = permissionResult.list; + loaded.value = true; + })(); + + try { + await loadTask; + } finally { + loadTask = null; + loading.value = false; + } + } + + async function loadRoleDetail(id: string): Promise { + if (!id) { + return createEmptyRole(); + } + + const role = normalizeRole(await RoleAPI.detail(id)); + upsertLocalRole(role); + return role; + } + + async function loadPermissionDetail(id: string): Promise { + if (!id) { + return createEmptyPermission(); + } + + const permission = permissionList.value.find(item => item.id === id); + if (!permission) { + throw new Error("权限不存在"); + } + upsertLocalPermission(permission); + return permission; + } + + function upsertLocalRole(role: Role): void { + const index = roleList.value.findIndex(item => item.id === role.id); + if (-1 < index) { + roleList.value.splice(index, 1, role); + return; + } + roleList.value.unshift(role); + } + + function upsertLocalPermission(permission: Permission): void { + const index = permissionList.value.findIndex(item => item.id === permission.id); + if (-1 < index) { + permissionList.value.splice(index, 1, permission); + return; + } + permissionList.value.unshift(permission); + } + + // ---------- 查询 ---------- + + function buildRoleTree(roleId: string, level: number, visitedRoleIds: Set): Array { + const current = getRoleById(roleId); + if (!current || visitedRoleIds.has(roleId)) { + return []; + } + + const nextVisitedRoleIds = new Set(visitedRoleIds); + nextVisitedRoleIds.add(roleId); + + return [{ + ...current, + level + }, ...current.childRoleIdList.flatMap(childRoleId => buildRoleTree(childRoleId, level + 1, nextVisitedRoleIds))]; + } + + function getRoleById(id: string): Role | undefined { + return roleList.value.find(item => item.id === id); + } + + function getPermissionById(id: string): Permission | undefined { + return permissionList.value.find(item => item.id === id); + } + + function getChildRoles(role: Role): Role[] { + return role.childRoleIdList.map(getRoleById).filter(Boolean) as Role[]; + } + + function getRolePermissionList(role: Role): Permission[] { + return role.permissionIdList.map(getPermissionById).filter(Boolean) as Permission[]; + } + + function getInheritedPermissionList(role: Role): Permission[] { + const permissionMap = new Map(); + const allPermissionList = role.allPermissionList || []; + for (const permission of [...getRolePermissionList(role), ...allPermissionList]) { + permissionMap.set(permission.id, permission); + } + + for (const childRole of getChildRoles(role)) { + for (const permission of getRolePermissionList(childRole)) { + permissionMap.set(permission.id, permission); + } + } + + return Array.from(permissionMap.values()); + } + + // ---------- 写入 ---------- + + async function upsertRole(draft: RoleDraft, createMode: boolean): Promise { + const current = getRoleById(draft.id || ""); + const payload: RolePayload = { + ...draft, + moduleCode: gaoModuleCode, + code: draft.code.trim(), + nameLangId: current?.nameLangId, + name: draft.name.trim(), + description: draft.description.trim(), + permissionIdList: [...draft.permissionIdList], + childRoleIdList: [...draft.childRoleIdList] + }; + + if (createMode) { + await RoleAPI.create({ + moduleCode: payload.moduleCode, + code: payload.code, + name: payload.name, + description: payload.description, + permissionIdList: payload.permissionIdList, + childRoleIdList: payload.childRoleIdList + }); + await loadAll(true); + return undefined; + } + + await RoleAPI.update(payload); + const role = await loadRoleDetail(payload.id || ""); + await loadAll(true); + return role; + } + + async function removeRole(id: string): Promise { + await RoleAPI.remove(id); + roleList.value = roleList.value + .filter(item => item.id !== id) + .map(item => ({ + ...item, + childRoleIdList: item.childRoleIdList.filter(childId => childId !== id) + })); + } + + async function upsertPermission(draft: PermissionDraft, createMode: boolean): Promise { + const current = getPermissionById(draft.id || ""); + const payload: PermissionPayload = { + ...draft, + moduleCode: gaoModuleCode, + code: draft.code.trim(), + nameLangId: current?.nameLangId, + name: draft.name.trim(), + description: draft.description.trim() + }; + + if (createMode) { + await PermissionAPI.create({ + moduleCode: payload.moduleCode, + code: payload.code, + name: payload.name, + description: payload.description + }); + await loadAll(true); + return undefined; + } + + await PermissionAPI.update(payload); + const permission = await loadPermissionDetail(payload.id || ""); + await loadAll(true); + return permission; + } + + async function removePermission(id: string): Promise { + await PermissionAPI.remove(id); + permissionList.value = permissionList.value.filter(item => item.id !== id); + roleList.value = roleList.value.map(item => ({ + ...item, + permissionIdList: item.permissionIdList.filter(permissionId => permissionId !== id) + })); + } + + async function setRolePermissionList(roleId: string, permissionIds: string[]): Promise { + const role = await loadRoleDetail(roleId); + await upsertRole({ + id: role.id, + moduleCode: gaoModuleCode, + code: role.code, + name: role.name || "", + description: role.description || "", + permissionIdList: [...permissionIds], + childRoleIdList: [...role.childRoleIdList] + }, false); + } + + return { + roleList, + permissionList, + roleTree, + loading, + loaded, + loadAll, + loadRoleDetail, + loadPermissionDetail, + getRoleById, + getPermissionById, + getChildRoles, + getRolePermissionList, + getInheritedPermissionList, + upsertRole, + removeRole, + upsertPermission, + removePermission, + setRolePermissionList + }; +}); diff --git a/src/store/settingStore.ts b/src/store/settingStore.ts new file mode 100644 index 0000000..3a060cb --- /dev/null +++ b/src/store/settingStore.ts @@ -0,0 +1,232 @@ +import scanSuccessSoundUrl from "@/assets/sound/scan-success.mp3"; +import registrationSuccessSoundUrl from "@/assets/sound/registration-success.mp3"; + +export interface SoundSetting { + scanSuccess: boolean; + registerSuccess: boolean; + volume: number; +} + +type SoundType = "scanSuccess" | "registerSuccess"; + +const SOUND_STORAGE_KEY = "gao-customer-h5:sound"; +const soundUrlMap: Record = { + scanSuccess: scanSuccessSoundUrl, + registerSuccess: registrationSuccessSoundUrl +}; +// Windows 某些设备链路对极短提示音的起音处理不稳定,直接播放会偏小。 +// 这里先补一段极低音量的预热头,把输出链路“叫醒”后再接原音效。 +const SCAN_SUCCESS_WARMUP_HEAD_MS = 120; +const SCAN_SUCCESS_WARMUP_GAIN = .08; + +function createDefaultSoundSetting(): SoundSetting { + return { + scanSuccess: true, + registerSuccess: true, + volume: 70 + }; +} + +function readStoredSoundSetting(): SoundSetting { + const rawValue = localStorage.getItem(SOUND_STORAGE_KEY); + if (!rawValue) { + return createDefaultSoundSetting(); + } + + try { + const parsedValue = JSON.parse(rawValue) as Partial; + const volume = Number(parsedValue.volume); + return { + scanSuccess: parsedValue.scanSuccess !== false, + registerSuccess: parsedValue.registerSuccess !== false, + volume: Number.isFinite(volume) ? Math.min(100, Math.max(0, volume)) : 70 + }; + } catch { + return createDefaultSoundSetting(); + } +} + +export const useSettingStore = defineStore("setting", () => { + const sound = ref(readStoredSoundSetting()); + const soundPlayerMap = shallowRef | null>(null); + const audioContext = shallowRef(null); + const scanSuccessBuffer = shallowRef(null); + const activeScanSuccessSource = shallowRef(null); + const soundUnlocked = ref(false); + + function setSound(value: Partial): void { + sound.value = { + scanSuccess: value.scanSuccess ?? sound.value.scanSuccess, + registerSuccess: value.registerSuccess ?? sound.value.registerSuccess, + volume: Math.min(100, Math.max(0, value.volume ?? sound.value.volume)) + }; + localStorage.setItem(SOUND_STORAGE_KEY, JSON.stringify(sound.value)); + applySoundVolume(); + } + + function loadSoundPlayers(): void { + if (soundPlayerMap.value) { + return; + } + + soundPlayerMap.value = { + scanSuccess: createSoundPlayer(soundUrlMap.scanSuccess), + registerSuccess: createSoundPlayer(soundUrlMap.registerSuccess) + }; + applySoundVolume(); + } + + function getAudioContext(): AudioContext { + if (audioContext.value) { + return audioContext.value; + } + + audioContext.value = new window.AudioContext(); + return audioContext.value; + } + + function createSoundPlayer(url: string): HTMLAudioElement { + const player = new Audio(url); + player.preload = "auto"; + player.load(); + return player; + } + + function applySoundVolume(): void { + if (!soundPlayerMap.value) { + return; + } + + const volume = sound.value.volume / 100; + Object.values(soundPlayerMap.value).forEach((player) => { + player.volume = volume; + }); + } + + async function unlockSoundPlayers(): Promise { + loadSoundPlayers(); + if (soundUnlocked.value || !soundPlayerMap.value) { + return soundUnlocked.value; + } + + try { + await getAudioContext().resume(); + for (const player of Object.values(soundPlayerMap.value)) { + player.muted = true; + player.volume = 0; + player.currentTime = 0; + await player.play(); + player.pause(); + player.currentTime = 0; + player.muted = false; + } + applySoundVolume(); + soundUnlocked.value = true; + return true; + } catch { + Object.values(soundPlayerMap.value).forEach((player) => { + player.muted = false; + }); + applySoundVolume(); + return false; + } + } + + async function loadScanSuccessBuffer(): Promise { + if (scanSuccessBuffer.value) { + return scanSuccessBuffer.value; + } + + const response = await fetch(soundUrlMap.scanSuccess); + const arrayBuffer = await response.arrayBuffer(); + scanSuccessBuffer.value = await getAudioContext().decodeAudioData(arrayBuffer.slice(0)); + return scanSuccessBuffer.value; + } + + async function playScanSuccessBufferSound(): Promise { + const context = getAudioContext(); + if (context.state === "suspended") { + await context.resume(); + } + + activeScanSuccessSource.value?.stop(); + activeScanSuccessSource.value?.disconnect(); + + const source = context.createBufferSource(); + const gainNode = context.createGain(); + source.buffer = await buildScanSuccessPlaybackBuffer(); + gainNode.gain.value = sound.value.volume / 100; + source.connect(gainNode); + gainNode.connect(context.destination); + source.onended = () => { + if (activeScanSuccessSource.value === source) { + activeScanSuccessSource.value = null; + } + source.disconnect(); + gainNode.disconnect(); + }; + activeScanSuccessSource.value = source; + source.start(0); + } + + async function buildScanSuccessPlaybackBuffer(): Promise { + const sourceBuffer = await loadScanSuccessBuffer(); + const context = getAudioContext(); + const warmupFrameCount = Math.max(1, Math.round(context.sampleRate * SCAN_SUCCESS_WARMUP_HEAD_MS / 1000)); + const outputBuffer = context.createBuffer( + sourceBuffer.numberOfChannels, + sourceBuffer.length + warmupFrameCount, + sourceBuffer.sampleRate + ); + + for (let channelIndex = 0; channelIndex < sourceBuffer.numberOfChannels; channelIndex += 1) { + const outputData = outputBuffer.getChannelData(channelIndex); + const sourceData = sourceBuffer.getChannelData(channelIndex); + const warmupSourceLength = Math.min(sourceData.length, warmupFrameCount); + // 预热头不能是纯静音;纯静音对这类 Windows 问题无效。 + for (let frameIndex = 0; frameIndex < warmupFrameCount; frameIndex += 1) { + const sourceIndex = frameIndex % warmupSourceLength; + outputData[frameIndex] = sourceData[sourceIndex] * SCAN_SUCCESS_WARMUP_GAIN; + } + outputData.set(sourceData, warmupFrameCount); + } + + return outputBuffer; + } + + async function playSound(type: SoundType): Promise { + if (type === "scanSuccess") { + await playScanSuccessBufferSound(); + return; + } + + loadSoundPlayers(); + if (!sound.value[type] || !soundPlayerMap.value) { + return; + } + + const player = soundPlayerMap.value[type]; + player.pause(); + player.muted = false; + player.volume = sound.value.volume / 100; + player.currentTime = 0; + await player.play(); + } + + async function playScanSuccessSound(): Promise { + await playSound("scanSuccess"); + } + + async function playRegisterSuccessSound(): Promise { + await playSound("registerSuccess"); + } + + return { + sound, + setSound, + loadSoundPlayers, + unlockSoundPlayers, + playScanSuccessSound, + playRegisterSuccessSound + }; +}); diff --git a/src/store/tabBarStore.ts b/src/store/tabBarStore.ts new file mode 100644 index 0000000..206c7b9 --- /dev/null +++ b/src/store/tabBarStore.ts @@ -0,0 +1,9 @@ +export const useTabBarStore = defineStore("tab-bar", () => { + const router = useRouter(); + + const isShowing = computed(() => !!router.currentRoute.value.meta.tabBarVisible); + + return { + isShowing + }; +}); diff --git a/src/styles/global.less b/src/styles/global.less new file mode 100644 index 0000000..0cb3bb2 --- /dev/null +++ b/src/styles/global.less @@ -0,0 +1,39 @@ +html, +body, +#root { + --td-swiper-border-radius: 0; + + height: 100%; + min-height: 100vh; +} + +html { + color-scheme: light; + background: #F5F5F8; +} + +html.theme-dark { + color-scheme: dark; + background: #10161f; +} + +body { + margin: 0; + color: #111827; + background: #F5F5F8; + font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; + transition: background .2s ease, color .2s ease; +} + +html.theme-dark body { + color: #f3f4f6; + background: #10161f; +} + +* { + box-sizing: border-box; +} + +.t-form__label { + color: #555; +} diff --git a/src/styles/tdesign-custom.css b/src/styles/tdesign-custom.css new file mode 100644 index 0000000..fa57999 --- /dev/null +++ b/src/styles/tdesign-custom.css @@ -0,0 +1,284 @@ +:root, :root[theme-mode="light"] { + --td-brand-color-1: #ebf9f6; + --td-brand-color-2: #ceebe6; + --td-brand-color-3: #a4d5ce; + --td-brand-color-4: #76bbb3; + --td-brand-color-5: #559f97; + --td-brand-color-6: #29857d; + --td-brand-color-7: #0f766e; + --td-brand-color-8: #00524b; + --td-brand-color-9: #003b36; + --td-brand-color-10: #002723; + --td-warning-color-1: #fff1e9; + --td-warning-color-2: #ffd9c2; + --td-warning-color-3: #ffb98c; + --td-warning-color-4: #fa9550; + --td-warning-color-5: #e37318; + --td-warning-color-6: #be5a00; + --td-warning-color-7: #954500; + --td-warning-color-8: #713300; + --td-warning-color-9: #532300; + --td-warning-color-10: #3b1700; + --td-error-color-1: #fff0ed; + --td-error-color-2: #ffd8d2; + --td-error-color-3: #ffb9b0; + --td-error-color-4: #ff9285; + --td-error-color-5: #f6685d; + --td-error-color-6: #d54941; + --td-error-color-7: #ad352f; + --td-error-color-8: #881f1c; + --td-error-color-9: #68070a; + --td-error-color-10: #490002; + --td-success-color-1: #e3f9e9; + --td-success-color-2: #c6f3d7; + --td-success-color-3: #92dab2; + --td-success-color-4: #56c08d; + --td-success-color-5: #2ba471; + --td-success-color-6: #008858; + --td-success-color-7: #006c45; + --td-success-color-8: #005334; + --td-success-color-9: #003b23; + --td-success-color-10: #002515; + --td-gray-color-1: #f6f6f6; + --td-gray-color-2: #eeeceb; + --td-gray-color-3: #dddbdb; + --td-gray-color-4: #cac9c9; + --td-gray-color-5: #b6b6b6; + --td-gray-color-6: #a2a2a2; + --td-gray-color-7: #8f8f8f; + --td-gray-color-8: #7b7c7c; + --td-gray-color-9: #6a6b6b; + --td-gray-color-10: #585a5a; + --td-gray-color-11: #494a4a; + --td-gray-color-12: #3a3b3b; + --td-gray-color-13: #2c2e2e; + --td-gray-color-14: #202222; + --td-font-white-1: rgba(255, 255, 255, 1); + --td-font-white-2: rgba(255, 255, 255, .55); + --td-font-white-3: rgba(255, 255, 255, .35); + --td-font-white-4: rgba(255, 255, 255, .22); + --td-font-gray-1: rgba(0, 0, 0, .9); + --td-font-gray-2: rgba(0, 0, 0, .6); + --td-font-gray-3: rgba(0, 0, 0, .4); + --td-font-gray-4: rgba(0, 0, 0, .26); + --td-brand-color: var(--td-brand-color-7); + --td-warning-color: var(--td-warning-color-5); + --td-error-color: var(--td-error-color-6); + --td-success-color: var(--td-success-color-5); + --td-brand-color-focus: var(--td-brand-color-1); + --td-brand-color-active: var(--td-brand-color-8); + --td-brand-color-disabled: var(--td-brand-color-3); + --td-brand-color-light: var(--td-brand-color-1); + --td-brand-color-light-active: var(--td-brand-color-2); + --td-warning-color-active: var(--td-warning-color-6); + --td-warning-color-disabled: var(--td-warning-color-3); + --td-warning-color-focus: var(--td-warning-color-2); + --td-warning-color-light: var(--td-warning-color-1); + --td-warning-color-light-active: var(--td-warning-color-2); + --td-error-color-focus: var(--td-error-color-2); + --td-error-color-active: var(--td-error-color-7); + --td-error-color-disabled: var(--td-error-color-3); + --td-error-color-light: var(--td-error-color-1); + --td-error-color-light-active: var(--td-error-color-2); + --td-success-color-focus: var(--td-success-color-2); + --td-success-color-active: var(--td-success-color-6); + --td-success-color-disabled: var(--td-success-color-3); + --td-success-color-light: var(--td-success-color-1); + --td-success-color-light-active: var(--td-success-color-2); + --td-mask-active: rgba(0, 0, 0, .6); + --td-mask-disabled: rgba(255, 255, 255, .6); + --td-bg-color-page: var(--td-gray-color-1); + --td-bg-color-container: var(--td-font-white-1); + --td-bg-color-container-active: var(--td-gray-color-3); + --td-bg-color-secondarycontainer: var(--td-gray-color-1); + --td-bg-color-secondarycontainer-active: var(--td-gray-color-4); + --td-bg-color-component: var(--td-gray-color-3); + --td-bg-color-component-active: var(--td-gray-color-6); + --td-bg-color-component-disabled: var(--td-gray-color-2); + --td-bg-color-secondarycomponent: var(--td-gray-color-4); + --td-bg-color-secondarycomponent-active: var(--td-gray-color-6); + --td-bg-color-specialcomponent: #fff; + --td-text-color-primary: var(--td-font-gray-1); + --td-text-color-secondary: var(--td-font-gray-2); + --td-text-color-placeholder: var(--td-font-gray-3); + --td-text-color-disabled: var(--td-font-gray-4); + --td-text-color-anti: var(--td-font-white-1); + --td-text-color-brand: var(--td-brand-color); + --td-text-color-link: var(--td-brand-color); + --td-border-level-1-color: var(--td-gray-color-3); + --td-component-stroke: var(--td-gray-color-3); + --td-border-level-2-color: var(--td-gray-color-4); + --td-component-border: var(--td-gray-color-4); + --td-shadow-1: 0 1px 6px rgba(0, 0, 0, 0.05),0 3px 4px rgba(0, 0, 0, 0.04),0 1px 2px -1px rgba(0, 0, 0, 0.08); + --td-shadow-2: 0 3px 10px 2px rgba(0, 0, 0, 0.04),0 6px 8px rgba(0, 0, 0, 0.05),0 4px 4px -2px rgba(0, 0, 0, 0.08); + --td-shadow-3: 0 4px 18px 5px rgba(0, 0, 0, 0.05),0 10px 9px 2px rgba(0, 0, 0, 0.04),0 3px 5px -3px rgba(0, 0, 0, 0.08); + --td-shadow-4: 0 2px 8px 0 rgba(0, 0, 0, 6%); + --td-shadow-inset-top: inset 0 .5px 0 #dcdcdc; + --td-shadow-inset-right: inset .5px 0 0 #dcdcdc; + --td-shadow-inset-bottom: inset 0 -.5px 0 #dcdcdc; + --td-shadow-inset-left: inset -.5px 0 0 #dcdcdc; + --td-table-shadow-color: rgba(0, 0, 0, .08); + --td-scrollbar-color: rgba(0, 0, 0, .1); + --td-scrollbar-hover-color: rgba(0, 0, 0, .3); + --td-scroll-track-color: #fff; +} + +:root.dark, :root[theme-mode="dark"] { + --td-brand-color-1: #002723; + --td-brand-color-2: #003b36; + --td-brand-color-3: #00524b; + --td-brand-color-4: #0f766e; + --td-brand-color-5: #29857d; + --td-brand-color-6: #559f97; + --td-brand-color-7: #76bbb3; + --td-brand-color-8: #a4d5ce; + --td-brand-color-9: #ceebe6; + --td-brand-color-10: #ebf9f6; + --td-warning-color-1: #4f2a1d; + --td-warning-color-2: #582f21; + --td-warning-color-3: #733c23; + --td-warning-color-4: #a75d2b; + --td-warning-color-5: #cf6e2d; + --td-warning-color-6: #dc7633; + --td-warning-color-7: #e8935c; + --td-warning-color-8: #ecbf91; + --td-warning-color-9: #eed7bf; + --td-warning-color-10: #f3e9dc; + --td-error-color-1: #472324; + --td-error-color-2: #5e2a2d; + --td-error-color-3: #703439; + --td-error-color-4: #83383e; + --td-error-color-5: #a03f46; + --td-error-color-6: #c64751; + --td-error-color-7: #de6670; + --td-error-color-8: #ec888e; + --td-error-color-9: #edb1b6; + --td-error-color-10: #eeced0; + --td-success-color-1: #193a2a; + --td-success-color-2: #1a4230; + --td-success-color-3: #17533d; + --td-success-color-4: #0d7a55; + --td-success-color-5: #059465; + --td-success-color-6: #43af8a; + --td-success-color-7: #46bf96; + --td-success-color-8: #80d2b6; + --td-success-color-9: #b4e1d3; + --td-success-color-10: #deede8; + --td-gray-color-1: #f6f6f6; + --td-gray-color-2: #eeeceb; + --td-gray-color-3: #dddbdb; + --td-gray-color-4: #cac9c9; + --td-gray-color-5: #b6b6b6; + --td-gray-color-6: #a2a2a2; + --td-gray-color-7: #8f8f8f; + --td-gray-color-8: #7b7c7c; + --td-gray-color-9: #6a6b6b; + --td-gray-color-10: #585a5a; + --td-gray-color-11: #494a4a; + --td-gray-color-12: #3a3b3b; + --td-gray-color-13: #2c2e2e; + --td-gray-color-14: #202222; + --td-font-white-1: rgba(255, 255, 255, .9); + --td-font-white-2: rgba(255, 255, 255, .55); + --td-font-white-3: rgba(255, 255, 255, .35); + --td-font-white-4: rgba(255, 255, 255, .22); + --td-font-gray-1: rgba(0, 0, 0, .9); + --td-font-gray-2: rgba(0, 0, 0, .6); + --td-font-gray-3: rgba(0, 0, 0, .4); + --td-font-gray-4: rgba(0, 0, 0, .26); + --td-brand-color: var(--td-brand-color-6); + --td-warning-color: var(--td-warning-color-5); + --td-error-color: var(--td-error-color-6); + --td-success-color: var(--td-success-color-5); + --td-brand-color-focus: var(--td-brand-color-1); + --td-brand-color-active: var(--td-brand-color-7); + --td-brand-color-disabled: var(--td-brand-color-3); + --td-brand-color-light: var(--td-brand-color-1); + --td-brand-color-light-active: var(--td-brand-color-2); + --td-warning-color-focus: var(--td-warning-color-2); + --td-warning-color-active: var(--td-warning-color-4); + --td-warning-color-disabled: var(--td-warning-color-3); + --td-warning-color-light: var(--td-warning-color-1); + --td-warning-color-light-active: var(--td-warning-color-2); + --td-error-color-focus: var(--td-error-color-2); + --td-error-color-active: var(--td-error-color-5); + --td-error-color-disabled: var(--td-error-color-3); + --td-error-color-light: var(--td-error-color-1); + --td-error-color-light-active: var(--td-error-color-2); + --td-success-color-focus: var(--td-success-color-2); + --td-success-color-active: var(--td-success-color-4); + --td-success-color-disabled: var(--td-success-color-3); + --td-success-color-light: var(--td-success-color-1); + --td-success-color-light-active: var(--td-success-color-2); + --td-mask-active: rgba(0, 0, 0, .4); + --td-mask-disabled: rgba(0, 0, 0, .6); + --td-bg-color-page: var(--td-gray-color-14); + --td-bg-color-container: var(--td-gray-color-13); + --td-bg-color-secondarycontainer: var(--td-gray-color-12); + --td-bg-color-component: var(--td-gray-color-11); + --td-bg-color-container-active: var(--td-gray-color-12); + --td-bg-color-secondarycontainer-active: var(--td-gray-color-11); + --td-bg-color-component-active: var(--td-gray-color-10); + --td-bg-color-component-disabled: var(--td-gray-color-12); + --td-bg-color-specialcomponent: transparent; + --td-text-color-primary: var(--td-font-white-1); + --td-text-color-secondary: var(--td-font-white-2); + --td-text-color-placeholder: var(--td-font-white-3); + --td-text-color-disabled: var(--td-font-white-4); + --td-text-color-anti: var(--td-font-white-1); + --td-text-color-brand: var(--td-brand-color-8); + --td-text-color-link: var(--td-brand-color-8); + --td-border-level-1-color: var(--td-gray-color-11); + --td-component-stroke: var(--td-gray-color-11); + --td-border-level-2-color: var(--td-gray-color-9); + --td-component-border: var(--td-gray-color-9); + --td-shadow-1: 0 1px 6px rgba(0, 0, 0, 0.05),0 3px 4px rgba(0, 0, 0, 0.04),0 1px 2px -1px rgba(0, 0, 0, 0.08); + --td-shadow-2: 0 3px 10px 2px rgba(0, 0, 0, 0.04),0 6px 8px rgba(0, 0, 0, 0.05),0 4px 4px -2px rgba(0, 0, 0, 0.08); + --td-shadow-3: 0 4px 18px 5px rgba(0, 0, 0, 0.05),0 10px 9px 2px rgba(0, 0, 0, 0.04),0 3px 5px -3px rgba(0, 0, 0, 0.08); + --td-shadow-inset-top: inset 0 .5px 0 #5e5e5e; + --td-shadow-inset-right: inset .5px 0 0 #5e5e5e; + --td-shadow-inset-bottom: inset 0 -.5px 0 #5e5e5e; + --td-shadow-inset-left: inset -.5px 0 0 #5e5e5e; + --td-table-shadow-color: rgba(0, 0, 0, .55); + --td-scrollbar-color: rgba(255, 255, 255, .1); + --td-scroll-track-color: #333; +} + +:root { + --td-font-family: pingfang sc, microsoft yahei, arial regular; + --td-font-family-medium: pingfang sc, microsoft yahei, arial medium; + --td-font-size-link-small: 12px; + --td-font-size-link-medium: 14px; + --td-font-size-link-large: 16px; + --td-font-size-mark-extraSmall: 10px; + --td-font-size-mark-small: 12px; + --td-font-size-mark-medium: 14px; + --td-font-size-mark-large: 16px; + --td-font-size-body-extraSmall: 10px; + --td-font-size-body-small: 12px; + --td-font-size-body-medium: 14px; + --td-font-size-body-large: 16px; + --td-font-size-title-small: 14px; + --td-font-size-title-medium: 16px; + --td-font-size-title-large: 18px; + --td-font-size-title-extraLarge: 20px; + --td-font-size-headline-small: 24px; + --td-font-size-headline-medium: 28px; + --td-font-size-headline-large: 36px; + --td-font-size-display-medium: 48px; + --td-font-size-display-large: 64px; + --td-font-size: 10px; + --td-font-size-xs: var(--td-font-size-body-extraSmall); + --td-font-size-s: var(--td-font-size-body-small); + --td-font-size-base: var(--td-font-size-title-small); + --td-font-size-m: var(--td-font-size-title-medium); + --td-font-size-l: var(--td-font-size-title-large); + --td-font-size-xl: var(--td-font-size-title-extraLarge); + --td-font-size-xxl: var(--td-font-size-headline-large); + --td-radius-small: 4px; + --td-radius-default: 6px; + --td-radius-large: 18px; + --td-radius-extraLarge: 24px; + --td-radius-round: 999px; + --td-radius-circle: 50%; +} diff --git a/src/types/Customer.ts b/src/types/Customer.ts new file mode 100644 index 0000000..73f0c97 --- /dev/null +++ b/src/types/Customer.ts @@ -0,0 +1,60 @@ +import type { Attachment, Model, User } from "timi-web"; + +export type CustomerGender = "MALE" | "FEMALE"; + +export type BodyAreaValue = { + selectedCodeList: string[]; +}; + +export type Customer = { + code?: string; + name?: string; + gender?: CustomerGender; + age?: number; + telephone?: string; + address?: string; + remark?: string; + disease?: string; + conditioningPart?: BodyAreaValue; + introducerCustomerId?: string; + creatorUserId?: string; + lastSignInAt?: number; + introducerCustomer?: Customer; + creatorUser?: Partial; + invitedCount?: number; + attachmentList?: Attachment[]; + attachmentIdList?: string[]; +} & Model; + +export type CustomerSearchReq = { + keyword?: string; + introducerCustomerId?: string; +}; + +export type CustomerTrendStatReq = { + beginCreatedAt: number; + endCreatedAt: number; +}; + +export type CustomerDailyStatView = { + dateValue?: number; + newCustomerCount?: number; + totalCustomerCount?: number; +}; + +export type CustomerGenderStatView = { + genderCode?: CustomerGender | "UNKNOWN"; + count?: number; +}; + +export type CustomerInviteUpdateReq = { + customerId: string; + introducerCustomerId?: string; +}; + +export type QuickRegisterReq = { + customerCode: string; + registrationEventId: string; + remark?: string; + attachmentIdList?: string[]; +}; diff --git a/src/types/GaoUser.ts b/src/types/GaoUser.ts new file mode 100644 index 0000000..627f194 --- /dev/null +++ b/src/types/GaoUser.ts @@ -0,0 +1,10 @@ +import type { Model, Role, User } from "timi-web"; + +export type GaoUser = { + userId?: string; + enabled?: boolean; + remark?: string; + user?: Partial; + roleList?: Array; + roleIdList?: string[]; +} & Model; diff --git a/src/types/RegistrationEvent.ts b/src/types/RegistrationEvent.ts new file mode 100644 index 0000000..0471d4e --- /dev/null +++ b/src/types/RegistrationEvent.ts @@ -0,0 +1,18 @@ +import type { Model } from "timi-web"; + +export type RegistrationEventStatus = "ACTIVE" | "INACTIVE" | "DELETED"; + +export type RegistrationLimitType = "NONE" | "DAILY_HALF_DAY" | "NATURAL_DAY" | "INTERVAL_HOUR" | "NATURAL_MONTH" | "TOTAL_LIMIT"; + +export type RegistrationEvent = { + name: string; + description?: string; + color?: string; + status?: RegistrationEventStatus; + enabled?: boolean; + requirePhoto?: boolean; + limitType?: RegistrationLimitType; + limitValue?: number; + sort?: number; + roleCodeList?: string[]; +} & Model; diff --git a/src/types/RegistrationEventRecord.ts b/src/types/RegistrationEventRecord.ts new file mode 100644 index 0000000..7aa87f0 --- /dev/null +++ b/src/types/RegistrationEventRecord.ts @@ -0,0 +1,81 @@ +import type { Attachment, Model, User } from "timi-web"; +import type { Customer } from "@/types/Customer"; +import type { RegistrationEvent } from "@/types/RegistrationEvent"; + +export type RegistrationEventRecord = { + customerId?: string; + registrationEventId?: string; + operatorUserId?: string; + remark?: string; + registeredAt?: number; + customer?: Customer; + registrationEvent?: RegistrationEvent; + operator?: Partial; + attachmentList?: Array>; + attachmentIdList?: string[]; +} & Model; + +export type RegistrationEventRecordListItemView = { + id?: string; + customerId?: string; + customerName?: string; + customerPhotoAttachmentId?: string; + registrationEventId?: string; + registrationEventName?: string; + registeredAt?: number; +}; + +export type RegistrationEventRecordRangeReq = { + customerId?: string; + registrationEventId?: string; + registrationEventIdList?: string[]; + keyword?: string; + beginRegisteredAt: number; + endRegisteredAt: number; +}; + +export type RegistrationEventRecordStatReq = { + customerId?: string; + beginRegisteredAt: number; + endRegisteredAt: number; +}; + +export type RegistrationEventRecordTrendStatReq = { + customerId?: string; + registrationEventId: string; + beginRegisteredAt: number; + endRegisteredAt: number; +}; + +export type CustomerRegisterStatView = { + customerId?: string; + customerName?: string; + registrationEventId?: string; + registrationEventName?: string; + count?: number; + latestRegisteredAt?: number; +}; + +export type RegistrationEventRecordDailyStatView = { + dateValue?: number; + dailyCount?: number; + totalCount?: number; +}; + +export type RegistrationEventRecordCalendarView = { + id?: string; + customerId?: string; + customerCode?: string; + customerName?: string; + registrationEventId?: string; + registeredAt?: number; +}; + +export type RegistrationEventRecordCreateReq = { + customerId?: string; + customerCode?: string; + registrationEventId: string; + remark?: string; + registeredAt?: number; + attachmentIdList?: string[]; +}; diff --git a/src/types/browser-image-compression.d.ts b/src/types/browser-image-compression.d.ts new file mode 100644 index 0000000..049a8ea --- /dev/null +++ b/src/types/browser-image-compression.d.ts @@ -0,0 +1,18 @@ +declare module "browser-image-compression" { + export interface ImageCompressionOptions { + alwaysKeepResolution?: boolean; + exifOrientation?: number; + fileType?: string; + initialQuality?: number; + libURL?: string; + maxIteration?: number; + maxSizeMB?: number; + maxWidthOrHeight?: number; + onProgress?: (progress: number) => void; + preserveExif?: boolean; + signal?: AbortSignal; + useWebWorker?: boolean; + } + + export default function imageCompression(file: File, options: ImageCompressionOptions): Promise; +} diff --git a/src/utils/customer.ts b/src/utils/customer.ts new file mode 100644 index 0000000..51ffa09 --- /dev/null +++ b/src/utils/customer.ts @@ -0,0 +1,32 @@ +import { AttachmentAPI } from "timi-web"; +import type { BodyAreaValue, Customer } from "@/types/Customer"; + +export function getCustomerPhotoURL(customer?: Customer): string { + const attachment = customer?.attachmentList?.find(item => item.attachType === "PHOTO") || customer?.attachmentList?.[0]; + if (!attachment?.id) { + return ""; + } + + return AttachmentAPI.getReadURL(attachment.id); +} + +export function createBodyAreaValue(): BodyAreaValue { + return { + selectedCodeList: [] + }; +} + +export function normalizeBodyAreaValue(value: unknown): BodyAreaValue { + if (!value || typeof value !== "object") { + return createBodyAreaValue(); + } + + const raw = value as Partial; + if (!Array.isArray(raw.selectedCodeList)) { + return createBodyAreaValue(); + } + + return { + selectedCodeList: raw.selectedCodeList.map(item => String(item).trim()).filter(Boolean) + }; +} diff --git a/src/utils/gaoPermission.ts b/src/utils/gaoPermission.ts new file mode 100644 index 0000000..f11ebdc --- /dev/null +++ b/src/utils/gaoPermission.ts @@ -0,0 +1,78 @@ +export const gaoPermissionCodes = { + customer: { + create: "GAO:CUSTOMER:CREATE", + read: "GAO:CUSTOMER:READ", + update: "GAO:CUSTOMER:UPDATE", + delete: "GAO:CUSTOMER:DELETE" + }, + registrationEvent: { + create: "GAO:REGISTRATION_EVENT:CREATE", + read: "GAO:REGISTRATION_EVENT:READ", + update: "GAO:REGISTRATION_EVENT:UPDATE", + delete: "GAO:REGISTRATION_EVENT:DELETE" + }, + registrationEventRecord: { + create: "GAO:REGISTRATION_EVENT_RECORD:CREATE", + read: "GAO:REGISTRATION_EVENT_RECORD:READ", + update: "GAO:REGISTRATION_EVENT_RECORD:UPDATE", + delete: "GAO:REGISTRATION_EVENT_RECORD:DELETE" + }, + stat: { + read: "GAO:STAT:READ" + }, + user: { + create: "GAO:USER:CREATE", + read: "GAO:USER:READ", + update: "GAO:USER:UPDATE", + delete: "GAO:USER:DELETE" + }, + qrCode: { + create: "GAO:QR_CODE:CREATE" + } +} as const; + +export const corePermissionCodes = { + role: { + create: "CORE:ROLE:CREATE", + read: "CORE:ROLE:READ", + update: "CORE:ROLE:UPDATE", + delete: "CORE:ROLE:DELETE" + }, + permission: { + create: "CORE:PERMISSION:CREATE", + read: "CORE:PERMISSION:READ", + update: "CORE:PERMISSION:UPDATE", + delete: "CORE:PERMISSION:DELETE" + }, + rolePermission: { + create: "CORE:ROLE_PERMISSION:CREATE", + read: "CORE:ROLE_PERMISSION:READ", + delete: "CORE:ROLE_PERMISSION:DELETE" + }, + roleRelation: { + create: "CORE:ROLE_RELATION:CREATE", + read: "CORE:ROLE_RELATION:READ", + delete: "CORE:ROLE_RELATION:DELETE" + }, + userRole: { + create: "CORE:USER_ROLE:CREATE", + read: "CORE:USER_ROLE:READ", + delete: "CORE:USER_ROLE:DELETE" + } +} as const; + +export const coreRoleCodes = { + admin: "CORE:ADMIN", + userRoleAdmin: "CORE:USER_ROLE_ADMIN" +} as const; + +export const permissionManagementRoleAccess = { + value: [ + coreRoleCodes.admin, + coreRoleCodes.userRoleAdmin + ], + mode: "or" +} as const; + +export type GaoPermissionCodes = typeof gaoPermissionCodes; +export type CorePermissionCodes = typeof corePermissionCodes; diff --git a/src/utils/gaoRole.ts b/src/utils/gaoRole.ts new file mode 100644 index 0000000..5b91003 --- /dev/null +++ b/src/utils/gaoRole.ts @@ -0,0 +1,70 @@ +import type { Role } from "@/store/permissionSettingsStore"; +import type { GaoUser } from "@/types/GaoUser"; + +type GaoUserRole = NonNullable[number]; + +function buildRoleCode(role: Role): string { + return role.moduleCode && !role.code.includes(":") ? `${role.moduleCode}:${role.code}` : role.code; +} + +function getBareRoleCode(code: string): string { + const codePartList = code.split(":"); + return codePartList[codePartList.length - 1] || code; +} + +function findRole(role: GaoUserRole, roleList: Role[]): Role | undefined { + if (typeof role === "string") { + return roleList.find(roleItem => roleItem.code === role || buildRoleCode(roleItem) === role); + } + return roleList.find(roleItem => roleItem.id === role.id || roleItem.code === role.code || buildRoleCode(roleItem) === role.code); +} + +function appendCompatibleRoleCode(roleCodeSet: Set, code: string): void { + if (!code) { + return; + } + + roleCodeSet.add(code); + roleCodeSet.add(getBareRoleCode(code)); +} + +export function getGaoRoleName(role: GaoUserRole | undefined, roleList: Role[]): string { + if (!role) { + return "未配置角色"; + } + + const fullRole = findRole(role, roleList); + if (fullRole) { + return fullRole.name || fullRole.code || "未配置角色"; + } + + return typeof role === "string" ? getBareRoleCode(role) : role.name || role.code || "未配置角色"; +} + +export function buildEffectiveRoleCodeSet(user: GaoUser, roleList: Role[]): Set { + const roleCodeSet = new Set(); + for (const role of user.roleList || []) { + const fullRole = findRole(role, roleList); + if (fullRole) { + appendRoleCode(roleCodeSet, fullRole, roleList, new Set()); + continue; + } + appendCompatibleRoleCode(roleCodeSet, typeof role === "string" ? role : role.code); + } + return roleCodeSet; +} + +function appendRoleCode(roleCodeSet: Set, role: Role, roleList: Role[], visitedRoleIds: Set): void { + if (!role.id || visitedRoleIds.has(role.id)) { + return; + } + + visitedRoleIds.add(role.id); + appendCompatibleRoleCode(roleCodeSet, buildRoleCode(role)); + for (const childRoleId of role.childRoleIdList) { + const childRole = roleList.find(item => item.id === childRoleId); + if (childRole) { + appendRoleCode(roleCodeSet, childRole, roleList, visitedRoleIds); + } + } +} diff --git a/src/utils/imageCompression.ts b/src/utils/imageCompression.ts new file mode 100644 index 0000000..fb75190 --- /dev/null +++ b/src/utils/imageCompression.ts @@ -0,0 +1,27 @@ +import imageCompression from "browser-image-compression"; + +const PHOTO_MAX_SIZE_MB = 300 / 1024; +const PHOTO_MAX_WIDTH_OR_HEIGHT = 1920; + +/** + * 压缩上传图片,统一限制到 300 KB。 + */ +export async function compressUploadImage(file: File): Promise { + return await imageCompression(file, { + maxSizeMB: PHOTO_MAX_SIZE_MB, + maxWidthOrHeight: PHOTO_MAX_WIDTH_OR_HEIGHT, + useWebWorker: true, + initialQuality: .86 + }); +} + +/** + * 批量压缩上传图片。 + */ +export async function compressUploadImageList(fileList: File[]): Promise { + const result: File[] = []; + for (const file of fileList) { + result.push(await compressUploadImage(file)); + } + return result; +} diff --git a/src/utils/managementQrCode.ts b/src/utils/managementQrCode.ts new file mode 100644 index 0000000..1fdee5b --- /dev/null +++ b/src/utils/managementQrCode.ts @@ -0,0 +1,278 @@ +import { BarcodeFormat, EncodeHintType, QRCodeWriter } from "@zxing/library"; + +export interface ManagementQrCodePage { + pageIndex: number; + codes: string[]; +} + +export interface DownloadManagementQrCodeOptions { + codes: string[]; + filePrefix: string; + maxCodeLength?: number; +} + +export interface PrintManagementQrCodeOptions { + codes: string[]; + maxCodeLength?: number; + title?: string; +} + +export interface ManagementQrCodeGrid { + rows: number; + columns: number; + pageSize: number; +} + +const pageWidth = 2480; +const pageHeight = 3508; +const pagePadding = 80; +const qrSize = 300; +const minCellGap = 18; +const codeFontSize = 34; +const codeTopGap = 3; +const gridLineWidth = 2; +const codeTextHorizontalPadding = 28; +const codeTextWidthRatio = .62; +const qrWriter = new QRCodeWriter(); +const qrEncodeHints = new Map([ + [EncodeHintType.ERROR_CORRECTION, "H"], + [EncodeHintType.CHARACTER_SET, "UTF-8"], + [EncodeHintType.MARGIN, 4] +]); + +export function calculateManagementQrCodeGrid(maxCodeLength = 0): ManagementQrCodeGrid { + const codeTextMinWidth = Math.ceil(maxCodeLength * codeFontSize * codeTextWidthRatio + codeTextHorizontalPadding); + const cellMinWidth = Math.max(qrSize + minCellGap, codeTextMinWidth + minCellGap); + const cellMinHeight = qrSize + codeTopGap + codeFontSize + minCellGap; + const columns = Math.max(1, Math.floor((pageWidth - pagePadding * 2) / cellMinWidth)); + const rows = Math.max(1, Math.floor((pageHeight - pagePadding * 2) / cellMinHeight)); + + return { + rows, + columns, + pageSize: rows * columns + }; +} + +export function splitManagementQrCodePages(codes: string[], maxCodeLength = 0): ManagementQrCodePage[] { + const pages: ManagementQrCodePage[] = []; + const pageSize = calculateManagementQrCodeGrid(maxCodeLength).pageSize; + + for (let index = 0; index < codes.length; index += pageSize) { + pages.push({ + pageIndex: pages.length, + codes: codes.slice(index, index + pageSize) + }); + } + + return pages; +} + +export async function downloadManagementQrCodeImages(options: DownloadManagementQrCodeOptions): Promise { + const pages = splitManagementQrCodePages(options.codes, options.maxCodeLength); + + for (const page of pages) { + const canvas = renderManagementQrCodePage(page.codes, options.maxCodeLength); + await downloadCanvas(canvas, `${options.filePrefix}-${String(page.pageIndex + 1).padStart(2, "0")}.png`); + } +} + +export async function printManagementQrCodeImages(options: PrintManagementQrCodeOptions): Promise { + const printWindow = window.open("", "_blank"); + if (!printWindow) { + throw new Error("浏览器阻止了打印窗口,请允许弹出窗口后重试"); + } + + const pages = splitManagementQrCodePages(options.codes, options.maxCodeLength); + const imageList = pages.map(page => renderManagementQrCodePage(page.codes, options.maxCodeLength).toDataURL("image/png")); + const title = options.title || "客户二维码打印"; + const imageHTML = imageList.map(src => `
客户二维码
`).join(""); + + printWindow.document.open(); + printWindow.document.write(` + + + + ${escapeHTML(title)} + + +${imageHTML} +`); + printWindow.document.close(); + await waitPrintImagesLoaded(printWindow.document); + printWindow.focus(); + printWindow.print(); +} + +function renderManagementQrCodePage(codes: string[], maxCodeLength = 0): HTMLCanvasElement { + const canvas = document.createElement("canvas"); + canvas.width = pageWidth; + canvas.height = pageHeight; + const grid = calculateManagementQrCodeGrid(maxCodeLength); + + const context = canvas.getContext("2d"); + if (!context) { + throw new Error("当前浏览器不支持 Canvas"); + } + + context.fillStyle = "#ffffff"; + context.fillRect(0, 0, pageWidth, pageHeight); + context.fillStyle = "#000000"; + context.font = `500 ${codeFontSize}px Arial, sans-serif`; + context.textAlign = "center"; + context.textBaseline = "top"; + + const cellWidth = (pageWidth - pagePadding * 2) / grid.columns; + const cellHeight = (pageHeight - pagePadding * 2) / grid.rows; + + drawGridLines(context, grid, cellWidth, cellHeight); + + codes.forEach((code, index) => { + const rowIndex = Math.floor(index / grid.columns); + const columnIndex = index % grid.columns; + const cellLeft = pagePadding + columnIndex * cellWidth; + const cellTop = pagePadding + rowIndex * cellHeight; + const qrLeft = Math.round(cellLeft + (cellWidth - qrSize) / 2); + const qrTop = Math.round(cellTop + (cellHeight - qrSize - codeTopGap - codeFontSize) / 2); + + drawQrCode(context, code, qrLeft, qrTop, qrSize); + context.fillStyle = "#000000"; + context.fillText(code, cellLeft + cellWidth / 2, qrTop + qrSize + codeTopGap); + }); + + return canvas; +} + +async function waitPrintImagesLoaded(document: Document): Promise { + const imageList = Array.from(document.images); + await Promise.all(imageList.map(image => { + if (image.complete) { + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + image.onload = () => resolve(); + image.onerror = () => reject(new Error("打印图片加载失败")); + }); + })); +} + +function escapeHTML(value: string): string { + return value + .replaceAll("&", "&") + .replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("\"", """); +} + +function drawGridLines(context: CanvasRenderingContext2D, grid: ManagementQrCodeGrid, cellWidth: number, cellHeight: number): void { + context.strokeStyle = "#d1d5db"; + context.lineWidth = gridLineWidth; + + for (let rowIndex = 0; rowIndex <= grid.rows; rowIndex++) { + const top = Math.round(pagePadding + rowIndex * cellHeight); + context.beginPath(); + context.moveTo(pagePadding, top); + context.lineTo(pageWidth - pagePadding, top); + context.stroke(); + } + + for (let columnIndex = 0; columnIndex <= grid.columns; columnIndex++) { + const left = Math.round(pagePadding + columnIndex * cellWidth); + context.beginPath(); + context.moveTo(left, pagePadding); + context.lineTo(left, pageHeight - pagePadding); + context.stroke(); + } +} + +function drawQrCode(context: CanvasRenderingContext2D, code: string, left: number, top: number, qrSize: number): void { + const matrix = qrWriter.encode(code, BarcodeFormat.QR_CODE, qrSize, qrSize, qrEncodeHints); + const width = matrix.getWidth(); + const height = matrix.getHeight(); + const sourceCanvas = document.createElement("canvas"); + sourceCanvas.width = width; + sourceCanvas.height = height; + const sourceContext = sourceCanvas.getContext("2d"); + + if (!sourceContext) { + throw new Error("当前浏览器不支持 Canvas"); + } + + sourceContext.fillStyle = "#ffffff"; + sourceContext.fillRect(0, 0, width, height); + sourceContext.fillStyle = "#000000"; + + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + if (matrix.get(x, y)) { + sourceContext.fillRect(x, y, 1, 1); + } + } + } + + context.fillStyle = "#ffffff"; + context.fillRect(left, top, qrSize, qrSize); + context.imageSmoothingEnabled = false; + context.drawImage(sourceCanvas, left, top, qrSize, qrSize); + context.imageSmoothingEnabled = true; +} + +async function downloadCanvas(canvas: HTMLCanvasElement, fileName: string): Promise { + const blob = await new Promise((resolve, reject) => { + canvas.toBlob(result => { + if (result) { + resolve(result); + return; + } + + reject(new Error("图片生成失败")); + }, "image/png"); + }); + const link = document.createElement("a"); + const url = URL.createObjectURL(blob); + + link.href = url; + link.download = fileName; + link.click(); + + await new Promise(resolve => { + window.setTimeout(resolve, 80); + }); + + URL.revokeObjectURL(url); +} diff --git a/src/utils/registrationEventRecord.ts b/src/utils/registrationEventRecord.ts new file mode 100644 index 0000000..4590cd0 --- /dev/null +++ b/src/utils/registrationEventRecord.ts @@ -0,0 +1,11 @@ +import { AttachmentAPI } from "timi-web"; +import type { RegistrationEventRecord } from "@/types/RegistrationEventRecord"; + +export function getRegistrationEventRecordPhotoURL(record?: RegistrationEventRecord): string { + const attachment = record?.attachmentList?.find(item => item.attachType === "PHOTO") || record?.attachmentList?.[0]; + if (!attachment?.id) { + return ""; + } + + return AttachmentAPI.getReadURL(attachment.id); +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..ae394ad --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,47 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": [ + "src/*" + ], + "timi-web": [ + "../timi-web/dist/src/index.d.ts" + ], + "timi-web/*": [ + "../timi-web/dist/src/*" + ], + "vue": [ + "node_modules/vue" + ], + "pinia": [ + "node_modules/pinia" + ], + "vue-router": [ + "node_modules/vue-router" + ] + }, + "lib": [ + "ES2021", + "DOM", + "DOM.Iterable" + ], + "types": [ + "vite/client", + "tdesign-mobile-vue/global" + ], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.vue", + "auto-imports.d.ts", + "components.d.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..a5b06bf --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..3945ae4 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "allowSyntheticDefaultImports": true + }, + "include": [ + "vite.config.ts", + ".eslintrc.cjs" + ] +} diff --git a/tsconfig.publish.json b/tsconfig.publish.json new file mode 100644 index 0000000..7e57b30 --- /dev/null +++ b/tsconfig.publish.json @@ -0,0 +1,25 @@ +{ + "extends": "./tsconfig.app.json", + "compilerOptions": { + "paths": { + "@/*": [ + "src/*" + ], + "timi-web": [ + "../timi-web/dist/src/index.d.ts" + ], + "timi-web/*": [ + "../timi-web/dist/src/*" + ], + "vue": [ + "node_modules/vue" + ], + "pinia": [ + "node_modules/pinia" + ], + "vue-router": [ + "node_modules/vue-router" + ] + } + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..313379d --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,88 @@ +import { fileURLToPath, URL } from "node:url"; +import { defineConfig, loadEnv } from "vite"; +import vue from "@vitejs/plugin-vue"; +import AutoImport from "unplugin-auto-import/vite"; +import Components from "unplugin-vue-components/vite"; +import { TDesignResolver } from "unplugin-vue-components/resolvers"; + +const localTimiWebRoot = fileURLToPath(new URL("../timi-web", import.meta.url)); +const projectRoot = fileURLToPath(new URL(".", import.meta.url)); + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); + const useLocalTimiWeb = env.VITE_USE_LOCAL_TIMI_WEB !== "false"; + const useLocalTimiWebSource = useLocalTimiWeb && mode === "development"; + const useLocalTimiWebPublish = useLocalTimiWeb && mode !== "development"; + return { + resolve: { + dedupe: ["vue", "pinia", "vue-router"], + alias: [ + { + find: "@", + replacement: fileURLToPath(new URL("./src", import.meta.url)) + }, + ...(useLocalTimiWeb + ? [ + { + find: /^timi-web$/, + replacement: useLocalTimiWebSource + ? fileURLToPath(new URL("../timi-web/src/index.ts", import.meta.url)) + : fileURLToPath(new URL("../timi-web/dist/timi-web.mjs", import.meta.url)) + }, + { + find: /^timi-web\/style\.css$/, + replacement: useLocalTimiWebPublish + ? fileURLToPath(new URL("../timi-web/dist/timi-web.css", import.meta.url)) + : fileURLToPath(new URL("../timi-web/src/assets/style/timi-web.less", import.meta.url)) + } + ] + : []) + ] + }, + plugins: [ + vue(), + AutoImport({ + imports: ["vue", "vue-router", "pinia"], + dts: "auto-imports.d.ts", + eslintrc: { + enabled: true, + filepath: "./.eslintrc-auto-import.json", + globalsPropValue: true + }, + resolvers: [ + TDesignResolver({ + library: "mobile-vue" + }) + ] + }), + Components({ + dirs: ["src/components", "src/layout"], + dts: "components.d.ts", + resolvers: [ + TDesignResolver({ + library: "mobile-vue" + }) + ] + }) + ], + css: { + preprocessorOptions: { + less: { + javascriptEnabled: true + } + } + }, + server: { + port: 84, + allowedHosts: [ + "gao.imyeyu.dev" + ], + fs: { + allow: [ + projectRoot, + localTimiWebRoot + ] + } + } + }; +});