commit ae8db2e68b7b8516203f3cc0a35a6ff989095fda Author: fangyang2021 <3020949587@qq.com> Date: Thu Nov 21 10:52:23 2024 +0800 first commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..59d9a3a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0711527 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..77b3745 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 + "recommendations": ["angular.ng-template"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0ca929b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,5 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a298b5b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "start", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "pattern": "$tsc", + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "(.*?)" + }, + "endsPattern": { + "regexp": "bundle generation complete" + } + } + } + }, + { + "type": "npm", + "script": "test", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "pattern": "$tsc", + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "(.*?)" + }, + "endsPattern": { + "regexp": "bundle generation complete" + } + } + } + } + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..74fd2b8 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# Dec 视觉检测项目 + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.0. + +## Development server + +* `npm run start:client` +* `npm run start:manage` + + + +## Build + +* `npm run build:client` +* `npm run build:manage` + + +# 7.10 问题 +1. 相机列表需要返回 监测点id、分组id、电站id、相机型号、延时参数 或者新增详情接口 +2. 系统信息管理 保存 一起保存 +3. 主题管理 保存 一起保存 +4. 颜色的设置 +5. ui 端接口 +6. 用户管理 id 、uid 、userId +7. ui 查看权限 +8. 编辑算法 需要的数据 & 名称? +9. 机组管理 机组编号 2#caa +10. 相机管理列表 保存了数据过后就报错了 diff --git a/angular.json b/angular.json new file mode 100644 index 0000000..d88d01e --- /dev/null +++ b/angular.json @@ -0,0 +1,239 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "pnpm", + "analytics": false + }, + "newProjectRoot": "projects", + "projects": { + "client": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "less" + } + }, + "root": "projects/client", + "sourceRoot": "projects/client/src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "baseHref": "/ui/", + "outputPath": "dist/client", + "index": "projects/client/src/index.html", + "main": "projects/client/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "projects/client/tsconfig.app.json", + "inlineStyleLanguage": "less", + "assets": [ + "projects/client/src/favicon.ico", + "projects/client/src/assets", + { + "glob": "**/*", + "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", + "output": "/assets/" + } + ], + "styles": ["projects/client/src/styles.less"], + "scripts": [], + "fileReplacements": [ + { + "replace": "projects/client/src/environments/environment.ts", + "with": "projects/client/src/environments/environment.prod.ts" + } + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "10mb", + "maximumError": "10mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "10mb", + "maximumError": "10mb" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "browserTarget": "client:build:production" + }, + "development": { + "browserTarget": "client:build:development", + "port": 4396, + "host": "0.0.0.0" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "client:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": ["zone.js", "zone.js/testing"], + "tsConfig": "projects/client/tsconfig.spec.json", + "inlineStyleLanguage": "less", + "assets": ["projects/client/src/favicon.ico", "projects/client/src/assets"], + "styles": ["projects/client/src/styles.less"], + "scripts": [] + } + } + } + }, + "manage": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "less" + } + }, + "root": "projects/manage", + "sourceRoot": "projects/manage/src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "baseHref": "/admin/", + "outputPath": "dist/manage", + "index": "projects/manage/src/index.html", + "main": "projects/manage/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "projects/manage/tsconfig.app.json", + "inlineStyleLanguage": "less", + "assets": [ + "projects/manage/src/favicon.ico", + "projects/manage/src/assets", + { + "glob": "**/*", + "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", + "output": "/assets/" + } + ], + "styles": ["projects/manage/src/styles.less"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "10mb", + "maximumError": "10mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "10mb", + "maximumError": "10mb" + } + ], + "outputHashing": "all", + "fileReplacements": [ + { + "replace": "projects/manage/src/environments/environment.ts", + "with": "projects/manage/src/environments/environment.prod.ts" + } + ] + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "browserTarget": "manage:build:production" + }, + "development": { + "browserTarget": "manage:build:development", + "port": 4567, + "host": "0.0.0.0" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "manage:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "polyfills": ["zone.js", "zone.js/testing"], + "tsConfig": "projects/manage/tsconfig.spec.json", + "inlineStyleLanguage": "less", + "assets": ["projects/manage/src/favicon.ico", "projects/manage/src/assets"], + "styles": ["projects/manage/src/styles.less"], + "scripts": [] + } + } + } + }, + "cdk": { + "projectType": "library", + "root": "projects/cdk", + "sourceRoot": "projects/cdk/src", + "prefix": "dec", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/cdk/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/cdk/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/cdk/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/cdk/tsconfig.spec.json", + "polyfills": ["zone.js", "zone.js/testing"] + } + } + } + } + } +} diff --git a/doc.md b/doc.md new file mode 100644 index 0000000..8a84c17 --- /dev/null +++ b/doc.md @@ -0,0 +1,5 @@ +enableDetect => 0 开启 1 关闭 + +高级设置 + +数据分析 diff --git a/mock/index.ts b/mock/index.ts new file mode 100644 index 0000000..6372d46 --- /dev/null +++ b/mock/index.ts @@ -0,0 +1,38 @@ +import * as Mock from "mockjs"; + +Mock.setup({ + timeout: "200-600", +}); + +const UserMock = [ + { + Url: "/api/user/list", + Method: "get", + Res: { + "data|5-10": [ + { + "Id|+1": "@guid", + "Name|1": "@cname(2)", + }, + ], + }, + }, + { + Url: "/api/user/add", + Method: "post", + Res: { + "Id|1": "@guid", + "Name|1": "@cname()", + }, + }, +]; +// mock数据集 +const routerList = [...UserMock]; + +// 循环创建mock接口拦截数据 +routerList.forEach((e) => { + Mock.mock(e.Url, e.Method, e.Res); +}); + +// 导出Mock +export default Mock; diff --git a/package.json b/package.json new file mode 100644 index 0000000..e55b30c --- /dev/null +++ b/package.json @@ -0,0 +1,54 @@ +{ + "name": "dec-app", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start:client": "ng serve client --proxy-config ./projects/client/proxy.conf.json", + "build:client": "ng build client --vendor-chunk", + "start:manage": "ng serve manage --proxy-config ./projects/manage/proxy.conf.json", + "build:manage": "ng build manage --vendor-chunk", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "dependencies": { + "@angular/animations": "^15.2.0", + "@angular/cdk": "^15.2.6", + "@angular/common": "^15.2.0", + "@angular/compiler": "^15.2.0", + "@angular/core": "^15.2.0", + "@angular/forms": "^15.2.0", + "@angular/platform-browser": "^15.2.0", + "@angular/platform-browser-dynamic": "^15.2.0", + "@angular/router": "^15.2.0", + "@ant-design/icons-angular": "^15.0.0", + "@iplab/ngx-color-picker": "15", + "date-fns": "^2.30.0", + "echarts": "^5.4.2", + "immer": "^10.0.1", + "ng-zorro-antd": "15.1.0", + "ngx-permissions": "^15.0.1", + "rxjs": "~7.8.0", + "tslib": "^2.3.0", + "zone.js": "~0.12.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^15.2.6", + "@angular/cli": "~15.2.0", + "@angular/compiler-cli": "^15.2.0", + "@types/jasmine": "~4.3.0", + "@types/mockjs": "^1.0.7", + "autoprefixer": "^10.4.14", + "jasmine-core": "~4.5.0", + "karma": "~6.4.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.1.0", + "karma-jasmine-html-reporter": "~2.0.0", + "mockjs": "^1.1.0", + "ng-packagr": "^15.2.2", + "postcss": "^8.4.21", + "tailwindcss": "^3.3.1", + "typescript": "~4.9.4" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..b8cf7d7 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,7380 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@angular/animations': + specifier: ^15.2.0 + version: 15.2.7(@angular/core@15.2.7) + '@angular/cdk': + specifier: ^15.2.6 + version: 15.2.6(@angular/common@15.2.7)(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/common': + specifier: ^15.2.0 + version: 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/compiler': + specifier: ^15.2.0 + version: 15.2.7(@angular/core@15.2.7) + '@angular/core': + specifier: ^15.2.0 + version: 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/forms': + specifier: ^15.2.0 + version: 15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + '@angular/platform-browser': + specifier: ^15.2.0 + version: 15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + '@angular/platform-browser-dynamic': + specifier: ^15.2.0 + version: 15.2.7(@angular/common@15.2.7)(@angular/compiler@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7) + '@angular/router': + specifier: ^15.2.0 + version: 15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + '@ant-design/icons-angular': + specifier: ^15.0.0 + version: 15.0.0(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + '@iplab/ngx-color-picker': + specifier: '15' + version: 15.0.2(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + date-fns: + specifier: ^2.30.0 + version: 2.30.0 + echarts: + specifier: ^5.4.2 + version: 5.4.2 + immer: + specifier: ^10.0.1 + version: 10.0.1 + ng-zorro-antd: + specifier: 15.1.0 + version: 15.1.0(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/forms@15.2.7)(@angular/platform-browser@15.2.7)(@angular/router@15.2.7)(rxjs@7.8.0) + ngx-permissions: + specifier: ^15.0.1 + version: 15.0.1(@angular/core@15.2.7)(@angular/router@15.2.7)(rxjs@7.8.0) + rxjs: + specifier: ~7.8.0 + version: 7.8.0 + tslib: + specifier: ^2.3.0 + version: 2.5.0 + zone.js: + specifier: ~0.12.0 + version: 0.12.0 + +devDependencies: + '@angular-devkit/build-angular': + specifier: ^15.2.6 + version: 15.2.6(@angular/compiler-cli@15.2.7)(karma@6.4.1)(ng-packagr@15.2.2)(tailwindcss@3.3.1)(typescript@4.9.5) + '@angular/cli': + specifier: ~15.2.0 + version: 15.2.6 + '@angular/compiler-cli': + specifier: ^15.2.0 + version: 15.2.7(@angular/compiler@15.2.7)(typescript@4.9.5) + '@types/jasmine': + specifier: ~4.3.0 + version: 4.3.1 + '@types/mockjs': + specifier: ^1.0.7 + version: 1.0.7 + autoprefixer: + specifier: ^10.4.14 + version: 10.4.14(postcss@8.4.21) + jasmine-core: + specifier: ~4.5.0 + version: 4.5.0 + karma: + specifier: ~6.4.0 + version: 6.4.1 + karma-chrome-launcher: + specifier: ~3.1.0 + version: 3.1.1 + karma-coverage: + specifier: ~2.2.0 + version: 2.2.0 + karma-jasmine: + specifier: ~5.1.0 + version: 5.1.0(karma@6.4.1) + karma-jasmine-html-reporter: + specifier: ~2.0.0 + version: 2.0.0(jasmine-core@4.5.0)(karma-jasmine@5.1.0)(karma@6.4.1) + mockjs: + specifier: ^1.1.0 + version: 1.1.0 + ng-packagr: + specifier: ^15.2.2 + version: 15.2.2(@angular/compiler-cli@15.2.7)(tailwindcss@3.3.1)(tslib@2.5.0)(typescript@4.9.5) + postcss: + specifier: ^8.4.21 + version: 8.4.21 + tailwindcss: + specifier: ^3.3.1 + version: 3.3.1(postcss@8.4.21) + typescript: + specifier: ~4.9.4 + version: 4.9.5 + +packages: + + /@ampproject/remapping@2.2.0: + resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.1.1 + '@jridgewell/trace-mapping': 0.3.18 + dev: true + + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + dev: true + + /@angular-devkit/architect@0.1502.6(chokidar@3.5.3): + resolution: {integrity: sha512-n4oJ9vzFWwabf+AfgqqevVzdJhNKNCav7ytefjD/Y01vkNwlXqWnHcvyyHCLkVibJ6WR8J9lK4t77j/HFlDvWQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + dependencies: + '@angular-devkit/core': 15.2.6(chokidar@3.5.3) + rxjs: 6.6.7 + transitivePeerDependencies: + - chokidar + dev: true + + /@angular-devkit/build-angular@15.2.6(@angular/compiler-cli@15.2.7)(karma@6.4.1)(ng-packagr@15.2.2)(tailwindcss@3.3.1)(typescript@4.9.5): + resolution: {integrity: sha512-OmMcdXXUrAdZNxwxDE8SUx1FMcq9FyMnrSv1PmP9sHPBoxAdBVc/qNdGA9V7C5yHvWHGgzsx7ZK5TDuvifzS5g==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + '@angular/compiler-cli': ^15.0.0 + '@angular/localize': ^15.0.0 + '@angular/platform-server': ^15.0.0 + '@angular/service-worker': ^15.0.0 + karma: ^6.3.0 + ng-packagr: ^15.0.0 + protractor: ^7.0.0 + tailwindcss: ^2.0.0 || ^3.0.0 + typescript: '>=4.8.2 <5.0' + peerDependenciesMeta: + '@angular/localize': + optional: true + '@angular/platform-server': + optional: true + '@angular/service-worker': + optional: true + karma: + optional: true + ng-packagr: + optional: true + protractor: + optional: true + tailwindcss: + optional: true + dependencies: + '@ampproject/remapping': 2.2.0 + '@angular-devkit/architect': 0.1502.6(chokidar@3.5.3) + '@angular-devkit/build-webpack': 0.1502.6(chokidar@3.5.3)(webpack-dev-server@4.11.1)(webpack@5.76.1) + '@angular-devkit/core': 15.2.6(chokidar@3.5.3) + '@angular/compiler-cli': 15.2.7(@angular/compiler@15.2.7)(typescript@4.9.5) + '@babel/core': 7.20.12 + '@babel/generator': 7.20.14 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-transform-runtime': 7.19.6(@babel/core@7.20.12) + '@babel/preset-env': 7.20.2(@babel/core@7.20.12) + '@babel/runtime': 7.20.13 + '@babel/template': 7.20.7 + '@discoveryjs/json-ext': 0.5.7 + '@ngtools/webpack': 15.2.6(@angular/compiler-cli@15.2.7)(typescript@4.9.5)(webpack@5.76.1) + ansi-colors: 4.1.3 + autoprefixer: 10.4.13(postcss@8.4.21) + babel-loader: 9.1.2(@babel/core@7.20.12)(webpack@5.76.1) + babel-plugin-istanbul: 6.1.1 + browserslist: 4.21.5 + cacache: 17.0.4 + chokidar: 3.5.3 + copy-webpack-plugin: 11.0.0(webpack@5.76.1) + critters: 0.0.16 + css-loader: 6.7.3(webpack@5.76.1) + esbuild-wasm: 0.17.8 + glob: 8.1.0 + https-proxy-agent: 5.0.1 + inquirer: 8.2.4 + jsonc-parser: 3.2.0 + karma: 6.4.1 + karma-source-map-support: 1.4.0 + less: 4.1.3 + less-loader: 11.1.0(less@4.1.3)(webpack@5.76.1) + license-webpack-plugin: 4.0.2(webpack@5.76.1) + loader-utils: 3.2.1 + magic-string: 0.29.0 + mini-css-extract-plugin: 2.7.2(webpack@5.76.1) + ng-packagr: 15.2.2(@angular/compiler-cli@15.2.7)(tailwindcss@3.3.1)(tslib@2.5.0)(typescript@4.9.5) + open: 8.4.1 + ora: 5.4.1 + parse5-html-rewriting-stream: 7.0.0 + piscina: 3.2.0 + postcss: 8.4.21 + postcss-loader: 7.0.2(postcss@8.4.21)(webpack@5.76.1) + resolve-url-loader: 5.0.0 + rxjs: 6.6.7 + sass: 1.58.1 + sass-loader: 13.2.0(sass@1.58.1)(webpack@5.76.1) + semver: 7.3.8 + source-map-loader: 4.0.1(webpack@5.76.1) + source-map-support: 0.5.21 + tailwindcss: 3.3.1(postcss@8.4.21) + terser: 5.16.3 + text-table: 0.2.0 + tree-kill: 1.2.2 + tslib: 2.5.0 + typescript: 4.9.5 + webpack: 5.76.1(esbuild@0.17.8) + webpack-dev-middleware: 6.0.1(webpack@5.76.1) + webpack-dev-server: 4.11.1(webpack@5.76.1) + webpack-merge: 5.8.0 + webpack-subresource-integrity: 5.1.0(webpack@5.76.1) + optionalDependencies: + esbuild: 0.17.8 + transitivePeerDependencies: + - '@swc/core' + - bluebird + - bufferutil + - debug + - fibers + - html-webpack-plugin + - node-sass + - sass-embedded + - supports-color + - uglify-js + - utf-8-validate + - webpack-cli + dev: true + + /@angular-devkit/build-webpack@0.1502.6(chokidar@3.5.3)(webpack-dev-server@4.11.1)(webpack@5.76.1): + resolution: {integrity: sha512-X7XQ11QDz2Bs5qpJ3a5glIytvI+S74ORQxdzvT6a6KB8ayW0SgZEhTwD+GF7pa5My8draIaXBGzzQR1qmpWK5Q==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + webpack: ^5.30.0 + webpack-dev-server: ^4.0.0 + dependencies: + '@angular-devkit/architect': 0.1502.6(chokidar@3.5.3) + rxjs: 6.6.7 + webpack: 5.76.1(esbuild@0.17.8) + webpack-dev-server: 4.11.1(webpack@5.76.1) + transitivePeerDependencies: + - chokidar + dev: true + + /@angular-devkit/core@15.2.6(chokidar@3.5.3): + resolution: {integrity: sha512-YVTWZ+M+xNKdFX4EnY9QX49PZraawiaA0iTd2CUW8ZoTUvU7yOGMKZLSdz6aokTMRVfm0449wt6YL994ibOo1g==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^3.5.2 + peerDependenciesMeta: + chokidar: + optional: true + dependencies: + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + chokidar: 3.5.3 + jsonc-parser: 3.2.0 + rxjs: 6.6.7 + source-map: 0.7.4 + dev: true + + /@angular-devkit/schematics@15.2.6: + resolution: {integrity: sha512-f7VgnAcok7AwR/DhX0ZWskB0rFBo/KsvtIUA2qZSrpKMf8eFiwu03dv/b2mI0vnf+1FBfIQzJvO0ww45zRp6dA==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + dependencies: + '@angular-devkit/core': 15.2.6(chokidar@3.5.3) + jsonc-parser: 3.2.0 + magic-string: 0.29.0 + ora: 5.4.1 + rxjs: 6.6.7 + transitivePeerDependencies: + - chokidar + dev: true + + /@angular/animations@15.2.7(@angular/core@15.2.7): + resolution: {integrity: sha512-Vmy0AljHc/GOp87O2x0mxUDiyfJFW8ndDE9Xrm/g0rnLnNWsaLtLXr1TWbwF7eTqKA3k/QcUvYAjLMWKvjyKgQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/core': 15.2.7 + dependencies: + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + tslib: 2.5.0 + dev: false + + /@angular/cdk@15.2.6(@angular/common@15.2.7)(@angular/core@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-c6XFKMFowllHxb4tUt9en3bXBDqXKG2k4O9XGggJ1TL668d3Uhlk9qULywFNVWmNQSamkERmhFKAN4hEO3TPAQ==} + peerDependencies: + '@angular/common': ^15.0.0 || ^16.0.0 + '@angular/core': ^15.0.0 || ^16.0.0 + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + rxjs: 7.8.0 + tslib: 2.5.0 + optionalDependencies: + parse5: 7.1.2 + dev: false + + /@angular/cli@15.2.6: + resolution: {integrity: sha512-wNkQ/qCVbd4pERaGVagKJPifEvjRNY5otwsd4iRVubY/XOcIHcYChUThZwgQdVfNAImfJPMZNrhbGxejuWLA9w==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + dependencies: + '@angular-devkit/architect': 0.1502.6(chokidar@3.5.3) + '@angular-devkit/core': 15.2.6(chokidar@3.5.3) + '@angular-devkit/schematics': 15.2.6 + '@schematics/angular': 15.2.6 + '@yarnpkg/lockfile': 1.1.0 + ansi-colors: 4.1.3 + ini: 3.0.1 + inquirer: 8.2.4 + jsonc-parser: 3.2.0 + npm-package-arg: 10.1.0 + npm-pick-manifest: 8.0.1 + open: 8.4.1 + ora: 5.4.1 + pacote: 15.1.0 + resolve: 1.22.1 + semver: 7.3.8 + symbol-observable: 4.0.0 + yargs: 17.6.2 + transitivePeerDependencies: + - bluebird + - chokidar + - supports-color + dev: true + + /@angular/common@15.2.7(@angular/core@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-CbmrQeZ0yChQrF/ab3v+gv6x2uLbv/s1wZNUBSO/p1STz6BZzHRJqObVlfPlQvyBx5btBBy/+I1sUh1yumARDA==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/core': 15.2.7 + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + rxjs: 7.8.0 + tslib: 2.5.0 + dev: false + + /@angular/compiler-cli@15.2.7(@angular/compiler@15.2.7)(typescript@4.9.5): + resolution: {integrity: sha512-4v51dOaT8GDUzRh6+mCLZOaYuU9FYX6vOHaLod9np3tVWPhcpoF2ZklRSiQDeFqrhr5B4vuCp/Lh9N2wzc22XQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + hasBin: true + peerDependencies: + '@angular/compiler': 15.2.7 + typescript: '>=4.8.2 <5.0' + dependencies: + '@angular/compiler': 15.2.7(@angular/core@15.2.7) + '@babel/core': 7.19.3 + '@jridgewell/sourcemap-codec': 1.4.15 + chokidar: 3.5.3 + convert-source-map: 1.9.0 + dependency-graph: 0.11.0 + magic-string: 0.27.0 + reflect-metadata: 0.1.13 + semver: 7.4.0 + tslib: 2.5.0 + typescript: 4.9.5 + yargs: 17.7.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@angular/compiler@15.2.7(@angular/core@15.2.7): + resolution: {integrity: sha512-SesyYI2ExUa13XukXgIsmfg3ar90HbWeWDJTgmzsIfph0M9t6+SaPGpf3FCtdBgNADIpUFp3cieCOJgLESzxYQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/core': 15.2.7 + peerDependenciesMeta: + '@angular/core': + optional: true + dependencies: + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + tslib: 2.5.0 + + /@angular/core@15.2.7(rxjs@7.8.0)(zone.js@0.12.0): + resolution: {integrity: sha512-iS7JCJubRFqdndoUdAnvNkQRT3tY5tNFupBQS/sytkwxVrdBg+Is5jpdgk741n824vTMsE+CnuY0SETar8rN6g==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.11.4 || ~0.12.0 || ~0.13.0 + dependencies: + rxjs: 7.8.0 + tslib: 2.5.0 + zone.js: 0.12.0 + + /@angular/forms@15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-rzrebDIrtxxOeMcBzRBxqaOBZ+T1DJrysG/6YWZy428W/Z3MfPxUarPxgfx/oZI+x5uUsDaZmyoRdhVPJ2KhZg==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/common': 15.2.7 + '@angular/core': 15.2.7 + '@angular/platform-browser': 15.2.7 + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/platform-browser': 15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + rxjs: 7.8.0 + tslib: 2.5.0 + dev: false + + /@angular/platform-browser-dynamic@15.2.7(@angular/common@15.2.7)(@angular/compiler@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7): + resolution: {integrity: sha512-t1Nf7hgbcYvhmxuzgUtsV47jrI5CXUBqrtz5I0ilWG92zZTig5qvfd1/2Ub8NHz87uHNrnggyZpL2+4MJ26nyQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/common': 15.2.7 + '@angular/compiler': 15.2.7 + '@angular/core': 15.2.7 + '@angular/platform-browser': 15.2.7 + dependencies: + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/compiler': 15.2.7(@angular/core@15.2.7) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/platform-browser': 15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + tslib: 2.5.0 + dev: false + + /@angular/platform-browser@15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7): + resolution: {integrity: sha512-aCbd7xyuP7c2eDITkOTDO2mqP550WHCBN8U6VnjysqtB5ocbJtR6z/MIRItN/Zx+xj3piiaKei//XIkb3Q5fXQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/animations': 15.2.7 + '@angular/common': 15.2.7 + '@angular/core': 15.2.7 + peerDependenciesMeta: + '@angular/animations': + optional: true + dependencies: + '@angular/animations': 15.2.7(@angular/core@15.2.7) + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + tslib: 2.5.0 + dev: false + + /@angular/router@15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-Wkk+oJSUrVafJjmv9uE1SoY4wDE9bjX7ald+UXePz+QyM/PFoLkm/CzLYjFBkJnsOkOVxw1VmvacoUjWN6BCTQ==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + peerDependencies: + '@angular/common': 15.2.7 + '@angular/core': 15.2.7 + '@angular/platform-browser': 15.2.7 + rxjs: ^6.5.3 || ^7.4.0 + dependencies: + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/platform-browser': 15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + rxjs: 7.8.0 + tslib: 2.5.0 + dev: false + + /@ant-design/colors@5.1.1: + resolution: {integrity: sha512-Txy4KpHrp3q4XZdfgOBqLl+lkQIc3tEvHXOimRN1giX1AEC7mGtyrO9p8iRGJ3FLuVMGa2gNEzQyghVymLttKQ==} + dependencies: + '@ctrl/tinycolor': 3.6.0 + dev: false + + /@ant-design/icons-angular@15.0.0(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-9DMpuoqZBvS7+VJ0s3tl2g/kI1sTLDQWfykiXYa+AkZ2AvJwHebvR7Cw7/xfiXFDLyZTjPgtC0x0gex13EShuA==} + peerDependencies: + '@angular/common': ^15.0.0 + '@angular/core': ^15.0.0 + '@angular/platform-browser': ^15.0.0 + rxjs: ^6.4.0 || ^7.4.0 + dependencies: + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/platform-browser': 15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + '@ant-design/colors': 5.1.1 + rxjs: 7.8.0 + tslib: 2.5.0 + dev: false + + /@assemblyscript/loader@0.10.1: + resolution: {integrity: sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==} + dev: true + + /@babel/code-frame@7.21.4: + resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + dev: true + + /@babel/compat-data@7.21.4: + resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.19.3: + resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.19.3) + '@babel/helper-module-transforms': 7.21.2 + '@babel/helpers': 7.21.0 + '@babel/parser': 7.21.4 + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + convert-source-map: 1.9.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/core@7.20.12: + resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.12) + '@babel/helper-module-transforms': 7.21.2 + '@babel/helpers': 7.21.0 + '@babel/parser': 7.21.4 + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + convert-source-map: 1.9.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/core@7.21.4: + resolution: {integrity: sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) + '@babel/helper-module-transforms': 7.21.2 + '@babel/helpers': 7.21.0 + '@babel/parser': 7.21.4 + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + convert-source-map: 1.9.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.20.14: + resolution: {integrity: sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + '@jridgewell/gen-mapping': 0.3.3 + jsesc: 2.5.2 + dev: true + + /@babel/generator@7.21.4: + resolution: {integrity: sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + jsesc: 2.5.2 + dev: true + + /@babel/helper-annotate-as-pure@7.18.6: + resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: + resolution: {integrity: sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-explode-assignable-expression': 7.18.6 + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-compilation-targets@7.21.4(@babel/core@7.19.3): + resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.21.4 + '@babel/core': 7.19.3 + '@babel/helper-validator-option': 7.21.0 + browserslist: 4.21.5 + lru-cache: 5.1.1 + semver: 6.3.0 + dev: true + + /@babel/helper-compilation-targets@7.21.4(@babel/core@7.20.12): + resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.21.4 + '@babel/core': 7.20.12 + '@babel/helper-validator-option': 7.21.0 + browserslist: 4.21.5 + lru-cache: 5.1.1 + semver: 6.3.0 + dev: true + + /@babel/helper-compilation-targets@7.21.4(@babel/core@7.21.4): + resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.21.4 + '@babel/core': 7.21.4 + '@babel/helper-validator-option': 7.21.0 + browserslist: 4.21.5 + lru-cache: 5.1.1 + semver: 6.3.0 + dev: true + + /@babel/helper-create-class-features-plugin@7.21.4(@babel/core@7.20.12): + resolution: {integrity: sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.21.0 + '@babel/helper-member-expression-to-functions': 7.21.0 + '@babel/helper-optimise-call-expression': 7.18.6 + '@babel/helper-replace-supers': 7.20.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/helper-split-export-declaration': 7.18.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-create-regexp-features-plugin@7.21.4(@babel/core@7.20.12): + resolution: {integrity: sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.18.6 + regexpu-core: 5.3.2 + dev: true + + /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.20.12): + resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} + peerDependencies: + '@babel/core': ^7.4.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + debug: 4.3.4 + lodash.debounce: 4.0.8 + resolve: 1.22.1 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-environment-visitor@7.18.9: + resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-explode-assignable-expression@7.18.6: + resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-function-name@7.21.0: + resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.20.7 + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-hoist-variables@7.18.6: + resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-member-expression-to-functions@7.21.0: + resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-module-imports@7.21.4: + resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-module-transforms@7.21.2: + resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-module-imports': 7.21.4 + '@babel/helper-simple-access': 7.20.2 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/helper-validator-identifier': 7.19.1 + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-optimise-call-expression@7.18.6: + resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-plugin-utils@7.20.2: + resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-wrap-function': 7.20.5 + '@babel/types': 7.21.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-replace-supers@7.20.7: + resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-member-expression-to-functions': 7.21.0 + '@babel/helper-optimise-call-expression': 7.18.6 + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-simple-access@7.20.2: + resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-skip-transparent-expression-wrappers@7.20.0: + resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-split-export-declaration@7.18.6: + resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/helper-string-parser@7.19.4: + resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-identifier@7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option@7.21.0: + resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-wrap-function@7.20.5: + resolution: {integrity: sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-function-name': 7.21.0 + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helpers@7.21.0: + resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.20.7 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight@7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser@7.21.4: + resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.21.4 + dev: true + + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.20.12): + resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.21.4 + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.20.12): + resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) + dev: true + + /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.20.12): + resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-create-class-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} + engines: {node: '>=4'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.20.12): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.20.12): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.20.12): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.20.12): + resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.20.12): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.20.12): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.20.12): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.20.12): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.20.12): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-imports': 7.21.4 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.20.12): + resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-classes@7.21.0(@babel/core@7.20.12): + resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.12) + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.21.0 + '@babel/helper-optimise-call-expression': 7.18.6 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-replace-supers': 7.20.7 + '@babel/helper-split-export-declaration': 7.18.6 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/template': 7.20.7 + dev: true + + /@babel/plugin-transform-destructuring@7.21.3(@babel/core@7.20.12): + resolution: {integrity: sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.20.12): + resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.12) + '@babel/helper-function-name': 7.21.0 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-literals@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.20.12): + resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.20.12): + resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-simple-access': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.20.12): + resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-validator-identifier': 7.19.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.20.12): + resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-replace-supers': 7.20.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-parameters@7.21.3(@babel/core@7.20.12): + resolution: {integrity: sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.20.12): + resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + regenerator-transform: 0.15.1 + dev: true + + /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-runtime@7.19.6(@babel/core@7.20.12): + resolution: {integrity: sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-imports': 7.21.4 + '@babel/helper-plugin-utils': 7.20.2 + babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.20.12) + babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.20.12) + babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.20.12) + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-spread@7.20.7(@babel/core@7.20.12): + resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + dev: true + + /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.20.12): + resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.20.12): + resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.20.12): + resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/preset-env@7.20.2(@babel/core@7.20.12): + resolution: {integrity: sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.21.4 + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-validator-option': 7.21.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-class-static-block': 7.21.0(@babel/core@7.20.12) + '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.20.12) + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.20.12) + '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.20.12) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.20.12) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.20.12) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.20.12) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.20.12) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.20.12) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.20.12) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.20.12) + '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.20.12) + '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.20.12) + '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-transform-destructuring': 7.21.3(@babel/core@7.20.12) + '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-for-of': 7.21.0(@babel/core@7.20.12) + '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.20.12) + '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.20.12) + '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.20.12) + '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.20.12) + '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.20.12) + '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.20.12) + '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.20.12) + '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.20.12) + '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.20.12) + '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.20.12) + '@babel/preset-modules': 0.1.5(@babel/core@7.20.12) + '@babel/types': 7.21.4 + babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.20.12) + babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.20.12) + babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.20.12) + core-js-compat: 3.30.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-modules@0.1.5(@babel/core@7.20.12): + resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.20.12) + '@babel/types': 7.21.4 + esutils: 2.0.3 + dev: true + + /@babel/regjsgen@0.8.0: + resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + dev: true + + /@babel/runtime@7.20.13: + resolution: {integrity: sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.11 + dev: true + + /@babel/runtime@7.21.5: + resolution: {integrity: sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.13.11 + + /@babel/template@7.20.7: + resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.21.4 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 + dev: true + + /@babel/traverse@7.21.4: + resolution: {integrity: sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.21.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types@7.21.4: + resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.19.4 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + dev: true + + /@colors/colors@1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + dev: true + + /@ctrl/tinycolor@3.6.0: + resolution: {integrity: sha512-/Z3l6pXthq0JvMYdUFyX9j0MaCltlIn6mfh9jLyQwg5aPKxkyNa0PTHtU1AlFXLNk55ZuAeJRcpvq+tmLfKmaQ==} + engines: {node: '>=10'} + dev: false + + /@discoveryjs/json-ext@0.5.7: + resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} + engines: {node: '>=10.0.0'} + dev: true + + /@esbuild/android-arm64@0.17.8: + resolution: {integrity: sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.17.8: + resolution: {integrity: sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.17.8: + resolution: {integrity: sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.17.8: + resolution: {integrity: sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.17.8: + resolution: {integrity: sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.17.8: + resolution: {integrity: sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.17.8: + resolution: {integrity: sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.17.8: + resolution: {integrity: sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.17.8: + resolution: {integrity: sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.17.8: + resolution: {integrity: sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.17.8: + resolution: {integrity: sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.17.8: + resolution: {integrity: sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.17.8: + resolution: {integrity: sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.17.8: + resolution: {integrity: sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.17.8: + resolution: {integrity: sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.17.8: + resolution: {integrity: sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.17.8: + resolution: {integrity: sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.17.8: + resolution: {integrity: sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.17.8: + resolution: {integrity: sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.17.8: + resolution: {integrity: sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.17.8: + resolution: {integrity: sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.17.8: + resolution: {integrity: sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@gar/promisify@1.1.3: + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + dev: true + + /@iplab/ngx-color-picker@15.0.2(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7): + resolution: {integrity: sha512-wum0Hg4Ky/6mhvzolEpFpjGckOjN8L2nkXvy3mWUVclFHP9MZqqgpJaxghtax7/tMdEWQnwQI3PYsNyKfF15ug==} + peerDependencies: + '@angular/animations': ^15.0.0 + '@angular/common': ^15.0.0 + '@angular/core': ^15.0.0 + dependencies: + '@angular/animations': 15.2.7(@angular/core@15.2.7) + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + tslib: 2.5.0 + dev: false + + /@istanbuljs/load-nyc-config@1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jridgewell/gen-mapping@0.1.1: + resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /@jridgewell/gen-mapping@0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.18 + dev: true + + /@jridgewell/resolve-uri@3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/set-array@1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/source-map@0.3.3: + resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + dev: true + + /@jridgewell/sourcemap-codec@1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + dev: true + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + + /@jridgewell/trace-mapping@0.3.18: + resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + + /@leichtgewicht/ip-codec@2.0.4: + resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} + dev: true + + /@ngtools/webpack@15.2.6(@angular/compiler-cli@15.2.7)(typescript@4.9.5)(webpack@5.76.1): + resolution: {integrity: sha512-I+kekKItfsCLdX+ZjjmsWqd0AyoYGTQPjlbQAiPtmdH73/rfPOF4Q/3AU4tzTdn0n0GXqZWv6VOs91w99ydi0A==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + '@angular/compiler-cli': ^15.0.0 + typescript: '>=4.8.2 <5.0' + webpack: ^5.54.0 + dependencies: + '@angular/compiler-cli': 15.2.7(@angular/compiler@15.2.7)(typescript@4.9.5) + typescript: 4.9.5 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@npmcli/fs@2.1.2: + resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.4.0 + dev: true + + /@npmcli/fs@3.1.0: + resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + semver: 7.4.0 + dev: true + + /@npmcli/git@4.0.4: + resolution: {integrity: sha512-5yZghx+u5M47LghaybLCkdSyFzV/w4OuH12d96HO389Ik9CDsLaDZJVynSGGVJOLn6gy/k7Dz5XYcplM3uxXRg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/promise-spawn': 6.0.2 + lru-cache: 7.18.3 + npm-pick-manifest: 8.0.1 + proc-log: 3.0.0 + promise-inflight: 1.0.1 + promise-retry: 2.0.1 + semver: 7.4.0 + which: 3.0.0 + transitivePeerDependencies: + - bluebird + dev: true + + /@npmcli/installed-package-contents@2.0.2: + resolution: {integrity: sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + npm-bundled: 3.0.0 + npm-normalize-package-bin: 3.0.0 + dev: true + + /@npmcli/move-file@2.0.1: + resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + dev: true + + /@npmcli/node-gyp@3.0.0: + resolution: {integrity: sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /@npmcli/promise-spawn@6.0.2: + resolution: {integrity: sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + which: 3.0.0 + dev: true + + /@npmcli/run-script@6.0.0: + resolution: {integrity: sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/node-gyp': 3.0.0 + '@npmcli/promise-spawn': 6.0.2 + node-gyp: 9.3.1 + read-package-json-fast: 3.0.2 + which: 3.0.0 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /@rollup/plugin-json@6.0.0(rollup@3.20.6): + resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.2(rollup@3.20.6) + rollup: 3.20.6 + dev: true + + /@rollup/plugin-node-resolve@15.0.2(rollup@3.20.6): + resolution: {integrity: sha512-Y35fRGUjC3FaurG722uhUuG8YHOJRJQbI6/CkbRkdPotSpDj9NtIN85z1zrcyDcCQIW4qp5mgG72U+gJ0TAFEg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.2(rollup@3.20.6) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-builtin-module: 3.2.1 + is-module: 1.0.0 + resolve: 1.22.1 + rollup: 3.20.6 + dev: true + + /@rollup/pluginutils@5.0.2(rollup@3.20.6): + resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + rollup: 3.20.6 + dev: true + + /@schematics/angular@15.2.6: + resolution: {integrity: sha512-OcBUvVAxZEMBX+fi0ytybeAdmStra+GwtlvipS70yOxcAgJ84ZrnZGN7a072cCVQcq7AgqUfssnyqCx1wu+yCg==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + dependencies: + '@angular-devkit/core': 15.2.6(chokidar@3.5.3) + '@angular-devkit/schematics': 15.2.6 + jsonc-parser: 3.2.0 + transitivePeerDependencies: + - chokidar + dev: true + + /@sigstore/protobuf-specs@0.1.0: + resolution: {integrity: sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /@socket.io/component-emitter@3.1.0: + resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + dev: true + + /@tootallnate/once@2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + dev: true + + /@tufjs/canonical-json@1.0.0: + resolution: {integrity: sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /@tufjs/models@1.0.2: + resolution: {integrity: sha512-uxarDtxTIK3f8hJS4yFhW/lvTa3tsiQU5iDCRut+NCnOXvNtEul0Ct58NIIcIx9Rkt7OFEK31Ndpqsd663nsew==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@tufjs/canonical-json': 1.0.0 + minimatch: 8.0.4 + dev: true + + /@types/body-parser@1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 18.15.11 + dev: true + + /@types/bonjour@3.5.10: + resolution: {integrity: sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==} + dependencies: + '@types/node': 18.15.11 + dev: true + + /@types/connect-history-api-fallback@1.3.5: + resolution: {integrity: sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==} + dependencies: + '@types/express-serve-static-core': 4.17.33 + '@types/node': 18.15.11 + dev: true + + /@types/connect@3.4.35: + resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + dependencies: + '@types/node': 18.15.11 + dev: true + + /@types/cookie@0.4.1: + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + dev: true + + /@types/cors@2.8.13: + resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} + dependencies: + '@types/node': 18.15.11 + dev: true + + /@types/eslint-scope@3.7.4: + resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} + dependencies: + '@types/eslint': 8.37.0 + '@types/estree': 0.0.51 + dev: true + + /@types/eslint@8.37.0: + resolution: {integrity: sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==} + dependencies: + '@types/estree': 0.0.51 + '@types/json-schema': 7.0.11 + dev: true + + /@types/estree@0.0.51: + resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} + dev: true + + /@types/estree@1.0.1: + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + dev: true + + /@types/express-serve-static-core@4.17.33: + resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} + dependencies: + '@types/node': 18.15.11 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + dev: true + + /@types/express@4.17.17: + resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.33 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.1 + dev: true + + /@types/http-proxy@1.17.10: + resolution: {integrity: sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==} + dependencies: + '@types/node': 18.15.11 + dev: true + + /@types/jasmine@4.3.1: + resolution: {integrity: sha512-Vu8l+UGcshYmV1VWwULgnV/2RDbBaO6i2Ptx7nd//oJPIZGhoI1YLST4VKagD2Pq/Bc2/7zvtvhM7F3p4SN7kQ==} + dev: true + + /@types/json-schema@7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true + + /@types/mime@3.0.1: + resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + dev: true + + /@types/mockjs@1.0.7: + resolution: {integrity: sha512-OCxXz6hEaJOVpRwuJMiVY5a6LtJcih+br9gwB/Q8ooOBikvk5FpBQ31OlNimXo3EqKha1Z7PFBni+q9m+8NCWg==} + dev: true + + /@types/node@18.15.11: + resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==} + dev: true + + /@types/parse-json@4.0.0: + resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + dev: true + + /@types/qs@6.9.7: + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + dev: true + + /@types/range-parser@1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + dev: true + + /@types/resolve@1.20.2: + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + dev: true + + /@types/retry@0.12.0: + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: true + + /@types/serve-index@1.9.1: + resolution: {integrity: sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==} + dependencies: + '@types/express': 4.17.17 + dev: true + + /@types/serve-static@1.15.1: + resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} + dependencies: + '@types/mime': 3.0.1 + '@types/node': 18.15.11 + dev: true + + /@types/sockjs@0.3.33: + resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} + dependencies: + '@types/node': 18.15.11 + dev: true + + /@types/ws@8.5.4: + resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} + dependencies: + '@types/node': 18.15.11 + dev: true + + /@webassemblyjs/ast@1.11.1: + resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} + dependencies: + '@webassemblyjs/helper-numbers': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + dev: true + + /@webassemblyjs/floating-point-hex-parser@1.11.1: + resolution: {integrity: sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==} + dev: true + + /@webassemblyjs/helper-api-error@1.11.1: + resolution: {integrity: sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==} + dev: true + + /@webassemblyjs/helper-buffer@1.11.1: + resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==} + dev: true + + /@webassemblyjs/helper-numbers@1.11.1: + resolution: {integrity: sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==} + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.11.1 + '@webassemblyjs/helper-api-error': 1.11.1 + '@xtuc/long': 4.2.2 + dev: true + + /@webassemblyjs/helper-wasm-bytecode@1.11.1: + resolution: {integrity: sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==} + dev: true + + /@webassemblyjs/helper-wasm-section@1.11.1: + resolution: {integrity: sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-buffer': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/wasm-gen': 1.11.1 + dev: true + + /@webassemblyjs/ieee754@1.11.1: + resolution: {integrity: sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==} + dependencies: + '@xtuc/ieee754': 1.2.0 + dev: true + + /@webassemblyjs/leb128@1.11.1: + resolution: {integrity: sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==} + dependencies: + '@xtuc/long': 4.2.2 + dev: true + + /@webassemblyjs/utf8@1.11.1: + resolution: {integrity: sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==} + dev: true + + /@webassemblyjs/wasm-edit@1.11.1: + resolution: {integrity: sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-buffer': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/helper-wasm-section': 1.11.1 + '@webassemblyjs/wasm-gen': 1.11.1 + '@webassemblyjs/wasm-opt': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + '@webassemblyjs/wast-printer': 1.11.1 + dev: true + + /@webassemblyjs/wasm-gen@1.11.1: + resolution: {integrity: sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/ieee754': 1.11.1 + '@webassemblyjs/leb128': 1.11.1 + '@webassemblyjs/utf8': 1.11.1 + dev: true + + /@webassemblyjs/wasm-opt@1.11.1: + resolution: {integrity: sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-buffer': 1.11.1 + '@webassemblyjs/wasm-gen': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + dev: true + + /@webassemblyjs/wasm-parser@1.11.1: + resolution: {integrity: sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/helper-api-error': 1.11.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/ieee754': 1.11.1 + '@webassemblyjs/leb128': 1.11.1 + '@webassemblyjs/utf8': 1.11.1 + dev: true + + /@webassemblyjs/wast-printer@1.11.1: + resolution: {integrity: sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==} + dependencies: + '@webassemblyjs/ast': 1.11.1 + '@xtuc/long': 4.2.2 + dev: true + + /@xtuc/ieee754@1.2.0: + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + dev: true + + /@xtuc/long@4.2.2: + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + dev: true + + /@yarnpkg/lockfile@1.1.0: + resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} + dev: true + + /abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + dev: true + + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + + /accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + dev: true + + /acorn-import-assertions@1.8.0(acorn@8.8.2): + resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==} + peerDependencies: + acorn: ^8 + dependencies: + acorn: 8.8.2 + dev: true + + /acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /adjust-sourcemap-loader@4.0.0: + resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} + engines: {node: '>=8.9'} + dependencies: + loader-utils: 2.0.4 + regex-parser: 2.2.11 + dev: true + + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /agentkeepalive@4.3.0: + resolution: {integrity: sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==} + engines: {node: '>= 8.0.0'} + dependencies: + debug: 4.3.4 + depd: 2.0.0 + humanize-ms: 1.2.1 + transitivePeerDependencies: + - supports-color + dev: true + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /ajv-formats@2.1.1(ajv@8.12.0): + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + dependencies: + ajv: 8.12.0 + dev: true + + /ajv-keywords@3.5.2(ajv@6.12.6): + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + dependencies: + ajv: 6.12.6 + dev: true + + /ajv-keywords@5.1.0(ajv@8.12.0): + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + dependencies: + ajv: 8.12.0 + fast-deep-equal: 3.1.3 + dev: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + 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 + dev: true + + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-html-community@0.0.8: + resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} + engines: {'0': node >= 0.8.0} + hasBin: true + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: true + + /are-we-there-yet@3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + dev: true + + /array-flatten@2.1.2: + resolution: {integrity: sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==} + dev: true + + /autoprefixer@10.4.13(postcss@8.4.21): + resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.21.5 + caniuse-lite: 1.0.30001478 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.21 + postcss-value-parser: 4.2.0 + dev: true + + /autoprefixer@10.4.14(postcss@8.4.21): + resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.21.5 + caniuse-lite: 1.0.30001478 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.21 + postcss-value-parser: 4.2.0 + dev: true + + /babel-loader@9.1.2(@babel/core@7.20.12)(webpack@5.76.1): + resolution: {integrity: sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==} + engines: {node: '>= 14.15.0'} + peerDependencies: + '@babel/core': ^7.12.0 + webpack: '>=5' + dependencies: + '@babel/core': 7.20.12 + find-cache-dir: 3.3.2 + schema-utils: 4.0.0 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.20.2 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.20.12): + resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.21.4 + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.20.12) + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.20.12): + resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.20.12) + core-js-compat: 3.30.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.20.12): + resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + dev: true + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + dev: true + + /batch@0.6.1: + resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + dev: true + + /big.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: true + + /body-parser@1.20.1: + resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /bonjour-service@1.1.1: + resolution: {integrity: sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==} + dependencies: + array-flatten: 2.1.2 + dns-equal: 1.0.0 + fast-deep-equal: 3.1.3 + multicast-dns: 7.2.5 + dev: true + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browserslist@4.21.5: + resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001478 + electron-to-chromium: 1.4.361 + node-releases: 2.0.10 + update-browserslist-db: 1.0.10(browserslist@4.21.5) + dev: true + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + dev: true + + /builtins@5.0.1: + resolution: {integrity: sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==} + dependencies: + semver: 7.4.0 + dev: true + + /bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + dev: true + + /bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + dev: true + + /cacache@16.1.3: + resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + '@npmcli/fs': 2.1.2 + '@npmcli/move-file': 2.0.1 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 8.1.0 + infer-owner: 1.0.4 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 9.0.1 + tar: 6.1.13 + unique-filename: 2.0.1 + transitivePeerDependencies: + - bluebird + dev: true + + /cacache@17.0.4: + resolution: {integrity: sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/fs': 3.1.0 + fs-minipass: 3.0.1 + glob: 8.1.0 + lru-cache: 7.18.3 + minipass: 4.2.8 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + ssri: 10.0.3 + tar: 6.1.13 + unique-filename: 3.0.0 + transitivePeerDependencies: + - bluebird + dev: true + + /cacache@17.0.5: + resolution: {integrity: sha512-Y/PRQevNSsjAPWykl9aeGz8Pr+OI6BYM9fYDNMvOkuUiG9IhG4LEmaYrZZZvioMUEQ+cBCxT0v8wrnCURccyKA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/fs': 3.1.0 + fs-minipass: 3.0.1 + glob: 9.3.5 + lru-cache: 7.18.3 + minipass: 4.2.8 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + ssri: 10.0.3 + tar: 6.1.13 + unique-filename: 3.0.0 + transitivePeerDependencies: + - bluebird + dev: true + + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.0 + dev: true + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + dev: true + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /caniuse-lite@1.0.30001478: + resolution: {integrity: sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==} + dev: true + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + 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.2 + dev: true + + /chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: true + + /chrome-trace-event@1.0.3: + resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} + engines: {node: '>=6.0'} + dev: true + + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-spinners@2.8.0: + resolution: {integrity: sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==} + engines: {node: '>=6'} + dev: true + + /cli-width@3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + dev: true + + /cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + dev: true + + /clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: true + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: true + + /colorette@2.0.19: + resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} + dev: true + + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + dev: true + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + + /commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + dev: true + + /compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /compression@1.7.4: + resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + bytes: 3.0.0 + compressible: 2.0.18 + debug: 2.6.9 + on-headers: 1.0.2 + safe-buffer: 5.1.2 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + dev: true + + /connect-history-api-fallback@2.0.0: + resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} + engines: {node: '>=0.8'} + dev: true + + /connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: true + + /content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + dev: true + + /convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: true + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + + /cookie-signature@1.0.6: + resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=} + dev: true + + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: true + + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: true + + /copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + dependencies: + is-what: 3.14.1 + dev: true + + /copy-webpack-plugin@11.0.0(webpack@5.76.1): + resolution: {integrity: sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==} + engines: {node: '>= 14.15.0'} + peerDependencies: + webpack: ^5.1.0 + dependencies: + fast-glob: 3.2.12 + glob-parent: 6.0.2 + globby: 13.1.4 + normalize-path: 3.0.0 + schema-utils: 4.0.0 + serialize-javascript: 6.0.1 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /core-js-compat@3.30.0: + resolution: {integrity: sha512-P5A2h/9mRYZFIAP+5Ab8ns6083IyVpSclU74UNvbGVQ8VM7n3n3/g2yF3AkKQ9NXz2O+ioxLbEWKnDtgsFamhg==} + dependencies: + browserslist: 4.21.5 + dev: true + + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: true + + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.0 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + + /critters@0.0.16: + resolution: {integrity: sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==} + dependencies: + chalk: 4.1.2 + css-select: 4.3.0 + parse5: 6.0.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + postcss: 8.4.21 + pretty-bytes: 5.6.0 + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /css-loader@6.7.3(webpack@5.76.1): + resolution: {integrity: sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + dependencies: + icss-utils: 5.1.0(postcss@8.4.21) + postcss: 8.4.21 + postcss-modules-extract-imports: 3.0.0(postcss@8.4.21) + postcss-modules-local-by-default: 4.0.0(postcss@8.4.21) + postcss-modules-scope: 3.0.0(postcss@8.4.21) + postcss-modules-values: 4.0.0(postcss@8.4.21) + postcss-value-parser: 4.2.0 + semver: 7.4.0 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + dev: true + + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: true + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /cuint@0.2.2: + resolution: {integrity: sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==} + dev: true + + /custom-event@1.0.1: + resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==} + dev: true + + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.21.5 + dev: false + + /date-format@4.0.14: + resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} + engines: {node: '>=4.0'} + dev: true + + /debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: true + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + optional: true + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: true + + /default-gateway@6.0.3: + resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} + engines: {node: '>= 10'} + dependencies: + execa: 5.1.1 + dev: true + + /defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + dependencies: + clone: 1.0.4 + dev: true + + /define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + dev: true + + /delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: true + + /depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + dev: true + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: true + + /dependency-graph@0.11.0: + resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==} + engines: {node: '>= 0.6.0'} + dev: true + + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dev: true + + /detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + dev: true + + /di@0.0.1: + resolution: {integrity: sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==} + dev: true + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + + /dns-equal@1.0.0: + resolution: {integrity: sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==} + dev: true + + /dns-packet@5.5.0: + resolution: {integrity: sha512-USawdAUzRkV6xrqTjiAEp6M9YagZEzWcSUaZTcIFAiyQWW1SoI6KyId8y2+/71wbgHKQAKd+iupLv4YvEwYWvA==} + engines: {node: '>=6'} + dependencies: + '@leichtgewicht/ip-codec': 2.0.4 + dev: true + + /dom-serialize@2.2.1: + resolution: {integrity: sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==} + dependencies: + custom-event: 1.0.1 + ent: 2.2.0 + extend: 3.0.2 + void-elements: 2.0.1 + dev: true + + /dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + dev: true + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + + /domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dev: true + + /echarts@5.4.2: + resolution: {integrity: sha512-2W3vw3oI2tWJdyAz+b8DuWS0nfXtSDqlDmqgin/lfzbkB01cuMEN66KWBlmur3YMp5nEDEEt5s23pllnAzB4EA==} + dependencies: + tslib: 2.3.0 + zrender: 5.4.3 + dev: false + + /ee-first@1.1.1: + resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} + dev: true + + /electron-to-chromium@1.4.361: + resolution: {integrity: sha512-VocVwjPp05HUXzf3xmL0boRn5b0iyqC7amtDww84Jb1QJNPBc7F69gJyEeXRoriLBC4a5pSyckdllrXAg4mmRA==} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emojis-list@3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + dev: true + + /encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + dev: true + + /encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + requiresBuild: true + dependencies: + iconv-lite: 0.6.3 + dev: true + optional: true + + /engine.io-parser@5.0.6: + resolution: {integrity: sha512-tjuoZDMAdEhVnSFleYPCtdL2GXwVTGtNjoeJd9IhIG3C1xs9uwxqRNEu5WpnDZCaozwVlK/nuQhpodhXSIMaxw==} + engines: {node: '>=10.0.0'} + dev: true + + /engine.io@6.4.1: + resolution: {integrity: sha512-JFYQurD/nbsA5BSPmbaOSLa3tSVj8L6o4srSwXXY3NqE+gGUNmmPTbhn8tjzcCtSqhFgIeqef81ngny8JM25hw==} + engines: {node: '>=10.0.0'} + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.13 + '@types/node': 18.15.11 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.2 + cors: 2.8.5 + debug: 4.3.4 + engine.io-parser: 5.0.6 + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /enhanced-resolve@5.12.0: + resolution: {integrity: sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==} + engines: {node: '>=10.13.0'} + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + dev: true + + /ent@2.2.0: + resolution: {integrity: sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==} + dev: true + + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: true + + /entities@4.4.0: + resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} + engines: {node: '>=0.12'} + + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: true + + /err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + dev: true + + /errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + requiresBuild: true + dependencies: + prr: 1.0.1 + dev: true + optional: true + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es-module-lexer@0.9.3: + resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} + dev: true + + /esbuild-wasm@0.17.8: + resolution: {integrity: sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==} + engines: {node: '>=12'} + hasBin: true + dev: true + + /esbuild@0.17.8: + resolution: {integrity: sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.17.8 + '@esbuild/android-arm64': 0.17.8 + '@esbuild/android-x64': 0.17.8 + '@esbuild/darwin-arm64': 0.17.8 + '@esbuild/darwin-x64': 0.17.8 + '@esbuild/freebsd-arm64': 0.17.8 + '@esbuild/freebsd-x64': 0.17.8 + '@esbuild/linux-arm': 0.17.8 + '@esbuild/linux-arm64': 0.17.8 + '@esbuild/linux-ia32': 0.17.8 + '@esbuild/linux-loong64': 0.17.8 + '@esbuild/linux-mips64el': 0.17.8 + '@esbuild/linux-ppc64': 0.17.8 + '@esbuild/linux-riscv64': 0.17.8 + '@esbuild/linux-s390x': 0.17.8 + '@esbuild/linux-x64': 0.17.8 + '@esbuild/netbsd-x64': 0.17.8 + '@esbuild/openbsd-x64': 0.17.8 + '@esbuild/sunos-x64': 0.17.8 + '@esbuild/win32-arm64': 0.17.8 + '@esbuild/win32-ia32': 0.17.8 + '@esbuild/win32-x64': 0.17.8 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + dev: true + + /eventemitter-asyncresource@1.0.0: + resolution: {integrity: sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==} + dev: true + + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: true + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: true + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /express@4.18.2: + resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: true + + /external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + dev: true + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + 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.5 + dev: true + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + dependencies: + websocket-driver: 0.7.4 + dev: true + + /figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + dev: true + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + dev: true + + /follow-redirects@1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: true + + /forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: true + + /fraction.js@4.2.0: + resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} + dev: true + + /fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + dev: true + + /fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: true + + /fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: true + + /fs-minipass@3.0.1: + resolution: {integrity: sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 4.2.8 + dev: true + + /fs-monkey@1.0.3: + resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true + + /fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + dev: true + + /gauge@4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: true + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 + dev: true + + /get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + + /glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + + /glob@9.3.5: + resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + fs.realpath: 1.0.0 + minimatch: 8.0.4 + minipass: 4.2.8 + path-scurry: 1.6.4 + dev: true + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globby@13.1.4: + resolution: {integrity: sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.2.12 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + + /handle-thing@2.0.1: + resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} + dev: true + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: true + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: true + + /has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + dev: true + + /hdr-histogram-js@2.0.3: + resolution: {integrity: sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==} + dependencies: + '@assemblyscript/loader': 0.10.1 + base64-js: 1.5.1 + pako: 1.0.11 + dev: true + + /hdr-histogram-percentiles-obj@3.0.0: + resolution: {integrity: sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==} + dev: true + + /hosted-git-info@6.1.1: + resolution: {integrity: sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + lru-cache: 7.18.3 + dev: true + + /hpack.js@2.1.6: + resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} + dependencies: + inherits: 2.0.4 + obuf: 1.1.2 + readable-stream: 2.3.8 + wbuf: 1.7.3 + dev: true + + /html-entities@2.3.3: + resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} + dev: true + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: true + + /http-deceiver@1.2.7: + resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} + dev: true + + /http-errors@1.6.3: + resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + dev: true + + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + dev: true + + /http-parser-js@0.5.8: + resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} + dev: true + + /http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /http-proxy-middleware@2.0.6(@types/express@4.17.17): + resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} + engines: {node: '>=12.0.0'} + peerDependencies: + '@types/express': ^4.17.13 + peerDependenciesMeta: + '@types/express': + optional: true + dependencies: + '@types/express': 4.17.17 + '@types/http-proxy': 1.17.10 + http-proxy: 1.18.1 + is-glob: 4.0.3 + is-plain-obj: 3.0.0 + micromatch: 4.0.5 + transitivePeerDependencies: + - debug + dev: true + + /http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.2 + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + dev: true + + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + dependencies: + ms: 2.1.3 + dev: true + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /icss-utils@5.1.0(postcss@8.4.21): + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + postcss: 8.4.21 + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /ignore-walk@6.0.2: + resolution: {integrity: sha512-ezmQ1Dg2b3jVZh2Dh+ar6Eu2MqNSTkyb32HU2MAQQQX9tKM3q/UQ/9lf03lQ5hW+fOeoMnwxwkleZ0xcNp0/qg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minimatch: 7.4.6 + dev: true + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + requiresBuild: true + dev: true + optional: true + + /immer@10.0.1: + resolution: {integrity: sha512-zg++jJLsKKTwXGeSYIw0HgChSYQGtu0UDTnbKx5aGLYgte4CwTmH9eJDYyQ6FheyUtBe+lQW9FrGxya1G+Dtmg==} + dev: false + + /immutable@4.3.0: + resolution: {integrity: sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==} + dev: true + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + dev: true + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /ini@3.0.1: + resolution: {integrity: sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dev: true + + /injection-js@2.4.0: + resolution: {integrity: sha512-6jiJt0tCAo9zjHbcwLiPL+IuNe9SQ6a9g0PEzafThW3fOQi0mrmiJGBJvDD6tmhPh8cQHIQtCOrJuBfQME4kPA==} + dependencies: + tslib: 2.5.0 + dev: true + + /inquirer@8.2.4: + resolution: {integrity: sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==} + engines: {node: '>=12.0.0'} + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.8.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + dev: true + + /ip@2.0.0: + resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + dev: true + + /ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: true + + /ipaddr.js@2.0.1: + resolution: {integrity: sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==} + engines: {node: '>= 10'} + dev: true + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + dependencies: + builtin-modules: 3.3.0 + dev: true + + /is-core-module@2.12.0: + resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} + dependencies: + has: 1.0.3 + dev: true + + /is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: true + + /is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + dev: true + + /is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-plain-obj@3.0.0: + resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} + engines: {node: '>=10'} + dev: true + + /is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + dev: true + + /is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + + /isbinaryfile@4.0.10: + resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} + engines: {node: '>= 8.0.0'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + dev: true + + /istanbul-lib-coverage@3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.21.4 + '@babel/parser': 7.21.4 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report@3.0.0: + resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} + engines: {node: '>=8'} + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 3.1.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.5: + resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.0 + dev: true + + /jasmine-core@4.5.0: + resolution: {integrity: sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==} + dev: true + + /jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/node': 18.15.11 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jiti@1.18.2: + resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==} + hasBin: true + dev: true + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + dev: true + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-parse-even-better-errors@3.0.0: + resolution: {integrity: sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + + /jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + + /jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + dev: true + + /karma-chrome-launcher@3.1.1: + resolution: {integrity: sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==} + dependencies: + which: 1.3.1 + dev: true + + /karma-coverage@2.2.0: + resolution: {integrity: sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==} + engines: {node: '>=10.0.0'} + dependencies: + istanbul-lib-coverage: 3.2.0 + istanbul-lib-instrument: 5.2.1 + istanbul-lib-report: 3.0.0 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.5 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + + /karma-jasmine-html-reporter@2.0.0(jasmine-core@4.5.0)(karma-jasmine@5.1.0)(karma@6.4.1): + resolution: {integrity: sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==} + peerDependencies: + jasmine-core: ^4.0.0 + karma: ^6.0.0 + karma-jasmine: ^5.0.0 + dependencies: + jasmine-core: 4.5.0 + karma: 6.4.1 + karma-jasmine: 5.1.0(karma@6.4.1) + dev: true + + /karma-jasmine@5.1.0(karma@6.4.1): + resolution: {integrity: sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==} + engines: {node: '>=12'} + peerDependencies: + karma: ^6.0.0 + dependencies: + jasmine-core: 4.5.0 + karma: 6.4.1 + dev: true + + /karma-source-map-support@1.4.0: + resolution: {integrity: sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==} + dependencies: + source-map-support: 0.5.21 + dev: true + + /karma@6.4.1: + resolution: {integrity: sha512-Cj57NKOskK7wtFWSlMvZf459iX+kpYIPXmkNUzP2WAFcA7nhr/ALn5R7sw3w+1udFDcpMx/tuB8d5amgm3ijaA==} + engines: {node: '>= 10'} + hasBin: true + dependencies: + '@colors/colors': 1.5.0 + body-parser: 1.20.2 + braces: 3.0.2 + chokidar: 3.5.3 + connect: 3.7.0 + di: 0.0.1 + dom-serialize: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + http-proxy: 1.18.1 + isbinaryfile: 4.0.10 + lodash: 4.17.21 + log4js: 6.9.1 + mime: 2.6.0 + minimatch: 3.1.2 + mkdirp: 0.5.6 + qjobs: 1.2.0 + range-parser: 1.2.1 + rimraf: 3.0.2 + socket.io: 4.6.1 + source-map: 0.6.1 + tmp: 0.2.1 + ua-parser-js: 0.7.35 + yargs: 16.2.0 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: true + + /kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: true + + /klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + dev: true + + /less-loader@11.1.0(less@4.1.3)(webpack@5.76.1): + resolution: {integrity: sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==} + engines: {node: '>= 14.15.0'} + peerDependencies: + less: ^3.5.0 || ^4.0.0 + webpack: ^5.0.0 + dependencies: + klona: 2.0.6 + less: 4.1.3 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /less@4.1.3: + resolution: {integrity: sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.5.0 + 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.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /license-webpack-plugin@4.0.2(webpack@5.76.1): + resolution: {integrity: sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==} + peerDependencies: + webpack: '*' + peerDependenciesMeta: + webpack: + optional: true + webpack-sources: + optional: true + dependencies: + webpack: 5.76.1(esbuild@0.17.8) + webpack-sources: 3.2.3 + dev: true + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + dev: true + + /loader-utils@2.0.4: + resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} + engines: {node: '>=8.9.0'} + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 2.2.3 + dev: true + + /loader-utils@3.2.1: + resolution: {integrity: sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==} + engines: {node: '>= 12.13.0'} + dev: true + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /log4js@6.9.1: + resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} + engines: {node: '>=8.0'} + dependencies: + date-format: 4.0.14 + debug: 4.3.4 + flatted: 3.2.7 + rfdc: 1.3.0 + streamroller: 3.1.5 + transitivePeerDependencies: + - supports-color + dev: true + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + dev: true + + /lru-cache@9.0.1: + resolution: {integrity: sha512-C8QsKIN1UIXeOs3iWmiZ1lQY+EnKDojWd37fXy1aSbJvH4iSma1uy2OWuoB3m4SYRli5+CUjDv3Dij5DVoetmg==} + engines: {node: 14 || >=16.14} + dev: true + + /magic-string@0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /magic-string@0.29.0: + resolution: {integrity: sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + pify: 4.0.1 + semver: 5.7.1 + dev: true + optional: true + + /make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: true + + /make-fetch-happen@10.2.1: + resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + agentkeepalive: 4.3.0 + cacache: 16.1.3 + http-cache-semantics: 4.1.1 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 2.1.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.3 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 9.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /make-fetch-happen@11.0.3: + resolution: {integrity: sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + agentkeepalive: 4.3.0 + cacache: 17.0.5 + http-cache-semantics: 4.1.1 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.18.3 + minipass: 4.2.8 + minipass-fetch: 3.0.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.3 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 10.0.3 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /media-typer@0.3.0: + resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} + engines: {node: '>= 0.6'} + dev: true + + /memfs@3.5.0: + resolution: {integrity: sha512-yK6o8xVJlQerz57kvPROwTMgx5WtGwC2ZxDtOUsnGl49rHjYkfQoPNZPCKH73VdLE1BwBu/+Fx/NL8NYMUw2aA==} + engines: {node: '>= 4.0.0'} + dependencies: + fs-monkey: 1.0.3 + dev: true + + /merge-descriptors@1.0.1: + resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=} + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: true + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: true + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /mime@2.5.2: + resolution: {integrity: sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==} + engines: {node: '>=4.0.0'} + hasBin: true + dev: true + + /mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + dev: true + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mini-css-extract-plugin@2.7.2(webpack@5.76.1): + resolution: {integrity: sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + dependencies: + schema-utils: 4.0.0 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: true + + /minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimatch@8.0.4: + resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass-fetch@2.1.2: + resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + dev: true + + /minipass-fetch@3.0.1: + resolution: {integrity: sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 4.2.8 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + dev: true + + /minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass-json-stream@1.0.1: + resolution: {integrity: sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==} + dependencies: + jsonparse: 1.3.1 + minipass: 3.3.6 + dev: true + + /minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + dependencies: + minipass: 3.3.6 + dev: true + + /minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: true + + /minipass@4.2.8: + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} + dev: true + + /minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + dev: true + + /minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: true + + /mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /mockjs@1.1.0: + resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==} + hasBin: true + dependencies: + commander: 10.0.1 + dev: true + + /ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /multicast-dns@7.2.5: + resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} + hasBin: true + dependencies: + dns-packet: 5.5.0 + thunky: 1.1.0 + dev: true + + /mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + dev: true + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /needle@3.2.0: + resolution: {integrity: sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==} + engines: {node: '>= 4.4.x'} + hasBin: true + requiresBuild: true + dependencies: + debug: 3.2.7 + iconv-lite: 0.6.3 + sax: 1.2.4 + transitivePeerDependencies: + - supports-color + dev: true + optional: true + + /negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + dev: true + + /neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + dev: true + + /ng-packagr@15.2.2(@angular/compiler-cli@15.2.7)(tailwindcss@3.3.1)(tslib@2.5.0)(typescript@4.9.5): + resolution: {integrity: sha512-+042GBD35ztxbHywGJloAiDM/s3Ja3TZtQh361TWqd/xza3K5DMUu6VRGLTgMwG7CW1YsqYHWgMZslP1c+ng7A==} + engines: {node: ^14.20.0 || ^16.13.0 || >=18.10.0} + hasBin: true + peerDependencies: + '@angular/compiler-cli': ^15.0.0 || ^15.2.0-next.0 + tailwindcss: ^2.0.0 || ^3.0.0 + tslib: ^2.3.0 + typescript: '>=4.8.2 <5.0' + peerDependenciesMeta: + tailwindcss: + optional: true + dependencies: + '@angular/compiler-cli': 15.2.7(@angular/compiler@15.2.7)(typescript@4.9.5) + '@rollup/plugin-json': 6.0.0(rollup@3.20.6) + '@rollup/plugin-node-resolve': 15.0.2(rollup@3.20.6) + ajv: 8.12.0 + ansi-colors: 4.1.3 + autoprefixer: 10.4.14(postcss@8.4.21) + browserslist: 4.21.5 + cacache: 17.0.5 + chokidar: 3.5.3 + commander: 10.0.1 + convert-source-map: 2.0.0 + dependency-graph: 0.11.0 + esbuild-wasm: 0.17.8 + find-cache-dir: 3.3.2 + glob: 8.1.0 + injection-js: 2.4.0 + jsonc-parser: 3.2.0 + less: 4.1.3 + ora: 5.4.1 + piscina: 3.2.0 + postcss: 8.4.21 + postcss-url: 10.1.3(postcss@8.4.21) + rollup: 3.20.6 + rxjs: 7.8.0 + sass: 1.58.1 + tailwindcss: 3.3.1(postcss@8.4.21) + tslib: 2.5.0 + typescript: 4.9.5 + optionalDependencies: + esbuild: 0.17.8 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /ng-zorro-antd@15.1.0(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/forms@15.2.7)(@angular/platform-browser@15.2.7)(@angular/router@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-HkZpaG4+fBGP8jhJ/rzyK9fm1G8pPzT0zCQ+3sae3Mwvop5diRUS8lSX/1SucEqjsYAGv+1S5ipl0HwKTLQlQw==} + peerDependencies: + '@angular/animations': ^15.0.1 + '@angular/common': ^15.0.1 + '@angular/core': ^15.0.1 + '@angular/forms': ^15.0.1 + '@angular/platform-browser': ^15.0.1 + '@angular/router': ^15.0.1 + dependencies: + '@angular/animations': 15.2.7(@angular/core@15.2.7) + '@angular/cdk': 15.2.6(@angular/common@15.2.7)(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/common': 15.2.7(@angular/core@15.2.7)(rxjs@7.8.0) + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/forms': 15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + '@angular/platform-browser': 15.2.7(@angular/animations@15.2.7)(@angular/common@15.2.7)(@angular/core@15.2.7) + '@angular/router': 15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + '@ant-design/icons-angular': 15.0.0(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + date-fns: 2.30.0 + tslib: 2.5.0 + transitivePeerDependencies: + - rxjs + dev: false + + /ngx-permissions@15.0.1(@angular/core@15.2.7)(@angular/router@15.2.7)(rxjs@7.8.0): + resolution: {integrity: sha512-GjPF54B0DYtzqVb95YUh1XZivU4ilpCnx04gtADnIz4grihb/AtVwGwjgeeC1N/zrwUaZWLxTkIm5emN11JlDw==} + peerDependencies: + '@angular/core': '>=13 || >18' + '@angular/router': '>=13 || >18' + rxjs: '>=7 || >11' + dependencies: + '@angular/core': 15.2.7(rxjs@7.8.0)(zone.js@0.12.0) + '@angular/router': 15.2.7(@angular/common@15.2.7)(@angular/core@15.2.7)(@angular/platform-browser@15.2.7)(rxjs@7.8.0) + rxjs: 7.8.0 + tslib: 2.5.0 + dev: false + + /nice-napi@1.0.2: + resolution: {integrity: sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==} + os: ['!win32'] + requiresBuild: true + dependencies: + node-addon-api: 3.2.1 + node-gyp-build: 4.6.0 + dev: true + optional: true + + /node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + requiresBuild: true + dev: true + optional: true + + /node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: true + + /node-gyp-build@4.6.0: + resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} + hasBin: true + requiresBuild: true + dev: true + optional: true + + /node-gyp@9.3.1: + resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} + engines: {node: ^12.13 || ^14.13 || >=16} + hasBin: true + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + make-fetch-happen: 10.2.1 + nopt: 6.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.4.0 + tar: 6.1.13 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /node-releases@2.0.10: + resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} + dev: true + + /nopt@6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + + /normalize-package-data@5.0.0: + resolution: {integrity: sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + hosted-git-info: 6.1.1 + is-core-module: 2.12.0 + semver: 7.4.0 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-bundled@3.0.0: + resolution: {integrity: sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + npm-normalize-package-bin: 3.0.0 + dev: true + + /npm-install-checks@6.1.1: + resolution: {integrity: sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + semver: 7.4.0 + dev: true + + /npm-normalize-package-bin@3.0.0: + resolution: {integrity: sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /npm-package-arg@10.1.0: + resolution: {integrity: sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + hosted-git-info: 6.1.1 + proc-log: 3.0.0 + semver: 7.3.8 + validate-npm-package-name: 5.0.0 + dev: true + + /npm-packlist@7.0.4: + resolution: {integrity: sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + ignore-walk: 6.0.2 + dev: true + + /npm-pick-manifest@8.0.1: + resolution: {integrity: sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + npm-install-checks: 6.1.1 + npm-normalize-package-bin: 3.0.0 + npm-package-arg: 10.1.0 + semver: 7.3.8 + dev: true + + /npm-registry-fetch@14.0.3: + resolution: {integrity: sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + make-fetch-happen: 11.0.3 + minipass: 4.2.8 + minipass-fetch: 3.0.1 + minipass-json-stream: 1.0.1 + minizlib: 2.1.2 + npm-package-arg: 10.1.0 + proc-log: 3.0.0 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /npmlog@6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + dev: true + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: true + + /object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + dev: true + + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: true + + /on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: true + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: true + + /on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /open@8.4.1: + resolution: {integrity: sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==} + engines: {node: '>=12'} + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: true + + /ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.8.0 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: true + + /os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + dev: true + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + dev: true + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /pacote@15.1.0: + resolution: {integrity: sha512-FFcjtIl+BQNfeliSm7MZz5cpdohvUV1yjGnqgVM4UnVF7JslRY0ImXAygdaCDV0jjUADEWu4y5xsDV8brtrTLg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + '@npmcli/git': 4.0.4 + '@npmcli/installed-package-contents': 2.0.2 + '@npmcli/promise-spawn': 6.0.2 + '@npmcli/run-script': 6.0.0 + cacache: 17.0.5 + fs-minipass: 3.0.1 + minipass: 4.2.8 + npm-package-arg: 10.1.0 + npm-packlist: 7.0.4 + npm-pick-manifest: 8.0.1 + npm-registry-fetch: 14.0.3 + proc-log: 3.0.0 + promise-retry: 2.0.1 + read-package-json: 6.0.1 + read-package-json-fast: 3.0.2 + sigstore: 1.2.0 + ssri: 10.0.3 + tar: 6.1.13 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: true + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.21.4 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + dev: true + + /parse5-html-rewriting-stream@7.0.0: + resolution: {integrity: sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==} + dependencies: + entities: 4.4.0 + parse5: 7.1.2 + parse5-sax-parser: 7.0.0 + dev: true + + /parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + dependencies: + parse5: 6.0.1 + dev: true + + /parse5-sax-parser@7.0.0: + resolution: {integrity: sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==} + dependencies: + parse5: 7.1.2 + dev: true + + /parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: true + + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.4.0 + + /parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: true + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-scurry@1.6.4: + resolution: {integrity: sha512-Qp/9IHkdNiXJ3/Kon++At2nVpnhRiPq/aSvQN+H3U1WZbvNRK0RIQK/o4HMqPoXjpuGJUEWpHSs6Mnjxqh3TQg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 9.0.1 + minipass: 5.0.0 + dev: true + + /path-to-regexp@0.1.7: + resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + dev: true + optional: true + + /pirates@4.0.5: + resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} + engines: {node: '>= 6'} + dev: true + + /piscina@3.2.0: + resolution: {integrity: sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==} + dependencies: + eventemitter-asyncresource: 1.0.0 + hdr-histogram-js: 2.0.3 + hdr-histogram-percentiles-obj: 3.0.0 + optionalDependencies: + nice-napi: 1.0.2 + dev: true + + /pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /postcss-import@14.1.0(postcss@8.4.21): + resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} + engines: {node: '>=10.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.21 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.1 + dev: true + + /postcss-js@4.0.1(postcss@8.4.21): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.21 + dev: true + + /postcss-load-config@3.1.4(postcss@8.4.21): + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + postcss: 8.4.21 + yaml: 1.10.2 + dev: true + + /postcss-loader@7.0.2(postcss@8.4.21)(webpack@5.76.1): + resolution: {integrity: sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==} + engines: {node: '>= 14.15.0'} + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + dependencies: + cosmiconfig: 7.1.0 + klona: 2.0.6 + postcss: 8.4.21 + semver: 7.4.0 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /postcss-modules-extract-imports@3.0.0(postcss@8.4.21): + resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + postcss: 8.4.21 + dev: true + + /postcss-modules-local-by-default@4.0.0(postcss@8.4.21): + resolution: {integrity: sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + icss-utils: 5.1.0(postcss@8.4.21) + postcss: 8.4.21 + postcss-selector-parser: 6.0.11 + postcss-value-parser: 4.2.0 + dev: true + + /postcss-modules-scope@3.0.0(postcss@8.4.21): + resolution: {integrity: sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + postcss: 8.4.21 + postcss-selector-parser: 6.0.11 + dev: true + + /postcss-modules-values@4.0.0(postcss@8.4.21): + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + icss-utils: 5.1.0(postcss@8.4.21) + postcss: 8.4.21 + dev: true + + /postcss-nested@6.0.0(postcss@8.4.21): + resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.21 + postcss-selector-parser: 6.0.11 + dev: true + + /postcss-selector-parser@6.0.11: + resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-url@10.1.3(postcss@8.4.21): + resolution: {integrity: sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==} + engines: {node: '>=10'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + make-dir: 3.1.0 + mime: 2.5.2 + minimatch: 3.0.8 + postcss: 8.4.21 + xxhashjs: 0.2.2 + dev: true + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + dev: true + + /postcss@8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + dev: true + + /proc-log@3.0.0: + resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + + /promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + dev: true + + /promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + dev: true + + /proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: true + + /prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + dev: true + optional: true + + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + + /qjobs@1.2.0: + resolution: {integrity: sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==} + engines: {node: '>=0.9'} + dev: true + + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: true + + /raw-body@2.5.1: + resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: true + + /raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: true + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: true + + /read-package-json-fast@3.0.2: + resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + json-parse-even-better-errors: 3.0.0 + npm-normalize-package-bin: 3.0.0 + dev: true + + /read-package-json@6.0.1: + resolution: {integrity: sha512-AaHqXxfAVa+fNL07x8iAghfKOds/XXsu7zoouIVsbm7PEbQ3nMWXlvjcbrNLjElnUHWQtAo4QEa0RXuvD4XlpA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + glob: 9.3.5 + json-parse-even-better-errors: 3.0.0 + normalize-package-data: 5.0.0 + npm-normalize-package-bin: 3.0.0 + dev: true + + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /reflect-metadata@0.1.13: + resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + dev: true + + /regenerate-unicode-properties@10.1.0: + resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} + engines: {node: '>=4'} + dependencies: + regenerate: 1.4.2 + dev: true + + /regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + dev: true + + /regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + /regenerator-transform@0.15.1: + resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} + dependencies: + '@babel/runtime': 7.21.5 + dev: true + + /regex-parser@2.2.11: + resolution: {integrity: sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==} + dev: true + + /regexpu-core@5.3.2: + resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} + engines: {node: '>=4'} + dependencies: + '@babel/regjsgen': 0.8.0 + regenerate: 1.4.2 + regenerate-unicode-properties: 10.1.0 + regjsparser: 0.9.1 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.1.0 + dev: true + + /regjsparser@0.9.1: + resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} + hasBin: true + dependencies: + jsesc: 0.5.0 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve-url-loader@5.0.0: + resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} + engines: {node: '>=12'} + dependencies: + adjust-sourcemap-loader: 4.0.0 + convert-source-map: 1.9.0 + loader-utils: 2.0.4 + postcss: 8.4.21 + source-map: 0.6.1 + dev: true + + /resolve@1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.12.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + dev: true + + /retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.20.6: + resolution: {integrity: sha512-2yEB3nQXp/tBQDN0hJScJQheXdvU2wFhh6ld7K/aiZ1vYcak6N/BKjY1QrU6BvO2JWYS8bEs14FRaxXosxy2zw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + dependencies: + tslib: 1.14.1 + dev: true + + /rxjs@7.8.0: + resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} + dependencies: + tslib: 2.5.0 + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /sass-loader@13.2.0(sass@1.58.1)(webpack@5.76.1): + resolution: {integrity: sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==} + engines: {node: '>= 14.15.0'} + peerDependencies: + fibers: '>= 3.1.0' + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + sass: ^1.3.0 + sass-embedded: '*' + webpack: ^5.0.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + sass-embedded: + optional: true + dependencies: + klona: 2.0.6 + neo-async: 2.6.2 + sass: 1.58.1 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /sass@1.58.1: + resolution: {integrity: sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + immutable: 4.3.0 + source-map-js: 1.0.2 + dev: true + + /sax@1.2.4: + resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} + dev: true + optional: true + + /schema-utils@3.1.1: + resolution: {integrity: sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/json-schema': 7.0.11 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + dev: true + + /schema-utils@4.0.0: + resolution: {integrity: sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==} + engines: {node: '>= 12.13.0'} + dependencies: + '@types/json-schema': 7.0.11 + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + ajv-keywords: 5.1.0(ajv@8.12.0) + dev: true + + /select-hose@2.0.0: + resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} + dev: true + + /selfsigned@2.1.1: + resolution: {integrity: sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==} + engines: {node: '>=10'} + dependencies: + node-forge: 1.3.1 + dev: true + + /semver@5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: true + optional: true + + /semver@6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: true + + /semver@7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /semver@7.4.0: + resolution: {integrity: sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /serialize-javascript@6.0.1: + resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} + dependencies: + randombytes: 2.1.0 + dev: true + + /serve-index@1.9.1: + resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} + engines: {node: '>= 0.8.0'} + dependencies: + accepts: 1.3.8 + batch: 0.6.1 + debug: 2.6.9 + escape-html: 1.0.3 + http-errors: 1.6.3 + mime-types: 2.1.35 + parseurl: 1.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + dev: true + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true + + /setprototypeof@1.1.0: + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} + dev: true + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: true + + /shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + dependencies: + kind-of: 6.0.3 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.2.0 + object-inspect: 1.12.3 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /sigstore@1.2.0: + resolution: {integrity: sha512-Fr9+W1nkBSIZCkJQR7jDn/zI0UXNsVpp+7mDQkCnZOIxG9p6yNXBx9xntHsfUyYHE55XDkkVV3+rYbrkzAeesA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + '@sigstore/protobuf-specs': 0.1.0 + make-fetch-happen: 11.0.3 + tuf-js: 1.1.3 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + dev: true + + /smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: true + + /socket.io-adapter@2.5.2: + resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} + dependencies: + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + + /socket.io-parser@4.2.2: + resolution: {integrity: sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /socket.io@4.6.1: + resolution: {integrity: sha512-KMcaAi4l/8+xEjkRICl6ak8ySoxsYG+gG6/XfRCPJPQ/haCRIJBTL4wIl8YCsmtaBovcAXGLOShyVWQ/FG8GZA==} + engines: {node: '>=10.0.0'} + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + debug: 4.3.4 + engine.io: 6.4.1 + socket.io-adapter: 2.5.2 + socket.io-parser: 4.2.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /sockjs@0.3.24: + resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} + dependencies: + faye-websocket: 0.11.4 + uuid: 8.3.2 + websocket-driver: 0.7.4 + dev: true + + /socks-proxy-agent@7.0.0: + resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} + engines: {node: '>= 10'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: true + + /socks@2.7.1: + resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} + engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map-loader@4.0.1(webpack@5.76.1): + resolution: {integrity: sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==} + engines: {node: '>= 14.15.0'} + peerDependencies: + webpack: ^5.72.1 + dependencies: + abab: 2.0.6 + iconv-lite: 0.6.3 + source-map-js: 1.0.2 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + dev: true + + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-exceptions@2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.13 + dev: true + + /spdx-license-ids@3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + dev: true + + /spdy-transport@3.0.0: + resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} + dependencies: + debug: 4.3.4 + detect-node: 2.1.0 + hpack.js: 2.1.6 + obuf: 1.1.2 + readable-stream: 3.6.2 + wbuf: 1.7.3 + transitivePeerDependencies: + - supports-color + dev: true + + /spdy@4.0.2: + resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} + engines: {node: '>=6.0.0'} + dependencies: + debug: 4.3.4 + handle-thing: 2.0.1 + http-deceiver: 1.2.7 + select-hose: 2.0.0 + spdy-transport: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /ssri@10.0.3: + resolution: {integrity: sha512-lJtX/BFPI/VEtxZmLfeh7pzisIs6micwZ3eruD3+ds9aPsXKlYpwDS2Q7omD6WC42WO9+bnUSzlMmfv8uK8meg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 4.2.8 + dev: true + + /ssri@9.0.1: + resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + minipass: 3.3.6 + dev: true + + /statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + dev: true + + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + dev: true + + /streamroller@3.1.5: + resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} + engines: {node: '>=8.0'} + dependencies: + date-format: 4.0.14 + debug: 4.3.4 + fs-extra: 8.1.0 + transitivePeerDependencies: + - supports-color + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /sucrase@3.32.0: + resolution: {integrity: sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.5 + ts-interface-checker: 0.1.13 + dev: true + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + dev: true + + /tailwindcss@3.3.1(postcss@8.4.21): + resolution: {integrity: sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==} + engines: {node: '>=12.13.0'} + hasBin: true + peerDependencies: + postcss: ^8.0.9 + dependencies: + arg: 5.0.2 + chokidar: 3.5.3 + color-name: 1.1.4 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.2.12 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.18.2 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.21 + postcss-import: 14.1.0(postcss@8.4.21) + postcss-js: 4.0.1(postcss@8.4.21) + postcss-load-config: 3.1.4(postcss@8.4.21) + postcss-nested: 6.0.0(postcss@8.4.21) + postcss-selector-parser: 6.0.11 + postcss-value-parser: 4.2.0 + quick-lru: 5.1.1 + resolve: 1.22.1 + sucrase: 3.32.0 + transitivePeerDependencies: + - ts-node + dev: true + + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true + + /tar@6.1.13: + resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 4.2.8 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: true + + /terser-webpack-plugin@5.3.7(esbuild@0.17.8)(webpack@5.76.1): + resolution: {integrity: sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + dependencies: + '@jridgewell/trace-mapping': 0.3.18 + esbuild: 0.17.8 + jest-worker: 27.5.1 + schema-utils: 3.1.1 + serialize-javascript: 6.0.1 + terser: 5.16.9 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /terser@5.16.3: + resolution: {integrity: sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.3 + acorn: 8.8.2 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + + /terser@5.16.9: + resolution: {integrity: sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.3 + acorn: 8.8.2 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /thunky@1.1.0: + resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} + dev: true + + /tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + dependencies: + os-tmpdir: 1.0.2 + dev: true + + /tmp@0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: true + + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + dev: false + + /tslib@2.5.0: + resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + + /tuf-js@1.1.3: + resolution: {integrity: sha512-jGYi5nG/kqgfTFQSdoN6PW9eIn+XRZqdXku+fSwNk6UpWIsWaV7pzAqPgFr85edOPhoyJDyBqCS+DCnHroMvrw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@tufjs/models': 1.0.2 + make-fetch-happen: 11.0.3 + transitivePeerDependencies: + - bluebird + - supports-color + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + dev: true + + /typed-assert@1.0.9: + resolution: {integrity: sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==} + dev: true + + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /ua-parser-js@0.7.35: + resolution: {integrity: sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==} + dev: true + + /unicode-canonical-property-names-ecmascript@2.0.0: + resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} + engines: {node: '>=4'} + dev: true + + /unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.0 + unicode-property-aliases-ecmascript: 2.1.0 + dev: true + + /unicode-match-property-value-ecmascript@2.1.0: + resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} + engines: {node: '>=4'} + dev: true + + /unicode-property-aliases-ecmascript@2.1.0: + resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} + engines: {node: '>=4'} + dev: true + + /unique-filename@2.0.1: + resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + unique-slug: 3.0.0 + dev: true + + /unique-filename@3.0.0: + resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + unique-slug: 4.0.0 + dev: true + + /unique-slug@3.0.0: + resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + imurmurhash: 0.1.4 + dev: true + + /unique-slug@4.0.0: + resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + dev: true + + /universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: true + + /unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + dev: true + + /update-browserslist-db@1.0.10(browserslist@4.21.5): + resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.5 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.0 + dev: true + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /utils-merge@1.0.1: + resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=} + engines: {node: '>= 0.4.0'} + dev: true + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + + /validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + dev: true + + /validate-npm-package-name@5.0.0: + resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + builtins: 5.0.1 + dev: true + + /vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + dev: true + + /void-elements@2.0.1: + resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==} + engines: {node: '>=0.10.0'} + dev: true + + /watchpack@2.4.0: + resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + dev: true + + /wbuf@1.7.3: + resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} + dependencies: + minimalistic-assert: 1.0.1 + dev: true + + /wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.4 + dev: true + + /webpack-dev-middleware@5.3.3(webpack@5.76.1): + resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + dependencies: + colorette: 2.0.19 + memfs: 3.5.0 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.0.0 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /webpack-dev-middleware@6.0.1(webpack@5.76.1): + resolution: {integrity: sha512-PZPZ6jFinmqVPJZbisfggDiC+2EeGZ1ZByyMP5sOFJcPPWSexalISz+cvm+j+oYPT7FIJyxT76esjnw9DhE5sw==} + engines: {node: '>= 14.15.0'} + peerDependencies: + webpack: ^5.0.0 + dependencies: + colorette: 2.0.19 + memfs: 3.5.0 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.0.0 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /webpack-dev-server@4.11.1(webpack@5.76.1): + resolution: {integrity: sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==} + engines: {node: '>= 12.13.0'} + hasBin: true + peerDependencies: + webpack: ^4.37.0 || ^5.0.0 + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/bonjour': 3.5.10 + '@types/connect-history-api-fallback': 1.3.5 + '@types/express': 4.17.17 + '@types/serve-index': 1.9.1 + '@types/serve-static': 1.15.1 + '@types/sockjs': 0.3.33 + '@types/ws': 8.5.4 + ansi-html-community: 0.0.8 + bonjour-service: 1.1.1 + chokidar: 3.5.3 + colorette: 2.0.19 + compression: 1.7.4 + connect-history-api-fallback: 2.0.0 + default-gateway: 6.0.3 + express: 4.18.2 + graceful-fs: 4.2.11 + html-entities: 2.3.3 + http-proxy-middleware: 2.0.6(@types/express@4.17.17) + ipaddr.js: 2.0.1 + open: 8.4.1 + p-retry: 4.6.2 + rimraf: 3.0.2 + schema-utils: 4.0.0 + selfsigned: 2.1.1 + serve-index: 1.9.1 + sockjs: 0.3.24 + spdy: 4.0.2 + webpack: 5.76.1(esbuild@0.17.8) + webpack-dev-middleware: 5.3.3(webpack@5.76.1) + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + dev: true + + /webpack-merge@5.8.0: + resolution: {integrity: sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==} + engines: {node: '>=10.0.0'} + dependencies: + clone-deep: 4.0.1 + wildcard: 2.0.0 + dev: true + + /webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} + engines: {node: '>=10.13.0'} + dev: true + + /webpack-subresource-integrity@5.1.0(webpack@5.76.1): + resolution: {integrity: sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==} + engines: {node: '>= 12'} + peerDependencies: + html-webpack-plugin: '>= 5.0.0-beta.1 < 6' + webpack: ^5.12.0 + peerDependenciesMeta: + html-webpack-plugin: + optional: true + dependencies: + typed-assert: 1.0.9 + webpack: 5.76.1(esbuild@0.17.8) + dev: true + + /webpack@5.76.1(esbuild@0.17.8): + resolution: {integrity: sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + dependencies: + '@types/eslint-scope': 3.7.4 + '@types/estree': 0.0.51 + '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/wasm-edit': 1.11.1 + '@webassemblyjs/wasm-parser': 1.11.1 + acorn: 8.8.2 + acorn-import-assertions: 1.8.0(acorn@8.8.2) + browserslist: 4.21.5 + chrome-trace-event: 1.0.3 + enhanced-resolve: 5.12.0 + es-module-lexer: 0.9.3 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.1.1 + tapable: 2.2.1 + terser-webpack-plugin: 5.3.7(esbuild@0.17.8)(webpack@5.76.1) + watchpack: 2.4.0 + webpack-sources: 3.2.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + dev: true + + /websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + dependencies: + http-parser-js: 0.5.8 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + dev: true + + /websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + dev: true + + /which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /which@3.0.0: + resolution: {integrity: sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 + dev: true + + /wildcard@2.0.0: + resolution: {integrity: sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==} + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true + + /ws@8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + + /xxhashjs@0.2.2: + resolution: {integrity: sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==} + dependencies: + cuint: 0.2.2 + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + + /yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + + /yargs@17.6.2: + resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yargs@17.7.1: + resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /zone.js@0.12.0: + resolution: {integrity: sha512-XtC+I5dXU14HrzidAKBNMqneIVUykLEAA1x+v4KVrd6AUPWlwYORF8KgsVqvgdHiKZ4BkxxjvYi/ksEixTPR0Q==} + dependencies: + tslib: 2.5.0 + + /zrender@5.4.3: + resolution: {integrity: sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==} + dependencies: + tslib: 2.3.0 + dev: false diff --git a/projects/cdk/README.md b/projects/cdk/README.md new file mode 100644 index 0000000..1a23b4e --- /dev/null +++ b/projects/cdk/README.md @@ -0,0 +1,24 @@ +# Cdk + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.0. + +## Code scaffolding + +Run `ng generate component component-name --project cdk` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project cdk`. +> Note: Don't forget to add `--project cdk` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build cdk` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build cdk`, go to the dist folder `cd dist/cdk` and run `npm publish`. + +## Running unit tests + +Run `ng test cdk` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/projects/cdk/ng-package.json b/projects/cdk/ng-package.json new file mode 100644 index 0000000..c3205e0 --- /dev/null +++ b/projects/cdk/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/cdk", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/cdk/package.json b/projects/cdk/package.json new file mode 100644 index 0000000..2052836 --- /dev/null +++ b/projects/cdk/package.json @@ -0,0 +1,12 @@ +{ + "name": "cdk", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^15.2.0", + "@angular/core": "^15.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/cdk/src/dec-module/base-href.ts b/projects/cdk/src/dec-module/base-href.ts new file mode 100644 index 0000000..01c083d --- /dev/null +++ b/projects/cdk/src/dec-module/base-href.ts @@ -0,0 +1,8 @@ +import { PlatformLocation } from "@angular/common"; +import { InjectionToken } from "@angular/core"; + +export const PUBLIC_PATH = new InjectionToken("pablic-path"); + +export function getBaseHref(platformLocation: PlatformLocation): string { + return platformLocation.getBaseHrefFromDOM(); +} diff --git a/projects/cdk/src/dec-module/dec.module.ts b/projects/cdk/src/dec-module/dec.module.ts new file mode 100644 index 0000000..249b270 --- /dev/null +++ b/projects/cdk/src/dec-module/dec.module.ts @@ -0,0 +1,41 @@ +import { InjectionToken, ModuleWithProviders, NgModule } from "@angular/core"; +import { CommonModule, PlatformLocation } from "@angular/common"; +import { NzMessageModule } from "ng-zorro-antd/message"; +import { HttpResponse, HTTP_INTERCEPTORS } from "@angular/common/http"; +import { HTTPInterceptor } from "./http.interceptor"; +import { DecSafeAny } from "@cdk/types"; +import { getBaseHref, PUBLIC_PATH } from "./base-href"; + +export const decConfigToken = new InjectionToken("decConfig"); + +export type DecConfig = { + environment: DecSafeAny; + isClient?: boolean; + loginUrl?: string; + localStroageKey: string; + triggerError?: (res: HttpResponse) => void; +}; + +@NgModule({ + declarations: [], + imports: [NzMessageModule], + providers: [{ provide: HTTP_INTERCEPTORS, useClass: HTTPInterceptor, multi: true }], +}) +export class DecModule { + public static forRoot(decConfig: DecConfig): ModuleWithProviders { + return { + ngModule: DecModule, + providers: [ + { + provide: decConfigToken, + useValue: decConfig, + }, + { + provide: PUBLIC_PATH, + useFactory: getBaseHref, + deps: [PlatformLocation], + }, + ], + }; + } +} diff --git a/projects/cdk/src/dec-module/http.interceptor.ts b/projects/cdk/src/dec-module/http.interceptor.ts new file mode 100644 index 0000000..a686af8 --- /dev/null +++ b/projects/cdk/src/dec-module/http.interceptor.ts @@ -0,0 +1,100 @@ +import { Inject, Injectable } from "@angular/core"; +import { + HttpRequest, + HttpHandler, + HttpEvent, + HttpInterceptor, + HttpErrorResponse, + HttpResponse, +} from "@angular/common/http"; +import { catchError, Observable, switchMap, tap, throwError, timer } from "rxjs"; +import { Router } from "@angular/router"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { decConfigToken, DecConfig } from "./dec.module"; +import { ResponseType } from "@cdk/types"; + +@Injectable({ providedIn: "root" }) +export class HTTPInterceptor implements HttpInterceptor { + constructor( + @Inject(decConfigToken) private decConfig: Required, + private router: Router, + private msg: NzMessageService + ) {} + + private msgFlag = false; + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + const { localStroageKey } = this.decConfig; + + const token = localStorage.getItem(localStroageKey); + + if (token) { + req = req.clone({ + // headers: req.headers.set('Authorization', `Bearer ${token}`), + headers: req.headers.set("Authorization", token), + }); + } + + return this.handleResult(next, req); + } + + private handleResult(next: HttpHandler, authReq: HttpRequest): Observable> { + return next.handle(authReq).pipe( + tap((res) => { + if (res instanceof HttpResponse) { + const Authorization = res.headers.get("Authorization"); + if (Authorization) { + localStorage.setItem(this.decConfig.localStroageKey, Authorization); + } + + if (this.decConfig.triggerError) { + this.decConfig.triggerError(res); + } + + if (res.body?.success === false && res.body.desc) { + throw new HttpErrorResponse({ error: res.body }); + } + } + }), + + catchError((err: HttpErrorResponse) => { + const throwErr = throwError(() => err); + if (this.msgFlag) { + return throwErr; + } + const { isClient } = this.decConfig; + setTimeout(() => { + this.msgFlag = false; + }, 1500); + const error: ResponseType = err.error; + this.msgFlag = true; + + if (error.success === false) { + if (isClient) { + switch (error.code) { + case 401: + break; + + default: + this.msg.error(error.desc); + break; + } + } else { + this.msg.error(error.desc); + switch (error.code) { + case 401: + this.router.navigate([this.decConfig.loginUrl]); + break; + default: + break; + } + } + } else { + this.msg.error("服务器出错了!"); + } + + return throwErr; + }) + ); + } +} diff --git a/projects/cdk/src/form-error-tips/form-error-tips.component.html b/projects/cdk/src/form-error-tips/form-error-tips.component.html new file mode 100644 index 0000000..914ea00 --- /dev/null +++ b/projects/cdk/src/form-error-tips/form-error-tips.component.html @@ -0,0 +1,36 @@ + + + {{item.value.message}} + + + +
+ 不能为空 +
+
+ 首末字符不能为空格 +
+
+ 请输入正确的邮箱地址 +
+
+ 最多输入{{item.value.requiredLength}}位字符 +
+
+ 最少输入{{item.value.requiredLength}}位字符 +
+
+ 不能小于{{item.value.min}} +
+
+ 不能大于{{item.value.max}} +
+
+ 请输入正确的内容 +
+
+ 字段验证失败 +
+
+
+
\ No newline at end of file diff --git a/projects/cdk/src/form-error-tips/form-error-tips.component.less b/projects/cdk/src/form-error-tips/form-error-tips.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/cdk/src/form-error-tips/form-error-tips.component.ts b/projects/cdk/src/form-error-tips/form-error-tips.component.ts new file mode 100644 index 0000000..0b20dbc --- /dev/null +++ b/projects/cdk/src/form-error-tips/form-error-tips.component.ts @@ -0,0 +1,28 @@ +import { CommonModule } from "@angular/common"; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; + +@Component({ + standalone: true, + selector: "dec-form-error-tips", + templateUrl: "./form-error-tips.component.html", + styleUrls: ["./form-error-tips.component.less"], + imports: [CommonModule], +}) +export class FormErrorTipsComponent implements OnInit, OnChanges { + constructor() {} + + @Input() control!: FormControl; + + ngOnChanges(changes: SimpleChanges): void { + // console.log("FormErrorTipsComponent changes", changes["control"]?.currentValue); + // const formControl: FormControl = changes["control"].currentValue; + // const root = formControl.root as FormGroup; + // console.log("formControl.root", formControl); + // if (formControl && !this.label) { + // if(initLabelFormControlNameMaps.has(formControl)) + // } + } + + ngOnInit(): void {} +} diff --git a/projects/cdk/src/input-space-error/input-space-error.directive.ts b/projects/cdk/src/input-space-error/input-space-error.directive.ts new file mode 100644 index 0000000..87bfc07 --- /dev/null +++ b/projects/cdk/src/input-space-error/input-space-error.directive.ts @@ -0,0 +1,24 @@ +import { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator, ValidatorFn } from "@angular/forms"; +import { Directive } from "@angular/core"; + +const VALIDATE_WHITE_SPACE_REGEX = /^[\s]|[\s]$/; + +export function stringWhiteSpaceForbiddenValidator(): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } | null => { + const isInvalid = VALIDATE_WHITE_SPACE_REGEX.test(control.value); + return isInvalid ? { inputTrim: { value: control.value } } : null; + }; +} + +@Directive({ + standalone: true, + selector: "[nz-input]", + providers: [{ provide: NG_VALIDATORS, useExisting: InputSpaceErrorDirective, multi: true }], +}) +export class InputSpaceErrorDirective implements Validator { + constructor() {} + + validate(control: AbstractControl): ValidationErrors | null { + return stringWhiteSpaceForbiddenValidator()(control); + } +} diff --git a/projects/cdk/src/public-api.ts b/projects/cdk/src/public-api.ts new file mode 100644 index 0000000..9fb6967 --- /dev/null +++ b/projects/cdk/src/public-api.ts @@ -0,0 +1,14 @@ +/* + * Public API Surface of cdk + */ + +export * from "./types"; +export * from "./utils"; +export * from "./validators"; +export * from "./dec-module/dec.module"; +export * from "./form-error-tips/form-error-tips.component"; +export * from "./input-space-error/input-space-error.directive"; +export * from "./public-path/public-path.pipe"; +export * from "./quick-date-range/quick-date-range.component"; +export * from "./table-list"; +export * from "./storage"; diff --git a/projects/cdk/src/public-path/public-path.pipe.ts b/projects/cdk/src/public-path/public-path.pipe.ts new file mode 100644 index 0000000..50f568e --- /dev/null +++ b/projects/cdk/src/public-path/public-path.pipe.ts @@ -0,0 +1,16 @@ +import { Inject, Pipe, PipeTransform } from "@angular/core"; +import { PUBLIC_PATH } from "@cdk/dec-module/base-href"; + +@Pipe({ + name: "publicPath", + standalone: true, +}) +export class PublicPathPipe implements PipeTransform { + constructor(@Inject(PUBLIC_PATH) private publicPath: string) {} + transform(value: string): string { + if (value.startsWith("/")) { + value = value.replace("/", ""); + } + return this.publicPath + value; + } +} diff --git a/projects/cdk/src/quick-date-range/quick-date-range.component.css b/projects/cdk/src/quick-date-range/quick-date-range.component.css new file mode 100644 index 0000000..e69de29 diff --git a/projects/cdk/src/quick-date-range/quick-date-range.component.html b/projects/cdk/src/quick-date-range/quick-date-range.component.html new file mode 100644 index 0000000..2e05348 --- /dev/null +++ b/projects/cdk/src/quick-date-range/quick-date-range.component.html @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/projects/cdk/src/quick-date-range/quick-date-range.component.ts b/projects/cdk/src/quick-date-range/quick-date-range.component.ts new file mode 100644 index 0000000..cac0b56 --- /dev/null +++ b/projects/cdk/src/quick-date-range/quick-date-range.component.ts @@ -0,0 +1,94 @@ +import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from "@angular/forms"; +import { NzRadioModule } from "ng-zorro-antd/radio"; +import { NzSpaceModule } from "ng-zorro-antd/space"; +import { CommonModule } from "@angular/common"; +import { Component, OnInit } from "@angular/core"; +import { NzDatePickerModule } from "ng-zorro-antd/date-picker"; +import { subDays, format } from "date-fns"; + +@Component({ + standalone: true, + selector: "dec-quick-date-range", + templateUrl: "./quick-date-range.component.html", + styleUrls: ["./quick-date-range.component.css"], + imports: [CommonModule, NzDatePickerModule, NzSpaceModule, NzRadioModule, FormsModule], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: QuickDateRangeComponent, + }, + ], +}) +export class QuickDateRangeComponent implements OnInit, ControlValueAccessor { + constructor() {} + + dateFilterOptions = [ + { + label: "今日", + value: 0, + }, + { + label: "近7日", + value: 7, + }, + { + label: "近30日", + value: 30, + }, + { + label: "近90日", + value: 90, + }, + ]; + + quick: number | null = null; + + range: Date[] = []; + + onQuickChange(v: number) { + this.quick = v; + this.range = this.getDateRange(v).map((d) => new Date(d)); + const val = this.range.map((date) => format(date, "yyyy-MM-dd")); + // console.log("val", val); + this.onChange(val); + } + + getDateRange(n: number): [string, string] { + const today = new Date(); + const previousDay = subDays(today, n); + const formattedToday = format(today, "yyyy-MM-dd"); + const formattedPreviousDay = format(previousDay, "yyyy-MM-dd"); + return [formattedPreviousDay, formattedToday]; + } + + ngOnInit(): void {} + + onRangeChange(v: Date[]) { + this.quick = null; + this.range = v; + const val = v.map((date) => format(date, "yyyy-MM-dd")); + this.onChange(val); + } + + onChange(v: any) {} + + ontouch(v: any) {} + + writeValue(v: string[]): void { + // console.log("v", v); + if (v && Array.isArray(v)) { + this.range = v?.map((d) => new Date(d)); + } else { + this.onQuickChange(90); + } + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.ontouch = fn; + } +} diff --git a/projects/cdk/src/storage/cache.service.ts b/projects/cdk/src/storage/cache.service.ts new file mode 100644 index 0000000..dfa3dd5 --- /dev/null +++ b/projects/cdk/src/storage/cache.service.ts @@ -0,0 +1,71 @@ +import { Injectable } from "@angular/core"; +import { NavigationEnd, Router } from "@angular/router"; +import { filter } from "rxjs/operators"; +import { DecSafeAny } from "../types"; +import { StorageService } from "./storage.service"; + +type IcacheUrlMap = Record>; + +export class CacheItem { + constructor(private storage: StorageService, private cacheKey: string) {} + + getItem(): T { + return this.storage.get(this.cacheKey, { stroage: "session" }); + } + + setItem(query: T) { + this.storage.set(this.cacheKey, query, { stroage: "session" }); + } + + remove() { + this.storage.set(this.cacheKey, null, { stroage: "session" }); + } +} + +@Injectable() +export class CacheService { + constructor(private router: Router, private storage: StorageService) {} + + /** + * cacheKey 与 url 之间的映射 + */ + private get cacheUrlMap(): IcacheUrlMap { + return this.storage.get("cacheUrlMap") ?? {}; + } + + private set cacheUrlMap(o: IcacheUrlMap) { + this.storage.set("cacheUrlMap", o); + } + + listen() { + this.router.events.pipe(filter((f): f is NavigationEnd => f instanceof NavigationEnd)).subscribe((r) => { + const currentUrl = r.url; + for (const [api, urls] of Object.entries(this.cacheUrlMap)) { + if (!urls.some((s) => currentUrl.startsWith(s))) { + this.storage.remove(api, { stroage: "session" }); + } + } + }); + } + + /** + * + * @param cacheKey 缓存的key + * @param cacheInUrl 当前 cacheKey 该url中缓存,若页面跳转到非url中时删除 缓存的数据 + * @return 返回一个可以操作该缓存的对象 getItem & setItem + */ + initCache(cacheKey: string, cacheInUrl?: string): CacheItem; + initCache(cacheKey: string, cacheInUrl?: Array): CacheItem; + initCache(cacheKey: string, cacheInUrl?: string | Array): CacheItem { + if (!cacheInUrl) { + cacheInUrl = [this.router.url]; + } + if (!this.cacheUrlMap[cacheKey]) { + cacheInUrl = (Array.isArray(cacheInUrl) ? cacheInUrl : [cacheInUrl]) as Array; + const storageData = this.cacheUrlMap; + storageData[cacheKey] = cacheInUrl; + this.cacheUrlMap = storageData; + } + return new CacheItem(this.storage, cacheKey); + } +} diff --git a/projects/cdk/src/storage/index.ts b/projects/cdk/src/storage/index.ts new file mode 100644 index 0000000..9cbe252 --- /dev/null +++ b/projects/cdk/src/storage/index.ts @@ -0,0 +1,3 @@ +export * from "./storage.module"; +export * from "./storage.service"; +export * from "./cache.service"; diff --git a/projects/cdk/src/storage/storage.module.ts b/projects/cdk/src/storage/storage.module.ts new file mode 100644 index 0000000..0e2155f --- /dev/null +++ b/projects/cdk/src/storage/storage.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from "@angular/core"; +import { CacheService } from "./cache.service"; +import { StorageService } from "./storage.service"; + +@NgModule({ + declarations: [], + imports: [], + providers: [StorageService, CacheService], + exports: [], +}) +export class StorageModule { + constructor(private cache: CacheService) { + this.cache.listen(); + } +} diff --git a/projects/cdk/src/storage/storage.service.ts b/projects/cdk/src/storage/storage.service.ts new file mode 100644 index 0000000..641cb3a --- /dev/null +++ b/projects/cdk/src/storage/storage.service.ts @@ -0,0 +1,79 @@ +import { Injectable } from "@angular/core"; + +export interface IFunc { + (prev?: T): T; +} + +interface Option { + stroage?: "local" | "session"; + defaultValue?: T | IFunc; + serializer?: (v: T) => string; + deserializer?: (v: string) => T; +} + +export const isFunction = (value: unknown): value is Function => typeof value === "function"; + +@Injectable() +export class StorageService { + constructor() {} + + private parseOption(option?: Option) { + const storage = option?.stroage === "session" ? sessionStorage : localStorage; + const serializer = option?.serializer ? option?.serializer : JSON.stringify; + const deserializer = option?.deserializer ? option?.deserializer : JSON.parse; + let defaultValue = option?.defaultValue; + + if (isFunction(option?.defaultValue)) { + defaultValue = option?.defaultValue(); + } + + return { + storage, + serializer, + deserializer, + defaultValue, + }; + } + + get(key: string, option?: Option) { + const { storage, deserializer, defaultValue } = this.parseOption(option); + try { + const val = storage.getItem(key); + if (val) { + return deserializer(val); + } + } catch (error) { + console.error(error); + } + return defaultValue; + } + + set(key: string, value: T | IFunc, option?: Option) { + const { storage, serializer, defaultValue } = this.parseOption(option); + const val = (isFunction(value) ? value() : value) ?? defaultValue; + if (typeof val === "undefined") { + storage.removeItem(key); + } else { + try { + storage.setItem(key, serializer(val)); + } catch (error) { + console.error(error); + } + } + } + + remove(key: string, option?: Pick) { + const { storage } = this.parseOption(option); + storage.removeItem(key); + } + + clear(option?: Pick) { + const { storage } = this.parseOption(option); + storage.clear(); + } + + keys(option?: Pick) { + const { storage } = this.parseOption(option); + return Object.keys(storage); + } +} diff --git a/projects/cdk/src/table-list/index.ts b/projects/cdk/src/table-list/index.ts new file mode 100644 index 0000000..05a28dc --- /dev/null +++ b/projects/cdk/src/table-list/index.ts @@ -0,0 +1,5 @@ +export * from "./table-list.module"; + +export * from "./table-list-options"; +export * from "./table-list/table-list.component"; +export * from "./table-operation/table-operation.component"; diff --git a/projects/cdk/src/table-list/table-list-options.ts b/projects/cdk/src/table-list/table-list-options.ts new file mode 100644 index 0000000..b5a57bf --- /dev/null +++ b/projects/cdk/src/table-list/table-list-options.ts @@ -0,0 +1,143 @@ +import { Observable, Subject } from "rxjs"; +import { produce, immerable, setAutoFreeze } from "immer"; +import { DecSafeAny, TableListColumns, TableOperation } from "../types"; +import { EventEmitter } from "@angular/core"; + +type IfetchData = (...args: DecSafeAny[]) => Observable; + +type ITableListConfig = { + manual?: boolean; + cacheKey?: string; + cacheTo?: string[]; + rowKey?: string; + columnKey?: string; + selectable?: boolean; + withOutDefaultColumns?: boolean; + theadSettable?: boolean; + pageFromZero?: boolean; + frontPagination?: boolean; +}; + +type TableListState = { + selectedKeys: string[]; +}; + +type TableListPager = { + page: number; + size: number; + total: number; + loading: boolean; + sort: { [K: string]: "ascend" | "descend" }; +}; + +setAutoFreeze(false); + +export class TableListOption { + [immerable] = true; + + trigger$ = new Subject(); + + getState$ = new EventEmitter(); + + columns: TableListColumns[] = []; + + operations!: TableOperation[]; + + fetchData: IfetchData; + + manual?: boolean = false; + + cacheKey?: string; + + cacheTo?: string[]; + + rowKey: string; + + columnKey?: string; + + selectable: boolean = false; + + withOutDefaultColumns?: boolean; + + pageFromZero?: boolean; + + theadSettable: boolean = false; + + frontPagination: boolean = true; + + scroll: { x?: string | null; y?: string | null } = { x: "2000px", y: null }; + + pager: TableListPager = { + page: 1, + size: 5, + loading: false, + total: 0, + sort: {}, + }; + + constructor(fetchData: IfetchData, config?: ITableListConfig) { + this.fetchData = fetchData; + this.manual = config?.manual; + this.cacheKey = config?.cacheKey; + this.cacheTo = config?.cacheTo; + this.rowKey = config?.rowKey ?? "id"; + this.selectable = config?.selectable ?? false; + this.withOutDefaultColumns = config?.withOutDefaultColumns; + this.theadSettable = config?.theadSettable ?? false; + this.columnKey = config?.columnKey; + this.pageFromZero = config?.pageFromZero; + this.frontPagination = config?.frontPagination ?? true; + } + + /** + * 设置表格的列,❗❗不可变数据❗❗ + * @param columns TableListColumns + * @returns + */ + setColumns(columns: TableListColumns[]) { + return produce(this, (draft) => { + // if (!this.withOutDefaultColumns) { + // columns = columns.concat( + // { key: "createTime", title: "创建时间", sort: true }, + // { key: "updateTime", title: "更新时间", sort: true, visible: false } + // ); + // draft.pager.sort = { createTime: "descend" }; + // } + draft.columns = columns; + }); + } + + /** + * 设置表格的操作项,❗❗不可变数据❗❗ + * @param columns TableListColumns + * @returns + */ + setOptions(operations: TableOperation[]) { + return produce(this, (draft) => { + draft.operations = operations; + }); + } + + /** + * 设置表格CacheKey,❗❗不可变数据❗❗ + * @param columns TableListColumns + * @returns + */ + setCacheKey(cacheKey: string) { + return produce(this, (draft) => { + draft.cacheKey = cacheKey; + }); + } + + run(e?: DecSafeAny) { + setTimeout(() => { + // 防止 还没有 subscribe 就 next 了 + this.trigger$.next(e); + }, 10); + } + + reset() { + this.pager.page = 1; + this.run(); + } +} diff --git a/projects/cdk/src/table-list/table-list.module.ts b/projects/cdk/src/table-list/table-list.module.ts new file mode 100644 index 0000000..d95859a --- /dev/null +++ b/projects/cdk/src/table-list/table-list.module.ts @@ -0,0 +1,56 @@ +import { NgxPermissionsModule } from "ngx-permissions"; +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { RouterModule } from "@angular/router"; +import { DragDropModule } from "@angular/cdk/drag-drop"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { NzDrawerModule } from "ng-zorro-antd/drawer"; +import { NzDropDownModule } from "ng-zorro-antd/dropdown"; +import { NzCheckboxModule } from "ng-zorro-antd/checkbox"; +import { NzEmptyModule } from "ng-zorro-antd/empty"; +import { NzTableModule } from "ng-zorro-antd/table"; +import { NzPaginationModule } from "ng-zorro-antd/pagination"; +import { NzCardModule } from "ng-zorro-antd/card"; +import { NzFormModule } from "ng-zorro-antd/form"; +import { NzSpaceModule } from "ng-zorro-antd/space"; +import { NzIconModule } from "ng-zorro-antd/icon"; +import { NzSwitchModule } from "ng-zorro-antd/switch"; +import { NzSkeletonModule } from "ng-zorro-antd/skeleton"; +import { NzDividerModule } from "ng-zorro-antd/divider"; +import { NzPopoverModule } from "ng-zorro-antd/popover"; +import { NzButtonModule } from "ng-zorro-antd/button"; +import { TableListComponent } from "./table-list/table-list.component"; +import { TableOperationComponent } from "./table-operation/table-operation.component"; +import { TdOverflowDirective } from "./td-overflow.directive"; + +@NgModule({ + declarations: [TableListComponent, TableOperationComponent, TdOverflowDirective], + imports: [ + CommonModule, + RouterModule, + FormsModule, + ReactiveFormsModule, + DragDropModule, + + NzSwitchModule, + NzDividerModule, + NzCheckboxModule, + NzDrawerModule, + NzDropDownModule, + NzEmptyModule, + NzTableModule, + NzPaginationModule, + NzCardModule, + NzFormModule, + NzSpaceModule, + NzButtonModule, + NzPopoverModule, + NzIconModule, + NzSkeletonModule, + NgxPermissionsModule.forRoot(), + ], + exports: [TableListComponent, TableOperationComponent], +}) +export class TableListModule { + constructor() {} +} diff --git a/projects/cdk/src/table-list/table-list/table-list.component.html b/projects/cdk/src/table-list/table-list/table-list.component.html new file mode 100644 index 0000000..0068332 --- /dev/null +++ b/projects/cdk/src/table-list/table-list/table-list.component.html @@ -0,0 +1,223 @@ +
+ +
+
+ + +
+ + + + + + + + + +
+
+
+
+ + + +
+
+ +
+
+ + + + +
+ + + + + + + + {{col.title}} + + + + 操作 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{dataItem[col.key]}} + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + + + + + +
+ +
+ + +
+
+ + +
+
+ + + + + +
+
+ + + + + +
    +
  • +
    +
    +
    + +
    +
    + {{item.title}} +
    +
    + + +
    +
    +
  • +
+
+
+ + + + + + + 共{{total}}条 + + + + + {{date| date:'yyyy-MM-dd HH:mm:ss'}} + \ No newline at end of file diff --git a/projects/cdk/src/table-list/table-list/table-list.component.less b/projects/cdk/src/table-list/table-list/table-list.component.less new file mode 100644 index 0000000..f99a107 --- /dev/null +++ b/projects/cdk/src/table-list/table-list/table-list.component.less @@ -0,0 +1,119 @@ +.advance-search-btn { + position: relative; + .up-arrow { + position: absolute; + bottom: calc(-100% + 10px); + left: 50%; + transform: translateX(-50%); + color: #fff; + font-size: 28px; + filter: drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.1)); + } + .double-arrow { + transform: rotate(90deg); + transition: transform 0.3s; + &.up { + transform: rotate(-90deg); + } + } +} + +.hidden-option { + display: inline-block; + height: 0; + opacity: 0; + overflow: hidden; + pointer-events: none; +} + +.table-list { + td { + word-break: break-all; + } + th { + white-space: nowrap; + } + ::ng-deep { + .ant-table-pagination.ant-pagination { + padding: 0 16px; + } + + // tbody { + // tr td:last-child { + // width: 0; + // } + // } + } +} + +.advance-search { + ::ng-deep { + .ant-card-body { + padding: 16px 24px; + } + } +} + +.search-row { + ::ng-deep { + > * { + padding: 6px; + } + } +} +.query-form { + ::ng-deep { + .hor { + nz-form-item { + align-items: center; + } + } + nz-form-item { + margin-bottom: 0; + + // flex-direction: column; + // align-items: flex-start; + // justify-content: flex-start; + // margin-right: 12px; + } + } +} + +::ng-deep { + .table-settings { + .ant-drawer-body { + padding: 12px 0; + } + } + .table-setting-item { + background-color: #fff; + &:hover { + background-color: var(--bg-light); + } + } +} + +.cdk-drag-preview { + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} + +.cdk-drag-animating { + transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1); +} + +.table-setting-item:last-child { + border: none; +} + +.columns-list.cdk-drop-list-dragging .table-setting-item:not(.cdk-drag-placeholder) { + transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1); +} + +.columns-item-placeholder { + background: #fff; + border: 3px dotted var(--p); + min-height: 38px; + transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1); +} diff --git a/projects/cdk/src/table-list/table-list/table-list.component.ts b/projects/cdk/src/table-list/table-list/table-list.component.ts new file mode 100644 index 0000000..21381d0 --- /dev/null +++ b/projects/cdk/src/table-list/table-list/table-list.component.ts @@ -0,0 +1,386 @@ +import { + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + TemplateRef, + ViewChild, + Pipe, + PipeTransform, + AfterViewInit, + ElementRef, + ViewChildren, + QueryList, + Renderer2, + ChangeDetectorRef, + OnDestroy, +} from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { SelectionModel } from "@angular/cdk/collections"; +import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop"; + +import { Router } from "@angular/router"; +import { debounceTime, finalize } from "rxjs/operators"; +import { FormsModule, FormControl, FormGroup, AbstractControl } from "@angular/forms"; +import { NzDrawerModule, NzDrawerService } from "ng-zorro-antd/drawer"; + +import { DecSafeAny, PageResult, TableListColumns, TableOperation } from "../../types"; +import { TableListOption } from "../table-list-options"; +import { CacheItem, CacheService, StorageService } from "../../storage"; +import { TableOperationComponent } from "../table-operation/table-operation.component"; + +@Pipe({ + name: "operationFilter", +}) +export class OperationPipe implements PipeTransform { + transform(operations: TableOperation[], rowItem: any): TableOperation[] { + return operations?.filter((f) => (f.visible ? f.visible(rowItem) : true)) ?? []; + } +} + +const DATE_RANGE_FIELDS = ["createTime", "updateTime"]; + +@Component({ + selector: "dec-table-list", + templateUrl: "./table-list.component.html", + styleUrls: ["./table-list.component.less"], +}) +export class TableListComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy { + constructor( + // private modal: NzModalService, + private cdr: ChangeDetectorRef, + private el: ElementRef, + private router: Router, + private drawerService: NzDrawerService, + private storage: StorageService, + private cacheService: CacheService + ) {} + + @Input() props!: TableListOption; + + // https://github.com/angular/angular/issues/13761 + @Input() formGroup = new FormGroup({}); + + /** + * 在表格模式下渲染具体每一个列的模板。 + * $implicit:dataItem[col.key] `具体的值`、 + * key:col.key `字段名`、 + * row:dataItem `当前行数据`、 + * column:col `当前列`、 + */ + @Input() renderColumns?: TemplateRef; + + /** + * 不使用表格模式,自定义渲染 + */ + @Input() renderItem?: TemplateRef; + + @Input() action?: TemplateRef; + + @Input() search?: TemplateRef; + + @Input() searchLayout: "horizontal" | "vertical" = "horizontal"; + + /** + * @deprecated + */ + @Input() advanceSearch?: TemplateRef; + + @Input() showTotal?: TemplateRef; + + @Input() beforeReset?: Function; + + @Input() rowClass?: string; + + // @Input() resizeable?: boolean; + + @Output() onRowClick = new EventEmitter(); + + dataSource: DecSafeAny[] = []; + + totalPages = 0; + + public selection = new SelectionModel(true); + + public advanceSearchVisible: boolean = false; + + public optionWidth: string = "200px"; + + private cache?: CacheItem; + + get columns(): TableListColumns[] { + return this.props.columns ?? []; + } + + get operation(): TableOperation[] { + return this.props.operations ?? []; + } + + get createTime() { + return this.formGroup.get("createTime"); + } + + ngOnInit(): void { + this.props.trigger$.pipe(debounceTime(100)).subscribe((e?: any) => { + if (this.props.fetchData) { + this.props.pager.loading = true; + this.selection.clear(); + this.emitState(); + const query = this.formGroup.getRawValue(); + // this.saveQueryDataToCache(query); + const pager = this.parsePager(); + this.props + .fetchData(pager, this.parseQueryValue(), e) + .pipe( + finalize(() => { + this.props.pager.loading = false; + }) + ) + .subscribe((f: PageResult) => { + this.dataSource = f.records ?? f.content; + console.log("this.dataSource", f); + this.props.pager.total = f.total; + this.totalPages = Math.ceil(f.total / this.props.pager.size); + this.checkPage(); + }); + } + }); + + setTimeout(() => { + this.emitState(); + }, 10); + + // 初始化的时候? + if (!this.props.manual) { + this.props.run(); + } + this.getCacheData(); + } + + ngOnDestroy(): void { + // console.log("ngOnDestroy"); + } + + ngAfterViewInit(): void { + const opEl: HTMLDivElement = this.el.nativeElement.querySelector(".hidden-option"); + + if (opEl) { + setTimeout(() => { + const paddingX = 2 * 24; + this.optionWidth = Math.ceil(opEl.offsetWidth + paddingX) + "px"; + this.cdr.detectChanges(); + }); + } + } + + ngOnChanges(changes: SimpleChanges): void { + const props = changes["props"]; + const currentProps = props?.currentValue; + const previousProps = props?.previousValue; + if (currentProps) { + if (previousProps?.["cacheKey"] !== currentProps?.["cacheKey"]) { + this.removeOldCache(); + this.getCacheData(); + } + this.parseColumus(currentProps?.["columns"]); + this.parseFormControls(currentProps?.["queryForm"]); + } + } + + private saveQueryDataToCache(query: {}) { + if (this.cache) { + const { page, size, sort, total } = this.props.pager; + this.cache.setItem({ page, size, sort, total, ...query }); + } + } + + private removeOldCache() { + this.cache?.remove(); + } + + private getCacheData() { + let { cacheKey, cacheTo = [] } = this.props; + + this.formGroup.reset(); + if (!cacheKey) { + cacheKey = `DATA_CACHE_${this.formatePathname()}`; + } + if (!this.cache) { + this.cache = this.cacheService.initCache(cacheKey, [this.router.url, ...cacheTo]); + } + const cacheData = this.cache?.getItem(); + if (cacheData) { + const { page, size, sort, total, ...query } = cacheData; + this.props.pager = { + ...this.props.pager, + total, + page, + size, + sort, + }; + + this.formGroup.patchValue(query); + } + } + + private parsePager() { + let { page, size } = this.props.pager; + if (this.props.pageFromZero) { + page = page - 1; + } + const pager = { page: page, current: page, size, sort: this.formatSort() }; + return pager; + } + + private parseQueryValue(): {} { + const o = Object.create(null); + Object.entries(this.formGroup.getRawValue()).forEach(([k, v]) => { + if (DATE_RANGE_FIELDS.includes(k) && Array.isArray(v)) { + const from = v?.[0] instanceof Date ? v?.[0]?.toISOString() : v[0]; + const to = v?.[1] instanceof Date ? v?.[1]?.toISOString() : v[1]; + o[k] = { from, to }; + } else { + o[k] = v; + } + }); + return o; + } + + private checkPage() { + const maxPages = this.totalPages === 0 ? 1 : this.totalPages; + if (maxPages < this.props.pager.page) { + this.props.pager.page = maxPages; + this.reload(); + } + } + + private emitState() { + this.props.getState$.emit({ selectedKeys: this.selection.selected }); + } + + private parseColumus(currentCols: TableListColumns[]) { + if (this.props.columns.some((s) => s.coverStorage)) { + this.onColumnsChange(); + } + const colsFormStorage: TableListColumns[] = this.storage.get(this.formatePathname()) ?? []; + this.props.columns = currentCols + .map((i: TableListColumns) => { + const storageCol = colsFormStorage.find((f) => f.key === i.key); + let visible = i.visible !== void 0 ? i.visible : true; + let width = i.width; + // if (["createTime", "updateTime"].includes(i.key)) { + // width = "180px"; + // } + return { + ...i, + visible, + width, + ...(storageCol ?? {}), + }; + }) + .sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); + } + + private parseFormControls(formGroup?: FormGroup) { + // if (!this.props.withOutDefaultColumns) { + // this.formGroup.addControl("updateTime", new FormControl(null)); + // this.formGroup.addControl("createTime", new FormControl(null)); + // } + } + + formatSort() { + const { sort } = this.props.pager; + if (!sort) { + return null; + } + const sortArr = [...Object.entries(sort)]?.[0]; + if (!sortArr) { + return null; + } + return `${sortArr[0]},${sortArr[1] === "ascend" ? "asc" : "desc"}`; + } + + colunmsSort(event: unknown) { + const e = event as CdkDragDrop; + moveItemInArray(this.props.columns, e.previousIndex, e.currentIndex); + this.onColumnsChange(); + } + + reload() { + this.props.run(); + } + + onPageChange() { + if (!this.props.frontPagination) { + this.props.run(); + } + } + + doQuery() { + this.props.pager.page = 1; + this.reload(); + } + + reset() { + this.beforeReset?.(); + this.formGroup.reset(); + this.doQuery(); + } + + onSort(v: string | null, fieldName: string) { + this.props.pager.sort = { [fieldName]: v as "ascend" | "descend" }; + this.reload(); + } + + toggleAdvanceSearch(show?: boolean) { + if (typeof show === "boolean") { + this.advanceSearchVisible = show; + } else { + this.advanceSearchVisible = !this.advanceSearchVisible; + } + } + + filteroperation(dataItem: any): TableOperation[] { + return this.operation?.filter((f) => (f.visible ? f.visible(dataItem) : true)) ?? []; + } + + toggleColumnVisible(nzContent: TemplateRef) { + this.drawerService.create({ + nzTitle: "设置展示项", + nzWidth: 280, + nzContent, + nzWrapClassName: "table-settings", + }); + } + + private formatePathname() { + return this.props.columnKey ?? this.router.url.replace(/\//g, "_"); + } + + onColumnsChange() { + const columnStorageKey = `COLUMN_${this.formatePathname()}`; + this.storage.set( + columnStorageKey, + this.columns.map((i, idx) => { + const { key, width, visible } = i; + return { key, width, visible, order: idx }; + }) + ); + } + + onChecked(checked: boolean, rowKey?: DecSafeAny) { + const fn = checked ? "select" : "deselect"; + const rowKeys = rowKey ? [rowKey] : this.dataSource.map((i) => i[this.props.rowKey]); + this.selection[fn](...rowKeys); + this.emitState(); + } + + onTrClick(dataItem: DecSafeAny) { + if (this.onRowClick) { + this.onRowClick.emit(dataItem); + } + } +} diff --git a/projects/cdk/src/table-list/table-operation/table-operation.component.html b/projects/cdk/src/table-list/table-operation/table-operation.component.html new file mode 100644 index 0000000..321537a --- /dev/null +++ b/projects/cdk/src/table-list/table-operation/table-operation.component.html @@ -0,0 +1,30 @@ +
+ + + + {{item.title}} + + + + + + + + 更多操作 + + + +
    +
  • + {{item.title}} +
  • +
+
+
+
\ No newline at end of file diff --git a/projects/cdk/src/table-list/table-operation/table-operation.component.less b/projects/cdk/src/table-list/table-operation/table-operation.component.less new file mode 100644 index 0000000..88222d3 --- /dev/null +++ b/projects/cdk/src/table-list/table-operation/table-operation.component.less @@ -0,0 +1,25 @@ +.operation { + display: inline-block; + min-width: 120px; +} + +.danger { + color: var(--red); +} +.disabled { + cursor: not-allowed; + a { + pointer-events: none; + color: rgba(0, 0, 0, 0.65); + } +} + +.operation { + a { + // color: rgba(0, 0, 0, 0.65); + &:hover { + color: var(--p); + text-decoration: underline; + } + } +} diff --git a/projects/cdk/src/table-list/table-operation/table-operation.component.ts b/projects/cdk/src/table-list/table-operation/table-operation.component.ts new file mode 100644 index 0000000..e2003ad --- /dev/null +++ b/projects/cdk/src/table-list/table-operation/table-operation.component.ts @@ -0,0 +1,61 @@ +import { Component, Input, OnInit } from "@angular/core"; +import { NgxPermissionsService } from "ngx-permissions"; + +import { DecSafeAny, TableOperation } from "../../types"; + +@Component({ + selector: "dec-table-operation", + templateUrl: "./table-operation.component.html", + styleUrls: ["./table-operation.component.less"], +}) +export class TableOperationComponent implements OnInit { + constructor(private premission: NgxPermissionsService) {} + + @Input() options: TableOperation[] = []; + + @Input() maximum: number = 3; + + @Input() rowData: DecSafeAny; + + ngOnInit(): void { + // this.options = this.options.filter(async (f) => { + // if (f.visible) { + // return f.visible(this.rowData); + // } + // if (f.premissions.length) { + // console.log("f.premissions", f.premissions, this.premission.hasPermission(f.premissions)); + // return await this.premission.hasPermission(f.premissions); + // } + // return true; + // }); + this.filterOption(); + } + + async filterOption() { + const o = []; + for (const f of this.options) { + let visible = true; + if (typeof f.visible === "function") { + visible = f.visible(this.rowData); + } + if (!visible) { + continue; + } + if (f.premissions.length) { + const r = await this.premission.hasPermission(f.premissions); + if (r) { + o.push(f); + } + continue; + } + o.push(f); + } + this.options = o; + } + + onClick(item: TableOperation) { + if (item.onClick) { + item?.onClick(this.rowData); + } + } +} diff --git a/projects/cdk/src/table-list/td-overflow.directive.ts b/projects/cdk/src/table-list/td-overflow.directive.ts new file mode 100644 index 0000000..49dd892 --- /dev/null +++ b/projects/cdk/src/table-list/td-overflow.directive.ts @@ -0,0 +1,30 @@ +import { AfterContentInit, AfterViewInit, ChangeDetectorRef, Directive, ElementRef, Input } from "@angular/core"; +import { NzPopoverDirective } from "ng-zorro-antd/popover"; + +@Directive({ + selector: "[jwTdOverflow]", +}) +export class TdOverflowDirective implements AfterViewInit { + @Input("jwTdOverflow") content!: string; + + constructor( + private elementRef: ElementRef, + private popoverDirective: NzPopoverDirective, + private cdr: ChangeDetectorRef + ) {} + + ngOnInit() {} + + ngAfterViewInit(): void { + const element = this.elementRef.nativeElement as HTMLElement; + console.log("element", element.offsetWidth, element.scrollWidth); + // 如果元素的实际宽度大于可见宽度,就使用 nz-popover 指令来显示完整的内容 + if (element.offsetWidth < element.scrollWidth) { + this.popoverDirective.content = this.content; + } else { + this.popoverDirective.trigger = null; + this.popoverDirective.content = "da"; + element.textContent = this.content; + } + } +} diff --git a/projects/cdk/src/types/index.ts b/projects/cdk/src/types/index.ts new file mode 100644 index 0000000..50b1044 --- /dev/null +++ b/projects/cdk/src/types/index.ts @@ -0,0 +1,58 @@ +export type AnyObject = { [k: string]: any }; + +export type DecSafeAny = any; + +export type DecText = number | string; + +export type Augmented = O & AnyObject; + +export interface ResponseType { + body: T; + code: number; + desc: string; + success: boolean; +} + +export interface TableListColumns { + key: string; + title: string; + visible?: boolean; + width?: string; + sort?: boolean; + order?: number; + disabled?: boolean; + coverStorage?: boolean; +} + +export interface TableOperation { + title: string; + href?: string; + link?: string[]; + target?: string; + premissions: string[]; + danger?: boolean; + disabled?: boolean; + onClick?: (v: DecSafeAny) => void; + visible?: (v: DecSafeAny) => boolean; +} + +export interface PageResult { + total: number; + content: T[]; + records: T[]; +} + +export interface AuthInterface { + role: string; + userId: string; + userName: string; + permissionList: AuthPermissionInterface[]; +} + +export interface AuthPermissionInterface { + name: string; + roleId: string; + scope: 1 | 0; + type: number; + value: "true" | "false"; +} diff --git a/projects/cdk/src/utils/index.ts b/projects/cdk/src/utils/index.ts new file mode 100644 index 0000000..596c713 --- /dev/null +++ b/projects/cdk/src/utils/index.ts @@ -0,0 +1,46 @@ +import { AbstractControl, FormControl, FormGroup } from "@angular/forms"; + +export class Utils { + static validateFormGroup(formGroup: FormGroup) { + if (!formGroup.valid) { + Object.keys(formGroup.controls).forEach((field) => { + const control = formGroup.get(field); + if (control instanceof FormControl) { + control.markAsDirty(); + control.markAsTouched({ onlySelf: true }); + control.updateValueAndValidity({ onlySelf: true }); + } else if (control instanceof FormGroup) { + Utils.validateFormGroup(control); + } + }); + } + return formGroup.valid; + } + + static validateFormControl(control: AbstractControl) { + control.markAsDirty(); + control.markAsTouched({ onlySelf: true }); + control.updateValueAndValidity({ onlySelf: true }); + return control.valid; + } + + static queryify(query: {}): string { + const o = Object.create(null); + Object.entries(query).forEach(([k, v]) => { + if (v !== void 0 && v !== null) { + o[k] = v; + } + }); + return new URLSearchParams(o).toString(); + } + + static getHostByEnvironment(prod?: boolean) { + const protocol = window.location.protocol; + const host = prod ? window.location.host : `localhost:${window.location.port}`; + return `${protocol}//${host}`; + } + + // static detectionImagePath(jobId: string, imgName: string) { + // return `/record/${jobId}/detect/${imgName}`; + // } +} diff --git a/projects/cdk/src/validators/index.ts b/projects/cdk/src/validators/index.ts new file mode 100644 index 0000000..2d6d986 --- /dev/null +++ b/projects/cdk/src/validators/index.ts @@ -0,0 +1,66 @@ +import { ValidatorFn, Validators } from "@angular/forms"; + +export class DecValidators { + static required(message?: string): ValidatorFn { + return (control) => { + const error = Validators.required(control); + return error ? { ...error, required: { message } } : null; + }; + } + static maxLength(maxLength: number, message?: string): ValidatorFn { + return (control) => { + const error = Validators.maxLength(maxLength)(control); + if (error) { + error["maxlength"]["message"] = message; + return error; + } + return null; + }; + } + static minLength(maxLength: number, message?: string): ValidatorFn { + return (control) => { + const error = Validators.minLength(maxLength)(control); + if (error) { + error["minlength"]["message"] = message; + return error; + } + return null; + }; + } + static pattern(pattern: RegExp | string, message?: string): ValidatorFn { + return (control) => { + const error = Validators.pattern(pattern)(control); + if (error) { + error["pattern"]["message"] = message; + return error; + } + return null; + }; + } + static min(maxLength: number, message?: string): ValidatorFn { + return (control) => { + const error = Validators.min(maxLength)(control); + if (error) { + error["min"]["message"] = message; + return error; + } + return null; + }; + } + static max(maxLength: number, message?: string): ValidatorFn { + return (control) => { + const error = Validators.max(maxLength)(control); + if (error) { + error["max"]["message"] = message; + return error; + } + return null; + }; + } + static email(message?: string): ValidatorFn { + return (control) => { + const error = Validators.email(control); + return error ? { ...error, email: { message } } : null; + }; + } +} diff --git a/projects/cdk/tsconfig.lib.json b/projects/cdk/tsconfig.lib.json new file mode 100644 index 0000000..543fd47 --- /dev/null +++ b/projects/cdk/tsconfig.lib.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/cdk/tsconfig.lib.prod.json b/projects/cdk/tsconfig.lib.prod.json new file mode 100644 index 0000000..06de549 --- /dev/null +++ b/projects/cdk/tsconfig.lib.prod.json @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/cdk/tsconfig.spec.json b/projects/cdk/tsconfig.spec.json new file mode 100644 index 0000000..ce7048b --- /dev/null +++ b/projects/cdk/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/client/proxy.conf.json b/projects/client/proxy.conf.json new file mode 100644 index 0000000..d6d46c0 --- /dev/null +++ b/projects/client/proxy.conf.json @@ -0,0 +1,15 @@ +{ + "/api": { + "target": "http://47.109.27.8:8081", + "secure": false + }, + "/record": { + "target": "http://47.109.27.8", + "secure": false + }, + "/websocket": { + "target": "http://47.109.27.8:8081", + "secure": false, + "ws": true + } +} \ No newline at end of file diff --git a/projects/client/src/app/app-routing.module.ts b/projects/client/src/app/app-routing.module.ts new file mode 100644 index 0000000..0a1c5b8 --- /dev/null +++ b/projects/client/src/app/app-routing.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; +import { authGuard } from "./core/gaurd/auth.guard"; + +const routes: Routes = [ + { + path: "auth", + loadChildren: () => import("./feature/auth/auth.module").then((m) => m.AuthModule), + }, + { + path: "", + pathMatch: "full", + redirectTo: "detection", + }, + { + path: "detection", + loadChildren: () => import("./feature/detection/detection.module").then((m) => m.DetectionModule), + canActivate: [authGuard], + }, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule], +}) +export class AppRoutingModule {} diff --git a/projects/client/src/app/app.component.html b/projects/client/src/app/app.component.html new file mode 100644 index 0000000..35b5ef8 --- /dev/null +++ b/projects/client/src/app/app.component.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/projects/client/src/app/app.component.less b/projects/client/src/app/app.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/app.component.ts b/projects/client/src/app/app.component.ts new file mode 100644 index 0000000..6823499 --- /dev/null +++ b/projects/client/src/app/app.component.ts @@ -0,0 +1,73 @@ +import { Component, OnInit, Renderer2 } from "@angular/core"; +import { AuthService } from "@client/app/core/services"; +import { delay, finalize } from "rxjs"; + +@Component({ + selector: "app-root", + templateUrl: "./app.component.html", + styleUrls: ["./app.component.less"], +}) +export class AppComponent implements OnInit { + constructor(private api: AuthService, private rd2: Renderer2) {} + + loading = true; + + ngOnInit(): void { + this.loading = true; + this.api + .getSystemInfo() + .pipe( + finalize(() => { + this.loading = false; + }) + ) + .subscribe((res) => { + if (res.theme) { + let style = ""; + Object.entries(res.theme as Record).forEach(([k, v]) => { + if (!["themeName", "themeId"].includes(k)) { + const key = k.replaceAll("_", "-"); + style += `--${key}:${v};`; + if (k === "primary") { + const pRgba = this.parseRGB(v); + style += `--p-rgb:${pRgba.join(",")};`; + style += `--p:${v};`; + } + + if (k === "text_color") { + style += `--thead-color:${v};`; + style += `--input-color:${v};`; + style += `--table-color:${v};`; + } + } + }); + + this.rd2.setAttribute(document.body, "style", style); + } + if (res.systemInfo) { + const { reservedField, systemInfoName } = res.systemInfo; + const title = (reservedField ? `${reservedField} · ` : "") + systemInfoName; + document.title = title; + } + }); + } + + parseRGB(color: string) { + color = color.replace(/\s/g, ""); + + const rgbRegex = /^rgb\((\d+),(\d+),(\d+)\)$/; + const rgbaRegex = /^rgba\((\d+),(\d+),(\d+),(\d+(\.\d+)?)\)$/; + + let matches = color.match(rgbRegex) || color.match(rgbaRegex); + + if (matches) { + const r = parseInt(matches[1], 10); + const g = parseInt(matches[2], 10); + const b = parseInt(matches[3], 10); + + return [r, g, b]; + } else { + return []; + } + } +} diff --git a/projects/client/src/app/app.module.ts b/projects/client/src/app/app.module.ts new file mode 100644 index 0000000..bb4aef1 --- /dev/null +++ b/projects/client/src/app/app.module.ts @@ -0,0 +1,47 @@ +import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http"; +import { NgModule } from "@angular/core"; +import { HashLocationStrategy, LocationStrategy, registerLocaleData } from "@angular/common"; +import { BrowserModule } from "@angular/platform-browser"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { NzConfig, NZ_CONFIG } from "ng-zorro-antd/core/config"; +import { NZ_I18N } from "ng-zorro-antd/i18n"; +import { zh_CN } from "ng-zorro-antd/i18n"; +import zh from "@angular/common/locales/zh"; +import { AppRoutingModule } from "./app-routing.module"; +import { AppComponent } from "./app.component"; +import { SharedModule } from "./shared/shared.module"; +import { NgxPermissionsModule } from "ngx-permissions"; +import { ClientHTTPInterceptor } from "./core/services/client.interceptor"; + +registerLocaleData(zh); + +const ngZorroConfig: NzConfig = { + pageHeader: { + nzGhost: false, + }, +}; + +@NgModule({ + declarations: [AppComponent], + imports: [ + BrowserModule, + BrowserAnimationsModule, + HttpClientModule, + SharedModule, + AppRoutingModule, + NgxPermissionsModule.forRoot(), + ], + providers: [ + { provide: NZ_I18N, useValue: zh_CN }, + + { provide: NZ_CONFIG, useValue: ngZorroConfig }, + + { + provide: LocationStrategy, + useClass: HashLocationStrategy, + }, + { provide: HTTP_INTERCEPTORS, useClass: ClientHTTPInterceptor, multi: true }, + ], + bootstrap: [AppComponent], +}) +export class AppModule {} diff --git a/projects/client/src/app/core/gaurd/auth.guard.ts b/projects/client/src/app/core/gaurd/auth.guard.ts new file mode 100644 index 0000000..0e115ec --- /dev/null +++ b/projects/client/src/app/core/gaurd/auth.guard.ts @@ -0,0 +1,27 @@ +import { inject } from "@angular/core"; +import { Router } from "@angular/router"; +import { decConfigToken } from "@cdk/public-api"; +import { map } from "rxjs"; +import { DetectionApiService } from "../services"; + +export const authGuard = () => { + const api = inject(DetectionApiService); + const router = inject(Router); + const decConfig = inject(decConfigToken); + // const token = localStorage.getItem(decConfig.localStroageKey); + + // if (!token) { + // router.navigate([decConfig.loginUrl]); + // return false; + // } + return api.getAllPoint().pipe( + map((res) => { + if (res) { + return true; + } else { + router.navigate([decConfig.loginUrl]); + return false; + } + }) + ); +}; diff --git a/projects/client/src/app/core/gaurd/permisson.guard.ts b/projects/client/src/app/core/gaurd/permisson.guard.ts new file mode 100644 index 0000000..2409789 --- /dev/null +++ b/projects/client/src/app/core/gaurd/permisson.guard.ts @@ -0,0 +1,33 @@ +import { inject } from "@angular/core"; +import { + ActivatedRoute, + ActivatedRouteSnapshot, + CanActivateChildFn, + CanActivateFn, + Route, + Router, + RouterStateSnapshot, +} from "@angular/router"; +import { AuthInterface } from "@cdk/public-api"; +import { NgxPermissionsService } from "ngx-permissions"; + +export const PermissionLoadGuard: CanActivateFn = async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const permissionsService = inject(NgxPermissionsService); + const auth = localStorage.getItem("auth"); + if (auth) { + try { + const authData = JSON.parse(auth) as AuthInterface; + if (Array.isArray(authData.permissionList)) { + const permissionList = authData.permissionList; + const permissions = permissionList.reduce((a, c) => { + if (c.scope === 0 && c.value === "true") { + return a.concat(c.roleId); + } + return a; + }, [] as string[]); + permissionsService.loadPermissions(permissions); + } + } catch (error) {} + } + return true; +}; diff --git a/projects/client/src/app/core/services/auth.service.ts b/projects/client/src/app/core/services/auth.service.ts new file mode 100644 index 0000000..c6142d8 --- /dev/null +++ b/projects/client/src/app/core/services/auth.service.ts @@ -0,0 +1,56 @@ +import { HttpClient, HttpParams, HttpResponse } from "@angular/common/http"; +import { Inject, Injectable } from "@angular/core"; +import { DecConfig, decConfigToken } from "@cdk/public-api"; +import { AnyObject, ResponseType } from "@cdk/types"; +import { environment } from "@client/environments/environment"; +import { map, of, tap } from "rxjs"; + +export interface SystemInfoInterface { + theme?: Record; + info?: { logoImg: string; systemInfoName: string }; +} + +@Injectable({ + providedIn: "root", +}) +export class AuthService { + constructor(private http: HttpClient, @Inject(decConfigToken) private decConfig: Required) {} + + private system: SystemInfoInterface = {}; + + private systemLoaded = false; + + getSystemInfo() { + if (this.systemLoaded) { + return of(this.system); + } + return this.http.post("/api/config/selectSystemInfoById", {}).pipe( + map((res) => { + return res.body; + }), + tap((res) => { + if (res.systemInfo) { + localStorage.setItem("systemInfo", JSON.stringify(res.systemInfo)); + this.system.info = res.systemInfo; + } + if (res.theme) { + localStorage.setItem("theme", JSON.stringify(res.theme)); + this.system.theme = res.theme; + } + console.log("this.system", this.system); + this.systemLoaded = true; + }) + ); + } + + login(vals: AnyObject) { + const auth = { ...vals, clientVersion: environment.clientVersion, clientType: environment.clientType }; + return this.http.post("/api/user/login", auth).pipe( + tap((res) => { + if (res.success) { + localStorage.setItem("auth", JSON.stringify(res.body)); + } + }) + ); + } +} diff --git a/projects/client/src/app/core/services/client.interceptor.ts b/projects/client/src/app/core/services/client.interceptor.ts new file mode 100644 index 0000000..e639fbc --- /dev/null +++ b/projects/client/src/app/core/services/client.interceptor.ts @@ -0,0 +1,43 @@ +import { Inject, Injectable } from "@angular/core"; +import { + HttpRequest, + HttpHandler, + HttpEvent, + HttpInterceptor, + HttpErrorResponse, + HttpResponse, +} from "@angular/common/http"; +import { catchError, Observable, switchMap, tap, throwError, timer } from "rxjs"; +import { Router } from "@angular/router"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { ResponseType } from "@cdk/types"; +import { AuthService } from "./auth.service"; + +@Injectable({ providedIn: "root" }) +export class ClientHTTPInterceptor implements HttpInterceptor { + constructor(private auth: AuthService, private router: Router) {} + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + return this.handleResult(next, req); + } + + private handleResult(next: HttpHandler, authReq: HttpRequest): Observable> { + return next.handle(authReq).pipe( + catchError((err: HttpErrorResponse) => { + const throwErr = throwError(() => err); + + const error: ResponseType = err.error; + + if (error.success === false) { + if (error.code === 401) { + this.auth.login({ uid: "", password: "" }).subscribe(() => { + this.router.navigate(["/"]); + }); + } + } + + return throwErr; + }) + ); + } +} diff --git a/projects/client/src/app/core/services/detection-api.service.ts b/projects/client/src/app/core/services/detection-api.service.ts new file mode 100644 index 0000000..d844b95 --- /dev/null +++ b/projects/client/src/app/core/services/detection-api.service.ts @@ -0,0 +1,269 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { AnyObject, Augmented, DecText, ResponseType } from "@cdk/types"; +import { Utils } from "@cdk/utils"; +import { AlarmDTO, AlgorithmDTO } from "@client/dtos"; +import { + DeviceDTO, + PointDTO, + PointGroupDTO, + PointStatusEnum, + PoleItemDTO, + PoleQueryDTO, + PowerStationDTO, +} from "@client/dtos/point.dto"; +import { map, Observable, of, tap } from "rxjs"; + +@Injectable({ + providedIn: "root", +}) +export class DetectionApiService { + constructor(private http: HttpClient) {} + + allPoint: PowerStationDTO[] = []; + + imgBaseUrl: string = ""; + + loadImage(jobId: string, img: string) { + return this.http.post>("/api/img/base", { jobId, img }).pipe( + map((res) => { + return "data:image/jpeg;base64," + res.body; + }) + ); + } + + loadImages(url: string): Promise { + return new Promise((resolve, reject) => { + if (url.startsWith("data:image/jpeg;base64,")) { + resolve(url); + return; + } + this.http.get(url, { responseType: "blob" }).subscribe({ + next(blob: Blob) { + // setTimeout(() => { + // resolve(""); + // }, 150); + const reader = new FileReader(); + reader.onloadend = () => { + resolve(reader.result as string); + }; + reader.readAsDataURL(blob); + }, + error(error) { + reject(new Error(`Failed to load image ${url}, ${error}`)); + }, + }); + }); + } + + getAllPoint(force?: boolean) { + if (this.allPoint.length > 0 && !force) { + return of(this.allPoint); + } + return this.http.post>("/api/point/getAll", {}).pipe( + map((res) => { + return res.body.map((station) => { + return { + ...station, + groupList: station.groupList.map((group) => { + let status = PointStatusEnum.NORMAL; + if (group.pointList.some((s) => s.status === PointStatusEnum.ABNORMAL)) { + status = PointStatusEnum.ABNORMAL; + } else if (group.pointList.some((s) => s.status === PointStatusEnum.DISCONNECT)) { + status = PointStatusEnum.DISCONNECT; + } + return { + ...group, + status, + }; + }), + }; + }); + }), + tap((points) => { + this.allPoint = points; + }) + ); + } + + getImageBaseUrl(force?: boolean) { + if (!force) { + if (this.imgBaseUrl) { + return of(this.imgBaseUrl); + } + } + return this.http.post>("/api/img/path", {}).pipe( + map((res) => { + return res.body; + }), + tap((imgBaseUrl) => { + this.imgBaseUrl = imgBaseUrl; + }) + ); + } + + getFlatPoints(): Observable<{ points: PointDTO[]; groups: PointGroupDTO[] }> { + return this.getAllPoint().pipe( + map((p) => { + const groups = p?.[0]?.groupList; + const points: PointDTO[] = []; + if (Array.isArray(groups)) { + groups.forEach((g) => { + points.push( + ...g.pointList.map((p) => ({ + ...p, + gid: g.motorGroupId, + gname: g.name, + })) + ); + }); + } + return { points, groups }; + }) + ); + } + + getNotice() { + return this.http.post>("/api/detect/alarm", null); + } + + getRealtimeJob(pointId: DecText) { + return this.http.post>("/api/detect/getRealtimeJob", { pointId }); + } + + getDetcttionHistoryPage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post(`/api/history/query`, q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.records, + }; + }) + ); + } + + getHistoryDetail(jobId: DecText) { + return this.http + .post>(`/api/history/detail`, { + jobId, + current: 1, + size: 5, + }) + .pipe( + map((r) => { + return r.body.dataList; + }) + ); + } + + exportWord(data: {}) { + return this.http.post("/api/history/exportWord", data, { + observe: "response", + responseType: "blob" as "json", + }); + } + + exportExcel(data: {}) { + return this.http.post("/api/history/exportExcel", data, { + observe: "response", + responseType: "blob" as "json", + }); + } + + getQuery(jobId: string) { + return this.http.post>("/api/detect/query", { jobId }).pipe( + map((r) => { + return r; + return { + body: {}, + success: true, + }; + }) + ); + // .pipe( + // map((i) => { + // i.body[5][2].value = 6; + // i.body[8][8].value = 116; + // i.body[4][8].alarm = true; + // i.body[2][8].alarm = true; + // i.body[1][8].alarm = true; + // i.body[1][10].alarm = true; + // i.body[20][10].alarm = true; + // i.body[4][8].alarm = true; + // i.body[15][9].alarm = true; + // i.body[11][1].alarm = true; + + // return i; + // }) + // ); + } + + getImg(jobId: string) { + return this.http.post>>("/api/detect/getImg", { jobId }); + } + + getBase64Image(o: { jobID: string; img: string }) { + return this.http.post("/api/img/base", o); + } + + getFeatures(pointId?: string) { + // return of({ + // body: { + // line: "引出线变形", + // bolt: "螺栓松动", + // temperature: "无线测温", + // pole: "磁极开闸", + // }, + // }); + return this.http.post>>("/api/analysis/features", { pointId }); + } + + manualDetection(pointId: string) { + return this.http.post("/api/detect/manualDetection", { pointId }); + } + + getAnalysisChartData(q: {}) { + return this.http.post[]>>>("/api/analysis/chartData", q); + } + + getVersion() { + return this.http.post("/api/config/selectVersion", null); + } + + getExportConfig(config: {}) { + return this.http.post("/api/config/select", config); + } + + updateExportConfig(config: {}) { + return this.http.post("/api/config/update", config); + } + + resetPointData(pointId: string) { + return this.http.post("/api/point/reset", { pointId }); + } + + savePointEnable(data: AnyObject[]) { + return this.http.post("/api/point/switch", data); + } + + getAlgorithm() { + return this.http.post>("/api/algorithm/selectParams", null); + } + + saveAlgorithm(vals: {}) { + return this.http.post("/api/algorithm/updateParams", vals); + } + + saveTemperatureSetting(vals: {}) { + return this.http.post>("/api/device/updateTemp", vals); + } + + getTemperatureSettings() { + return this.http.post("/api/device/selectTemp", null); + } + + getDeviceListByPointId(pointId: string) { + return this.http.post>("/api/device/select", { pointId }); + } +} diff --git a/projects/client/src/app/core/services/index.ts b/projects/client/src/app/core/services/index.ts new file mode 100644 index 0000000..34c8587 --- /dev/null +++ b/projects/client/src/app/core/services/index.ts @@ -0,0 +1,4 @@ +export * from "./auth.service"; +export * from "./detection-api.service"; +export * from "./websocket-api.service"; +export * from "./utils.service"; diff --git a/projects/client/src/app/core/services/utils.service.ts b/projects/client/src/app/core/services/utils.service.ts new file mode 100644 index 0000000..08cfb78 --- /dev/null +++ b/projects/client/src/app/core/services/utils.service.ts @@ -0,0 +1,11 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { ResponseType } from "@cdk/types"; +import { map } from "rxjs"; + +@Injectable({ + providedIn: "root", +}) +export class UtilsService { + constructor(private http: HttpClient) {} +} diff --git a/projects/client/src/app/core/services/websocket-api.service.ts b/projects/client/src/app/core/services/websocket-api.service.ts new file mode 100644 index 0000000..798cf82 --- /dev/null +++ b/projects/client/src/app/core/services/websocket-api.service.ts @@ -0,0 +1,65 @@ +import { Injectable } from "@angular/core"; +import { WebSocketSubject } from "rxjs/webSocket"; +import { environment } from "@client/environments/environment"; + +@Injectable({ + providedIn: "root", +}) +export class WebsocketApiService { + connect(wsUrl: string): WebSocketSubject { + const protocol = window.location.protocol.replace("http", "ws"); + const host = environment.production ? window.location.host : `localhost:${window.location.port}`; + wsUrl = `${protocol}//${host}${wsUrl}`; + console.log("wsUrl", environment, wsUrl); + return new WebSocketSubject(wsUrl); + } +} +// const CHAT_URL = "ws://localhost:8082"; + +// @Injectable({ +// providedIn: "root", +// }) +// export class WebsocketApiService { +// private subject?: AnonymousSubject; + +// public messages: Subject; + +// constructor() { +// this.messages = >this.connect(CHAT_URL).pipe( +// map((response: MessageEvent): AnyObject => { +// console.log(response.data); +// let data = JSON.parse(response.data); +// return data; +// }) +// ); +// } + +// public connect(url: string): AnonymousSubject { +// if (!this.subject) { +// this.subject = this.create(url); +// console.log("Successfully connected: " + url); +// } +// return this.subject; +// } + +// private create(url: string): AnonymousSubject { +// let ws = new WebSocket(url); +// let observable = new Observable((obs: Observer) => { +// ws.onmessage = obs.next.bind(obs); +// ws.onerror = obs.error.bind(obs); +// ws.onclose = obs.complete.bind(obs); +// return ws.close.bind(ws); +// }); +// let observer = { +// error: () => {}, +// complete: () => {}, +// next: (data: AnyObject) => { +// console.log("Message sent to websocket: ", data, ws.readyState, WebSocket.OPEN); +// if (ws.readyState === WebSocket.OPEN) { +// ws.send(JSON.stringify(data)); +// } +// }, +// }; +// return new AnonymousSubject(observer, observable); +// } +// } diff --git a/projects/client/src/app/feature/auth/auth-routing.module.ts b/projects/client/src/app/feature/auth/auth-routing.module.ts new file mode 100644 index 0000000..80cd35a --- /dev/null +++ b/projects/client/src/app/feature/auth/auth-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; +import { LoginComponent } from "./pages"; + +const routes: Routes = [ + { + path: "login", + component: LoginComponent, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class AuthRoutingModule {} diff --git a/projects/client/src/app/feature/auth/auth.module.ts b/projects/client/src/app/feature/auth/auth.module.ts new file mode 100644 index 0000000..76db313 --- /dev/null +++ b/projects/client/src/app/feature/auth/auth.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from "@angular/core"; +import { SharedModule } from "@client/app/shared/shared.module"; +import { AuthRoutingModule } from "./auth-routing.module"; + +import { LoginComponent } from "./pages"; + +@NgModule({ + declarations: [LoginComponent], + imports: [SharedModule, AuthRoutingModule], +}) +export class AuthModule {} diff --git a/projects/client/src/app/feature/auth/pages/index.ts b/projects/client/src/app/feature/auth/pages/index.ts new file mode 100644 index 0000000..97961b0 --- /dev/null +++ b/projects/client/src/app/feature/auth/pages/index.ts @@ -0,0 +1 @@ +export * from "./login/login.component"; diff --git a/projects/client/src/app/feature/auth/pages/login/login.component.html b/projects/client/src/app/feature/auth/pages/login/login.component.html new file mode 100644 index 0000000..41adfc1 --- /dev/null +++ b/projects/client/src/app/feature/auth/pages/login/login.component.html @@ -0,0 +1,57 @@ +
+ +
+ + +
+ +
+
\ No newline at end of file diff --git a/projects/client/src/app/feature/auth/pages/login/login.component.less b/projects/client/src/app/feature/auth/pages/login/login.component.less new file mode 100644 index 0000000..4505de9 --- /dev/null +++ b/projects/client/src/app/feature/auth/pages/login/login.component.less @@ -0,0 +1,23 @@ +.login { + width: 320px; + height: 404px; + h1 { + margin-bottom: 12px; + font-size: 40px; + font-weight: 400; + } + p { + font-size: 16px; + line-height: 24px; + letter-spacing: 0.23em; + text-shadow: 0px 8px 20px rgba(0, 0, 0, 0.1); + } + + form { + margin-top: 48px; + } + + .btn { + margin-top: 16px; + } +} diff --git a/projects/client/src/app/feature/auth/pages/login/login.component.ts b/projects/client/src/app/feature/auth/pages/login/login.component.ts new file mode 100644 index 0000000..bb10991 --- /dev/null +++ b/projects/client/src/app/feature/auth/pages/login/login.component.ts @@ -0,0 +1,50 @@ +import { Router } from "@angular/router"; +import { Component, Inject, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Utils } from "@cdk/utils"; +import { DecValidators } from "@cdk/validators"; +import { PUBLIC_PATH } from "@cdk/dec-module/base-href"; +import { AuthService } from "@client/app/core/services"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { finalize, lastValueFrom, tap } from "rxjs"; + +@Component({ + selector: "app-login", + templateUrl: "./login.component.html", + styleUrls: ["./login.component.less"], +}) +export class LoginComponent implements OnInit { + constructor( + @Inject(PUBLIC_PATH) public baseHref: string, + private msg: NzMessageService, + private api: AuthService, + private router: Router + ) {} + + public loginForm = new FormGroup({ + uid: new FormControl("", [DecValidators.required("请输入账户")]), + password: new FormControl("", [DecValidators.required("请输入密码")]), + }); + + public loading: boolean = false; + + system$ = this.api.getSystemInfo(); + + ngOnInit(): void {} + + async onLogin() { + if (Utils.validateFormGroup(this.loginForm)) { + const { value } = this.loginForm; + this.loading = true; + const res = await lastValueFrom( + this.api.login(value).pipe( + finalize(() => { + this.loading = false; + }) + ) + ); + this.msg.success(res.desc); + this.router.navigate(["/"]); + } + } +} diff --git a/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.html b/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.html new file mode 100644 index 0000000..4683861 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.html @@ -0,0 +1,153 @@ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +    +    +    +    +    +    +    +    +    +    +    +    +    +    +    +    +    +    +   + #{{pole.zone}} + 开匝 + + + + + + + + + + + + + + + + + + + + + #{{pole.zone}}磁极 + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.less b/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.less new file mode 100644 index 0000000..8c37bf2 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.less @@ -0,0 +1,204 @@ +:host { + display: block; + width: 100%; + height: 100%; + overflow: hidden; +} + +.circle { + display: block; + width: 400px; + height: 400px; + border: 3px solid #6e5ac9; + box-sizing: border-box; +} + +.inner-bg { + stroke: #183265; + stroke-width: 4px; +} + +.piepath { + .tooltip { + opacity: 0; + pointer-events: none; + } + path { + // stroke: #fff; + stroke-width: 4px; + fill: transparent; + position: relative; + opacity: 0.1; + &.selected { + stroke: #68bbe9; + opacity: 1; + // & + .textpath { + // display: block; + // } + } + + &:hover { + stroke: #68bbe9; + opacity: 0.6; + & + .tooltip { + opacity: 1; + } + } + } +} + +.center-img { + position: absolute; + top: 50%; + left: 50%; + z-index: 100; + width: 225px; + height: 225px; + transform: translate(-50%, -50%) scale(1.5); + border: 1px solid #2b529a; + border-radius: 50%; + // background-color: rgba(255, 255, 255, 0.05); + transform-origin: center; + pointer-events: none; + + img { + position: absolute; + top: 50%; + left: 50%; + + transform-origin: center; + + &:nth-child(1) { + transform: translate(-60%, -131%) rotate(-2deg); + } + &:nth-child(2) { + transform: translate(31%, -127%) rotate(18deg); + } + &:nth-child(3) { + transform: translate(114%, -115%) rotate(36deg); + } + &:nth-child(4) { + transform: translate(180%, -96%) rotate(54deg); + } + &:nth-child(5) { + transform: translate(219%, -73%) rotate(72deg); + } + &:nth-child(6) { + transform: translate(232%, -47%) rotate(90deg); + } + &:nth-child(7) { + transform: translate(217%, -21%) rotate(108deg); + } + &:nth-child(8) { + transform: translate(174%, 2%) rotate(126deg); + } + &:nth-child(9) { + transform: translate(109%, 20%) rotate(144deg); + } + &:nth-child(10) { + transform: translate(30%, 31%) rotate(162deg); + } + &:nth-child(11) { + transform: translate(-57%, 35%) rotate(180deg); + } + &:nth-child(12) { + transform: translate(-147%, 31%) rotate(196deg); + } + &:nth-child(13) { + transform: translate(-228%, 20%) rotate(214deg); + } + &:nth-child(14) { + transform: translate(-295%, 3%) rotate(232deg); + } + &:nth-child(15) { + transform: translate(-336%, -20%) rotate(250deg); + } + &:nth-child(16) { + transform: translate(-352%, -45%) rotate(268deg); + } + &:nth-child(17) { + transform: translate(-340%, -71%) rotate(286deg); + } + &:nth-child(18) { + transform: translate(-298%, -95%) rotate(304deg); + } + &:nth-child(19) { + transform: translate(-234%, -114%) rotate(322deg); + } + &:nth-child(20) { + transform: translate(-154%, -126%) rotate(343deg); + } + } +} + +.box { + width: 500px; + height: 500px; + margin: 0 auto; + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + position: relative; + z-index: 10; + + .polygons { + pointer-events: none; + path { + stroke: rgba(255, 255, 255, 0.85); + stroke-width: 2px; + fill: rgba(255, 255, 255, 0.45); + } + } + + svg { + display: block; + // border: 1px solid red; + transition: transform 0.3s; + transform-origin: center; + position: relative; + z-index: 10; + text { + font-size: 30px; + } + } + + .action { + position: absolute; + bottom: 20px; + right: 20px; + button { + margin: 6px; + } + } +} +.lines { + .alarm { + stroke: var(--red-1) !important; + } +} +.points { + circle { + fill: #fff; + &.alarm { + fill: var(--red-1); + } + } +} + +.textpath { + pointer-events: none; + path { + stroke: none; + fill: none; + } +} + +.center { + fill: linear-gradient(to right, red, yellow); + opacity: 0.99; +} + +.text { + fill: #5eb7e8; +} diff --git a/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.ts b/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.ts new file mode 100644 index 0000000..8537ff7 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/detection-graphics/detection-graphics.component.ts @@ -0,0 +1,375 @@ +import { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + Renderer2, + SimpleChanges, + ViewChild, +} from "@angular/core"; +import { PoleItemDTO } from "@client/dtos"; +import { BehaviorSubject } from "rxjs"; + +class PathLine { + constructor(public cx: number, public cy: number, public r: number, public dr: number = 0) {} + x0: number = 0; + y0: number = 0; + x1: number = 0; + y1: number = 0; + angle: number = 0; +} + +class Point { + constructor(public x: number, public y: number, public r: number = 10) {} +} + +interface Pie { + piePath: string; + textPath: string; + polygons: [path: string, path: string]; + points: [Point, Point, Point, Point, Point, Point, Point, Point]; +} + +export type PoleGroupInterface = { + zone: number; + pole: PoleItemDTO; + bolt: Array; + line: Array; +}; + +const createDefaultPole = (idx: number) => { + return { + zone: idx + 1, + pole: { + alarm: false, + img: "img1.jpg", + position: 1, + type: "pole", + value: 0, + zone: 1, + }, + line: Array.from({ length: 2 }, (_, i) => { + return { + alarm: false, + img: "img1.jpg", + position: i + 1, + type: "line", + value: 0, + zone: idx, + }; + }), + bolt: Array.from({ length: 8 }, (_, i) => { + return { + alarm: false, + img: "img1.jpg", + position: i + 1, + type: "bolt", + value: 0, + zone: idx, + }; + }), + } as PoleGroupInterface; +}; + +@Component({ + selector: "app-detection-graphics", + templateUrl: "./detection-graphics.component.html", + styleUrls: ["./detection-graphics.component.less"], +}) +export class DetectionGraphicsComponent implements OnDestroy, OnInit, AfterViewInit, OnChanges { + constructor(private rd2: Renderer2, private cdr: ChangeDetectorRef) {} + + @Input() props$!: BehaviorSubject<{ poles: Array }>; + + @Input() public selectedZone?: number; + + poleNum: number = 0; + + @Output() onPoleSelect = new EventEmitter(); + + @ViewChild("wapper") wapper!: ElementRef; + + @ViewChild("box") box!: ElementRef; + + @ViewChild("centerImage") centerImage!: ElementRef; + + public poles: Array = []; + + public size: number = 800; + + public d: string = ""; + + public pies: Pie[] = []; + + public rd = Math.ceil(Math.random() * 10); + + public scale: number = 1; + + public borderPath = ""; + + public RATIO = 1; + + private isDragging = false; + + private startX = 0; + + private startY = 0; + + private translateX = 0; + + private translateY = 0; + + private readonly MIN_SCALE = 1; + + private readonly MAX_SCALE = 2.5; + + ngOnChanges(changes: SimpleChanges): void {} + + ngOnInit(): void { + this.RATIO = this.size / 800; + this.drawBorderPath(); + + this.props$.subscribe((r) => { + // console.log('graphics-poles', r) + if (r.poles.length > 0) { + this.poles = r.poles; + this.poleNum = r.poles.length; + this.createPie(); + } + }); + } + + ngAfterViewInit(): void { + this.dragMove(); + this.setBoxSize(); + } + + ngOnDestroy(): void { + this.wapper?.nativeElement.removeEventListener("mousedown", this.onMouseDown); + this.box?.nativeElement.removeEventListener("mousemove", this.onMouseMove); + document.removeEventListener("mouseup", this.onMouseUp); + } + + onSelect(poleZone: number) { + // this.selectedZone = poleZone; + this.onPoleSelect.emit(poleZone); + } + + drawBorderPath() { + const { RATIO } = this; + + const d1 = 700 * RATIO; + const d2 = 60 * RATIO; + const d3 = 10 * RATIO; + const d4 = 900 * RATIO; + const d5 = 720 * RATIO; + + const d7 = 1540 * RATIO; + const d8 = 1590 * RATIO; + + this.borderPath = `M${d1},${d2} L${d1},${d3} L${d4},${d3} L${d4},${d2} + A ${d5} ${d5} 0 0 1 ${d7} ${d1} + L${d8},${d1} L${d8},${d4} L${d7},${d4} + A ${d5} ${d5} 0 0 1 ${d4} ${d7} + L${d4},${d8} L${d1},${d8} L${d1},${d7} + A ${d5} ${d5} 0 0 1 ${d2} ${d4} + L${d3},${d4} L${d3},${d1} L${d2},${d1} + A ${d5} ${d5} 0 0 1 ${d1} ${d2}`; + } + + createPie() { + const { size, RATIO, poleNum } = this; + + const cx = size; + const cy = size; + const radius = size - 80 * RATIO; + + const pie = new PathLine(cx, cy, radius); + + const polygon1_1 = new PathLine(cx, cy, 710 * RATIO, 0.6 * RATIO); + const polygon1_2 = new PathLine(cx, cy, 675 * RATIO, 0.7 * RATIO); + const polygon2_1 = new PathLine(cx, cy, 660 * RATIO, 0.7 * RATIO); + const polygon2_2 = new PathLine(cx, cy, 625 * RATIO, 0.75 * RATIO); + + const dot1 = new PathLine(cx, cy, 700 * RATIO, 1.3 * RATIO); + const dot2 = new PathLine(cx, cy, 685 * RATIO, 1.4 * RATIO); + const dot3 = new PathLine(cx, cy, 650 * RATIO, 1.3 * RATIO); + const dot4 = new PathLine(cx, cy, 635 * RATIO, 1.4 * RATIO); + + let sweep = 0; + + if ((1 / poleNum) * 360 > 180) { + sweep = 1; + } + this.pies = Array.from({ length: this.poleNum }, (_, idx) => { + this.calcPos(pie, idx); + + this.calcPos(polygon1_1, idx); + this.calcPos(polygon1_2, idx); + this.calcPos(polygon2_1, idx); + this.calcPos(polygon2_2, idx); + + this.calcPos(dot1, idx); + this.calcPos(dot2, idx); + this.calcPos(dot3, idx); + this.calcPos(dot4, idx); + + const dotSize = 4 * RATIO; + + // this.poles.push(createDefaultPole(idx)); + + return { + textPath: `M ${cx} ${cy},L ${pie.x0} ${pie.y0}`, + piePath: `M ${cx} ${cy},L ${pie.x0} ${pie.y0} A ${pie.r} ${pie.r} 0 ${sweep} 1 ${pie.x1} ${pie.y1} Z`, + polygons: [ + `M ${polygon1_1.x0} ${polygon1_1.y0} A ${polygon1_1.r} ${polygon1_1.r} 0 ${sweep} 1 ${polygon1_1.x1} ${polygon1_1.y1} L ${polygon1_2.x1} ${polygon1_2.y1} A ${polygon1_2.r} ${polygon1_2.r} 0 ${sweep} 0 ${polygon1_2.x0} ${polygon1_2.y0} Z`, + `M ${polygon2_1.x0} ${polygon2_1.y0} A ${polygon2_1.r} ${polygon2_1.r} 0 ${sweep} 1 ${polygon2_1.x1} ${polygon2_1.y1} L ${polygon2_2.x1} ${polygon2_2.y1} A ${polygon2_2.r} ${polygon2_2.r} 0 ${sweep} 0 ${polygon2_2.x0} ${polygon2_2.y0} Z`, + ], + dots: [dot1, dot2, dot3, dot4], + points: [ + new Point(dot1.x0, dot1.y0, dotSize), + new Point(dot1.x1, dot1.y1, dotSize), + new Point(dot2.x0, dot2.y0, dotSize), + new Point(dot2.x1, dot2.y1, dotSize), + new Point(dot3.x0, dot3.y0, dotSize), + new Point(dot3.x1, dot3.y1, dotSize), + new Point(dot4.x0, dot4.y0, dotSize), + new Point(dot4.x1, dot4.y1, dotSize), + ], + }; + }); + } + + calcPos(line: PathLine, idx: number): PathLine { + const { poleNum } = this; + const n = poleNum; + let { cx, cy, dr, r } = line; + let currentIndex = 0; + currentIndex = idx + 1; + if (idx === 0) { + line.x0 = cx + r * Math.cos((dr * Math.PI) / 180); + line.y0 = cy + r * Math.sin((dr * Math.PI) / 180); + line.angle = (currentIndex / n) * 360; + line.x1 = cx + r * Math.cos(((line.angle - dr) * Math.PI) / 180); + line.y1 = cy + r * Math.sin(((line.angle - dr) * Math.PI) / 180); + } else if (idx > 0 && idx < n - 1) { + line.x0 = cx + r * Math.cos(((line.angle + dr) * Math.PI) / 180); + line.y0 = cy + r * Math.sin(((line.angle + dr) * Math.PI) / 180); + line.angle = (currentIndex / n) * 360; + line.x1 = cx + r * Math.cos(((line.angle - dr) * Math.PI) / 180); + line.y1 = cy + r * Math.sin(((line.angle - dr) * Math.PI) / 180); + } else { + line.x0 = cx + r * Math.cos(((line.angle + dr) * Math.PI) / 180); + line.y0 = cy + r * Math.sin(((line.angle + dr) * Math.PI) / 180); + line.x1 = cx + r * Math.cos((-dr * Math.PI) / 180); + line.y1 = cy + r * Math.sin((-dr * Math.PI) / 180); + } + return line; + } + + // getPole(idx: number): PoleGroupInterface { + + // console.log("defaultPole", defaultPole); + // return defaultPole as PoleGroupInterface; + // } + + handleNumber(m: number) { + const n = 250; + if (m < -n) { + return -n; + } else if (m > n) { + return n; + } else { + return m; + } + } + + onMouseDown = (event: MouseEvent) => { + event.preventDefault(); + this.isDragging = true; + this.startX = event.clientX - this.translateX; + this.startY = event.clientY - this.translateY; + }; + + onMouseUp = () => { + this.isDragging = false; + }; + + onMouseMove = (event: MouseEvent) => { + if (this.isDragging) { + event.preventDefault(); + let x = event.clientX - this.startX; + let y = event.clientY - this.startY; + + this.translateX = this.handleNumber(x); + this.translateY = this.handleNumber(y); + this.modifyTransform(); + } + }; + + dragMove() { + this.wapper.nativeElement.addEventListener("mousedown", this.onMouseDown); + this.box.nativeElement.addEventListener("mousemove", this.onMouseMove); + document.addEventListener("mouseup", this.onMouseUp); + } + + @HostListener("window:resize") + onResize() { + this.setBoxSize(); + } + + onMouseWheel(event: WheelEvent): void { + event.preventDefault(); + const scaleChange = -event.deltaY / 2000; + this.scale += scaleChange; + if (this.scale < this.MIN_SCALE) { + this.scale = this.MIN_SCALE; + } else if (this.scale > this.MAX_SCALE) { + this.scale = this.MAX_SCALE; + } + + this.modifyTransform(); + } + + modifyTransform() { + this.rd2.setStyle( + this.box.nativeElement, + "transform", + `scale(${this.scale}) translate(${this.translateX}px, ${this.translateY}px)` + ); + } + + setBoxSize() { + if (this.wapper.nativeElement) { + setTimeout(() => { + const { width, height } = this.wapper.nativeElement.getBoundingClientRect(); + const min = Math.min(width, height); + const svg = this.box.nativeElement.querySelector("svg"); + this.rd2.setStyle(this.box.nativeElement, "width", width + "px"); + this.rd2.setStyle(this.box.nativeElement, "height", height + "px"); + this.rd2.setStyle(svg, "width", min + "px"); + this.rd2.setStyle(svg, "height", min + "px"); + const scale = min / (225 * 1.35); + this.rd2.setStyle(this.centerImage.nativeElement, "transform", `translate(-50%, -50%) scale(${scale})`); + }, 70); + } + } + + onScale(sc: number) { + this.scale = this.scale + sc; + } + + onScroll(event: any) { + event.preventDefault(); + const delta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail)); + const zoom = delta > 0 ? 1.1 : 0.9; // 缩放系数 + this.scale *= zoom; + } +} diff --git a/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.html b/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.html new file mode 100644 index 0000000..96ee28b --- /dev/null +++ b/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.html @@ -0,0 +1,4 @@ + + {{value.value}} + +- \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.less b/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.ts b/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.ts new file mode 100644 index 0000000..59eaad0 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/detection-value/detection-value.component.ts @@ -0,0 +1,12 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "app-detection-value", + templateUrl: "./detection-value.component.html", + styleUrls: ["./detection-value.component.less"], +}) +export class DetectionValueComponent { + constructor() {} + + @Input() value?: { alarm: boolean; value: number }; +} diff --git a/projects/client/src/app/feature/detection/components/device-table/device-table.component.html b/projects/client/src/app/feature/detection/components/device-table/device-table.component.html new file mode 100644 index 0000000..ad1033a --- /dev/null +++ b/projects/client/src/app/feature/detection/components/device-table/device-table.component.html @@ -0,0 +1,47 @@ +
+
+ + + + + + + + +
+
+ + + + +
+
+ + + + + + + 机组/检测点/设备 + + + + + + + + {{currentSelectedGroupName}}/{{currentSelectedPoint?.name}}/{{data.name}} + + + + \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/device-table/device-table.component.less b/projects/client/src/app/feature/detection/components/device-table/device-table.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/device-table/device-table.component.ts b/projects/client/src/app/feature/detection/components/device-table/device-table.component.ts new file mode 100644 index 0000000..626e226 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/device-table/device-table.component.ts @@ -0,0 +1,133 @@ +import { Component, Input, OnInit } from "@angular/core"; +import { AnyObject } from "@cdk/types"; +import { DetectionApiService } from "@client/app/core/services"; +import { PointDTO, PointGroupDTO, DeviceDTO } from "@client/dtos"; +import { NzMessageService } from "ng-zorro-antd/message"; + +@Component({ + selector: "app-device-table", + templateUrl: "./device-table.component.html", + styleUrls: ["./device-table.component.less"], +}) +export class DeviceTableComponent implements OnInit { + constructor(private api: DetectionApiService, private msg: NzMessageService) {} + + @Input() currentSelected: { id: string; name: string }[] = []; + + @Input() otherSelected: { id: string; name: string }[] = []; + + checked = false; + + loading = false; + + indeterminate = false; + + groups: PointGroupDTO[] = []; + + gid: string = ""; + + pid: string = ""; + + points: PointDTO[] = []; + + currentPointList: PointDTO[] = []; + + listOfData: DeviceDTO[] = []; + + listOfCurrentPageData: readonly any[] = []; + + setOfCheckedId = new Set(); + + setOfDataFromServer: AnyObject[] = []; + + public get selectedDevice(): AnyObject[] { + return this.setOfDataFromServer.filter((f) => this.setOfCheckedId.has(f["id"])); + } + + public get currentSelectedGroupName(): string { + return this.groups.find((f) => f.motorGroupId === this.gid)?.name ?? ""; + } + + public get currentSelectedPoint(): PointDTO | undefined { + return this.points.find((f) => f.pointId === this.pid); + } + + ngOnInit(): void { + this.currentSelected?.forEach((p) => { + this.updateCheckedSet(p.id, true); + }); + this.api.getFlatPoints().subscribe(({ points, groups }) => { + this.groups = groups; + this.points = points; + }); + } + + onReset() { + this.gid = ""; + this.onSearch(); + } + + onSearch() { + if (!this.pid) { + this.msg.error("请选择检测点"); + return; + } + + this.api.getDeviceListByPointId(this.pid).subscribe((res) => { + console.log("this.otherSelected", this.otherSelected); + if (Array.isArray(res.body)) { + this.listOfData = res.body.map((i) => { + return { + ...i, + id: i.deviceId, + disabled: !!this.otherSelected.find((f) => f.id === i.deviceId), + }; + }); + } else { + this.listOfData = []; + } + this.listOfData.forEach((i) => { + if (!this.setOfDataFromServer.some((s) => s["id"] === i["id"])) { + this.setOfDataFromServer.push(i); + } + }); + this.refreshCheckedStatus(); + }); + } + + onGroupChange(gid: string) { + this.currentPointList = this.groups.find((f) => f.motorGroupId === gid)?.pointList ?? []; + this.pid = ""; + } + + updateCheckedSet(id: string, checked: boolean): void { + if (checked) { + this.setOfCheckedId.add(id); + } else { + this.setOfCheckedId.delete(id); + } + } + + onCurrentPageDataChange(listOfCurrentPageData: readonly any[]): void { + this.listOfCurrentPageData = listOfCurrentPageData; + this.refreshCheckedStatus(); + } + + refreshCheckedStatus(): void { + const listOfEnabledData = this.listOfCurrentPageData.filter(({ disabled }) => !disabled); + this.checked = listOfEnabledData.length > 0 && listOfEnabledData.every(({ id }) => this.setOfCheckedId.has(id)); + this.indeterminate = listOfEnabledData.some(({ id }) => this.setOfCheckedId.has(id)) && !this.checked; + } + + onItemChecked(id: string, checked: boolean): void { + this.updateCheckedSet(id, checked); + this.refreshCheckedStatus(); + } + + onAllChecked(checked: boolean): void { + this.listOfCurrentPageData + .filter(({ disabled }) => !disabled) + .forEach(({ id }) => this.updateCheckedSet(id, checked)); + this.refreshCheckedStatus(); + } +} diff --git a/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.html b/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.html new file mode 100644 index 0000000..a753299 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.html @@ -0,0 +1,4 @@ +
+ +

你没有此页面的访问权限。

+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.less b/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.ts b/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.ts new file mode 100644 index 0000000..3bdfe40 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/forbidden/forbidden.component.ts @@ -0,0 +1,14 @@ +import { ActivatedRoute, Router } from "@angular/router"; +import { Component, OnInit } from "@angular/core"; +import { NgxPermissionsService } from "ngx-permissions"; + +@Component({ + selector: "app-forbidden", + templateUrl: "./forbidden.component.html", + styleUrls: ["./forbidden.component.less"], +}) +export class ForbiddenComponent implements OnInit { + constructor(private perm: NgxPermissionsService, private router: Router, private route: ActivatedRoute) {} + + async ngOnInit() {} +} diff --git a/projects/client/src/app/feature/detection/components/home/home.component.html b/projects/client/src/app/feature/detection/components/home/home.component.html new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/home/home.component.less b/projects/client/src/app/feature/detection/components/home/home.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/home/home.component.ts b/projects/client/src/app/feature/detection/components/home/home.component.ts new file mode 100644 index 0000000..696b12f --- /dev/null +++ b/projects/client/src/app/feature/detection/components/home/home.component.ts @@ -0,0 +1,34 @@ +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { NgxPermissionsService } from "ngx-permissions"; + +@Component({ + selector: "app-home", + templateUrl: "./home.component.html", + styleUrls: ["./home.component.less"], +}) +export class HomeComponent { + constructor(private perm: NgxPermissionsService, private router: Router, private route: ActivatedRoute) {} + + async ngOnInit() { + let children = this.route.parent?.routeConfig?.children; + const { from } = this.route.snapshot.queryParams; + if (Array.isArray(children)) { + if (from) { + children = children.find((f) => f.path === from)?.children ?? []; + } + for (const child of children) { + if (child.path === this.route.routeConfig?.path) { + continue; + } + const only = child.data?.["permissions"]?.only; + if (Array.isArray(only)) { + if (await this.perm.hasPermission(only)) { + this.router.navigate(["/detection", from, child.path].filter(Boolean)); + break; + } + } + } + } + } +} diff --git a/projects/client/src/app/feature/detection/components/image-player/_image-player.component.ts b/projects/client/src/app/feature/detection/components/image-player/_image-player.component.ts new file mode 100644 index 0000000..1d85c08 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/image-player/_image-player.component.ts @@ -0,0 +1,129 @@ +// import { environment } from "@client/environments/environment"; +// import { Component, Inject, Input, OnDestroy, OnInit } from "@angular/core"; +// import { BehaviorSubject, forkJoin, interval, lastValueFrom, Subject, Subscription } from "rxjs"; +// import { filter, takeUntil } from "rxjs/operators"; +// import { NzImageService } from "ng-zorro-antd/image"; +// import { UtilsService } from "@client/app/core/services"; + +// export interface ImageObj { +// jobId: string; +// img: string; +// } + +// @Component({ +// selector: "app-image-player", +// templateUrl: "./image-player.component.html", +// styleUrls: ["./image-player.component.less"], +// }) +// export class ImagePlayerComponent implements OnInit, OnDestroy { +// constructor(private img: NzImageService, private util: UtilsService) {} + +// @Input() images$!: BehaviorSubject; + +// images: string[] = []; +// imageObjs: ImageObj[] = []; + +// environment = environment; + +// subs$?: Subscription; + +// currentIndex = 0; + +// played = false; + +// fps: number = 1; + +// ngOnInit(): void { +// this.images$.subscribe(async (imgObjs) => { +// for (let i = 0; i < imgObjs.length; i++) { +// const o = imgObjs[i]; +// // if (i < 10) { +// // const res = await lastValueFrom(this.util.loadImage(o.jobId, o.img)); +// // this.imageObjs.push +// // this.images.push("data:image/png;base64," + res.body); +// // } +// this.imageObjs.push(o); +// } + +// this.initPlayImage(); +// }); +// } + +// ngOnDestroy(): void { +// this.currentIndex = 0; +// this.tempIndex = 0; +// this.played = false; +// this.subs$?.unsubscribe(); +// } + +// jumpTo(idx: number) { +// this.played = false; +// if (idx < 0 || idx > this.images.length - 1) { +// return; +// } +// this.currentIndex = idx; +// this.tempIndex = idx; +// } +// tempIndex = 0; +// initPlayImage() { +// this.subs$?.unsubscribe(); +// this.subs$ = interval(1000 / this.fps) +// .pipe( +// filter(() => { +// // return this.currentIndex === this.tempIndex; +// return true; +// }) +// ) +// .subscribe(async () => { +// if (this.played) { +// // this.tempIndex = this.currentIndex + 1; +// let targetImage = this.images[this.currentIndex]; + +// if (!targetImage) { +// const o = this.imageObjs[this.tempIndex]; +// const base64 = await lastValueFrom(this.util.loadImage(o.jobId, o.img)); +// targetImage = base64; +// this.images.push(base64); +// } + +// this.currentIndex++; + +// console.log("targetImage", targetImage); +// // if (!targetImage) { +// // this.currentIndex = this.images.length - 1; +// // this.tempIndex = this.currentIndex; +// // this.togglePaly(); +// // } else { +// // const bs = await this.util.loadImages(targetImage); +// // this.currentIndex++; +// // this.images[this.currentIndex] = bs; +// // } +// } else { +// this.subs$?.unsubscribe(); +// } +// }); +// } + +// togglePaly() { +// this.played = !this.played; +// if (this.played) { +// if (this.currentIndex === this.images.length - 1) { +// this.currentIndex = 0; +// this.tempIndex = 0; +// } +// this.initPlayImage(); +// } +// } + +// onFpsChange(fps: number) { +// this.fps = fps; +// this.initPlayImage(); +// } + +// showImg() { +// if (this.images.length > 0) { +// const imgRef = this.img.preview(this.images.map((src) => ({ src }))); +// imgRef.switchTo(this.currentIndex); +// } +// } +// } diff --git a/projects/client/src/app/feature/detection/components/image-player/image-player.component.html b/projects/client/src/app/feature/detection/components/image-player/image-player.component.html new file mode 100644 index 0000000..0230101 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/image-player/image-player.component.html @@ -0,0 +1,52 @@ +
+ + + + + +
+
+
+ + + + + + + +
+
+ + +
+
+ + +
    +
  • 1 FPS
  • +
  • 2 FPS
  • +
  • 3 FPS
  • +
  • 5 FPS
  • +
+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/image-player/image-player.component.less b/projects/client/src/app/feature/detection/components/image-player/image-player.component.less new file mode 100644 index 0000000..9e162d4 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/image-player/image-player.component.less @@ -0,0 +1,44 @@ +:host { + display: flex; + height: 100%; + background-color: var(--black-10); + position: relative; +} + +.idx { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 60px; + color: #fff; +} + +.controls { + background-color: rgba(0, 0, 0, .25); + color: var(--text-color); + + ::ng-deep { + .ant-space-item { + margin-right: 0; + } + } + + button { + appearance: none; + border: none; + outline: none; + color: var(--text-color); + font-size: 20px; + background-color: transparent; + cursor: pointer; + } + + .fps { + appearance: none; + border: none; + border-radius: 2px; + background-color: var(--white-10); + font-size: 14px; + } +} \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/image-player/image-player.component.ts b/projects/client/src/app/feature/detection/components/image-player/image-player.component.ts new file mode 100644 index 0000000..7433ae3 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/image-player/image-player.component.ts @@ -0,0 +1,176 @@ +import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { AnyObject } from "@cdk/types"; +import { DetectionApiService, UtilsService } from "@client/app/core/services"; +import { NzImageService } from "ng-zorro-antd/image"; +import { + BehaviorSubject, + Subject, + Subscription, + interval, + lastValueFrom, + switchMap, + takeUntil, + takeWhile, + tap, +} from "rxjs"; + +export interface ImageObj { + jobId: string; + img: string; +} + +@Component({ + selector: "app-image-player", + templateUrl: "./image-player.component.html", + styleUrls: ["./image-player.component.less"], +}) +export class ImagePlayerComponent implements OnInit { + constructor(private nzImg: NzImageService, private api: DetectionApiService) {} + + @Input() props$!: BehaviorSubject; + + images: ({ url: string; loaded: boolean } & Partial)[] = []; + + currentIndex = -1; + + autoPlay = false; + + fps = 5; + + private destroy$ = new Subject(); + + private trigger$ = new Subject(); + + private subs$?: Subscription; + + ngOnInit(): void { + const { origin } = window.location; + this.props$.subscribe((imgs) => { + if (imgs.length === 0) { + return; + } + // console.log("imgs", imgs); + this.api.getImageBaseUrl().subscribe((baseUrl) => { + imgs.forEach((item) => { + const url = `${origin}${baseUrl}${item.jobId}/detect/${item.img}`; + this.images.push({ url, loaded: false, ...item }); + }); + if (this.currentIndex < 0 && this.images.length > 0) { + this.jumpTo(0); + } + }); + }); + } + + reset() { + this.images = []; + this.currentIndex = -1; + } + + destroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + ngOnDestroy() { + this.destroy(); + } + + togglePlay() { + this.autoPlay = !this.autoPlay; + if (this.autoPlay && this.currentIndex === this.images.length - 1) { + this.currentIndex = 0; + } + if (this.images.length === 0) { + this.autoPlay = false; + } + + if (this.autoPlay) { + this.subs$?.unsubscribe(); + this.subs$ = this.trigger$ + .pipe( + switchMap(() => interval(1000 / this.fps)), + takeUntil(this.destroy$), + takeWhile(() => this.autoPlay), + tap((i) => { + // console.log(i); + }) + ) + + .subscribe(() => { + this.jumpTo(this.currentIndex + 1); + // console.log("played"); + }); + + this.trigger$.next(); + } + } + + async jumpTo(idx: number) { + // console.log("idx", idx); + if (idx < 0 || idx > this.images.length - 1) { + return; + } + const image = this.images[idx]; + if (!image.loaded) { + // await this.loadBase64(image as ImageObj); + await this.loadImage(image); + } + this.currentIndex = idx; + + if (this.autoPlay && this.currentIndex === this.images.length - 1) { + this.togglePlay(); + } + } + + async loadBase64(item: ImageObj & AnyObject) { + const base64 = await lastValueFrom(this.api.loadImage(item.jobId, item.img)); + item["loaded"] = true; + item["url"] = base64; + } + + loadImage(image: { url: string; loaded: boolean }) { + return new Promise((r, j) => { + if (!image.loaded) { + const img = new Image(); + img.src = image.url; + img.onload = () => { + image.loaded = true; + r(image); + }; + } else { + r(image); + } + }); + } + + onFpsChange(fps: number) { + this.fps = fps; + this.trigger$.next(); + // this.initPlayImage(); + } + + showImg() { + if (this.images.length > 0) { + this.togglePlay(); + const imgRef = this.nzImg.preview(this.images.map((img) => ({ src: img.url }))); + imgRef.switchTo(this.currentIndex); + } + } + + preLoad() { + this.images.forEach((image) => { + if (!image.loaded) { + const img = new Image(); + img.src = image.url; + img.onload = () => { + image.loaded = true; + }; + } + }); + + if (this.currentIndex < 0) { + this.currentIndex = 0; + } + } +} diff --git a/projects/client/src/app/feature/detection/components/index.ts b/projects/client/src/app/feature/detection/components/index.ts new file mode 100644 index 0000000..61979e5 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/index.ts @@ -0,0 +1,10 @@ +export * from "./detection-graphics/detection-graphics.component"; +export * from "./image-player/image-player.component"; +export * from "./point-status/point-status.component"; +export * from "./detection-value/detection-value.component"; +export * from "./point-table/point-table.component"; +export * from "./device-table/device-table.component"; + +export * from "./home/home.component"; +export * from "./forbidden/forbidden.component"; +export * from "./notfound/notfound.component"; diff --git a/projects/client/src/app/feature/detection/components/notfound/notfound.component.html b/projects/client/src/app/feature/detection/components/notfound/notfound.component.html new file mode 100644 index 0000000..df4b62f --- /dev/null +++ b/projects/client/src/app/feature/detection/components/notfound/notfound.component.html @@ -0,0 +1,6 @@ +
+ +

+ 此页面未找到。 +

+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/notfound/notfound.component.less b/projects/client/src/app/feature/detection/components/notfound/notfound.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/notfound/notfound.component.ts b/projects/client/src/app/feature/detection/components/notfound/notfound.component.ts new file mode 100644 index 0000000..0368db3 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/notfound/notfound.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-notfound', + templateUrl: './notfound.component.html', + styleUrls: ['./notfound.component.less'] +}) +export class NotfoundComponent { + +} diff --git a/projects/client/src/app/feature/detection/components/point-status/point-status.component.html b/projects/client/src/app/feature/detection/components/point-status/point-status.component.html new file mode 100644 index 0000000..be40b1e --- /dev/null +++ b/projects/client/src/app/feature/detection/components/point-status/point-status.component.html @@ -0,0 +1,29 @@ + + + + + + +
+ + + 异常 + + + + 掉线 + + + + 正常 + +
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/point-status/point-status.component.less b/projects/client/src/app/feature/detection/components/point-status/point-status.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/point-status/point-status.component.ts b/projects/client/src/app/feature/detection/components/point-status/point-status.component.ts new file mode 100644 index 0000000..10437e6 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/point-status/point-status.component.ts @@ -0,0 +1,16 @@ +import { Component, Input, ViewEncapsulation } from "@angular/core"; +import { PointStatusEnum } from "@client/dtos"; + +@Component({ + selector: "app-point-status", + templateUrl: "./point-status.component.html", + styleUrls: ["./point-status.component.less"], + encapsulation: ViewEncapsulation.None, +}) +export class PointStatusComponent { + @Input() status: PointStatusEnum = PointStatusEnum.NORMAL; + + @Input() textVisible: boolean = false; + + PointStatusEnum = PointStatusEnum; +} diff --git a/projects/client/src/app/feature/detection/components/point-table/point-table.component.html b/projects/client/src/app/feature/detection/components/point-table/point-table.component.html new file mode 100644 index 0000000..a092d54 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/point-table/point-table.component.html @@ -0,0 +1,41 @@ +
+
+ + + +
+
+ + + + +
+
+ + + + + + + 机组/检测点 + + + + + + + + {{data.name}} + + + + \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/components/point-table/point-table.component.less b/projects/client/src/app/feature/detection/components/point-table/point-table.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/components/point-table/point-table.component.ts b/projects/client/src/app/feature/detection/components/point-table/point-table.component.ts new file mode 100644 index 0000000..53153c1 --- /dev/null +++ b/projects/client/src/app/feature/detection/components/point-table/point-table.component.ts @@ -0,0 +1,115 @@ +import { Component, Input, OnInit } from "@angular/core"; +import { DetectionApiService } from "@client/app/core/services"; +import { PointDTO, PointGroupDTO } from "@client/dtos"; + +@Component({ + selector: "app-point-table", + templateUrl: "./point-table.component.html", + styleUrls: ["./point-table.component.less"], +}) +export class PointTableComponent implements OnInit { + constructor(private api: DetectionApiService) {} + + @Input() currentSelected: PointDTO[] = []; + + @Input() otherSelected: PointDTO[] = []; + + checked = false; + + loading = false; + + indeterminate = false; + + groups: PointGroupDTO[] = []; + + gid: string = ""; + + points: PointDTO[] = []; + + listOfData: PointDTO[] = []; + + listOfCurrentPageData: readonly any[] = []; + + setOfCheckedId = new Set(); + + arrOfChecked: PointDTO[] = []; + + ngOnInit(): void { + this.currentSelected?.forEach((p) => { + this.updateCheckedSet(p.pointId, true); + }); + this.api.getFlatPoints().subscribe(({ groups, points }) => { + points = points.map((p) => ({ ...p, disabled: this.otherSelected.some((s) => s.pointId === p.pointId) })); + this.points = points; + this.listOfData = points; + this.groups = groups; + this.refreshCheckedStatus(); + }); + // this.api.getAllPoint().subscribe((p) => { + // const groups = p?.[0]?.groupList; + // const points: PointDTO[] = []; + // console.log("this.currentSelected", this.currentSelected, this.otherSelected); + // if (groups) { + // this.groups = groups; + // groups.forEach((g) => { + // points.push( + // ...g.pointList.map((p) => ({ + // ...p, + // gid: g.motorGroupId, + // gname: g.name, + // })) + // ); + // }); + // this.points = points; + // this.listOfData = points; + // this.refreshCheckedStatus(); + // } + // }); + } + + updateCheckedSet(id: string, checked: boolean): void { + if (checked) { + this.setOfCheckedId.add(id); + } else { + this.setOfCheckedId.delete(id); + } + this.arrOfChecked = this.points.filter((f) => this.setOfCheckedId.has(f.pointId)); + } + + onCurrentPageDataChange(listOfCurrentPageData: readonly any[]): void { + this.listOfCurrentPageData = listOfCurrentPageData; + this.refreshCheckedStatus(); + } + + refreshCheckedStatus(): void { + const listOfEnabledData = this.listOfCurrentPageData.filter(({ disabled }) => !disabled); + this.checked = + listOfEnabledData.length > 0 && listOfEnabledData.every(({ pointId }) => this.setOfCheckedId.has(pointId)); + this.indeterminate = listOfEnabledData.some(({ pointId }) => this.setOfCheckedId.has(pointId)) && !this.checked; + } + + onItemChecked(id: string, checked: boolean): void { + this.updateCheckedSet(id, checked); + this.refreshCheckedStatus(); + } + + onAllChecked(checked: boolean): void { + this.listOfCurrentPageData + .filter(({ disabled }) => !disabled) + .forEach(({ pointId }) => this.updateCheckedSet(pointId, checked)); + this.refreshCheckedStatus(); + } + + onReset() { + this.gid = ""; + this.onSearch(); + } + + onSearch() { + if (this.gid) { + this.listOfData = this.points.filter((f) => f["gid"] === this.gid); + } else { + this.listOfData = this.points; + } + } +} diff --git a/projects/client/src/app/feature/detection/detection-routing.module.ts b/projects/client/src/app/feature/detection/detection-routing.module.ts new file mode 100644 index 0000000..9ac474c --- /dev/null +++ b/projects/client/src/app/feature/detection/detection-routing.module.ts @@ -0,0 +1,156 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; +import { AuthorizationLayoutComponent } from "@client/app/shared/components"; +import { + AnalysisComponent, + DetectionIndexComponent, + HistoryDetailComponent, + HistoryListComponent, + PointSettingComponent, + SettingsLayoutComponent, + AlgorithmSettingComponent, + TemperatureSettingComponent, + SystemSettingComponent, +} from "./pages"; +import { PermissionLoadGuard } from "@client/app/core/gaurd/permisson.guard"; +import { ForbiddenComponent, HomeComponent, NotfoundComponent } from "./components"; +import { NgxPermissionsGuard } from "ngx-permissions"; + +const routes: Routes = [ + { + path: "", + component: AuthorizationLayoutComponent, + canActivateChild: [PermissionLoadGuard], + children: [ + { + path: "", + pathMatch: "full", + redirectTo: "home", + }, + { + path: "home", + component: HomeComponent, + }, + { + path: "index", + component: DetectionIndexComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_pole"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "history", + component: HistoryListComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_history"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "history/:id", + component: HistoryDetailComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_history"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "analysis", + component: AnalysisComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_analysis"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "settings", + component: SettingsLayoutComponent, + canActivateChild: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_settings_show", "role_settings_bolt", "role_settings_temp", "role_settings_sys"], + redirectTo: "/detection/forbidden", + }, + }, + children: [ + { + path: "", + pathMatch: "full", + redirectTo: "/detection/home?from=settings", + }, + { + path: "point", + component: PointSettingComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_settings_show"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "algorithm", + component: AlgorithmSettingComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_settings_bolt"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "temperature", + component: TemperatureSettingComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_settings_temp"], + redirectTo: "/detection/forbidden", + }, + }, + }, + { + path: "system", + component: SystemSettingComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_settings_sys"], + redirectTo: "/detection/forbidden", + }, + }, + }, + ], + }, + { + path: "forbidden", + component: ForbiddenComponent, + }, + { + path: "**", + component: NotfoundComponent, + }, + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class DetectionRoutingModule {} diff --git a/projects/client/src/app/feature/detection/detection.module.ts b/projects/client/src/app/feature/detection/detection.module.ts new file mode 100644 index 0000000..890025b --- /dev/null +++ b/projects/client/src/app/feature/detection/detection.module.ts @@ -0,0 +1,56 @@ +import { FormsModule } from "@angular/forms"; +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { DetectionRoutingModule } from "./detection-routing.module"; +import { + DetectionGraphicsComponent, + ImagePlayerComponent, + PointStatusComponent, + DetectionValueComponent, + PointTableComponent, + DeviceTableComponent, + ForbiddenComponent, + NotfoundComponent, + HomeComponent, +} from "./components"; +import { + AnalysisComponent, + DetectionIndexComponent, + HistoryDetailComponent, + HistoryListComponent, + SettingsLayoutComponent, + PointSettingComponent, + AlgorithmSettingComponent, + TemperatureSettingComponent, + SystemSettingComponent, +} from "./pages"; +import { SharedModule } from "../../shared/shared.module"; + +const components = [ + DetectionGraphicsComponent, + ImagePlayerComponent, + PointStatusComponent, + DetectionValueComponent, + PointTableComponent, + DeviceTableComponent, + ForbiddenComponent, + NotfoundComponent, + HomeComponent, +]; +const pages = [ + AnalysisComponent, + DetectionIndexComponent, + HistoryDetailComponent, + HistoryListComponent, + SettingsLayoutComponent, + PointSettingComponent, + AlgorithmSettingComponent, + TemperatureSettingComponent, + SystemSettingComponent, +]; + +@NgModule({ + declarations: [...components, ...pages], + imports: [SharedModule, DetectionRoutingModule], +}) +export class DetectionModule {} diff --git a/projects/client/src/app/feature/detection/pages/analysis/analysis.component.html b/projects/client/src/app/feature/detection/pages/analysis/analysis.component.html new file mode 100644 index 0000000..60a9963 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/analysis/analysis.component.html @@ -0,0 +1,94 @@ +
+
+ + +
+ +
+ + + +
+ +
+ + + + +
+ + +
+ + + + + + + +
+
+
+
+ + + + +
+ +
+
+
+ + + + +
+
+
+
+ + + + +
+
+
+
+ + + + +
+
+
+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/analysis/analysis.component.less b/projects/client/src/app/feature/detection/pages/analysis/analysis.component.less new file mode 100644 index 0000000..8f64dc3 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/analysis/analysis.component.less @@ -0,0 +1,34 @@ +:host { + display: flex; + height: calc(100% - 1px); + flex-direction: column; + overflow-y: auto; +} + +.visible { + visibility: visible !important; +} +.analysis { + gap: 16px; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 500px); + + & > div { + &:nth-child(1) { + grid-column: 1 / span 1; + grid-row: 1 / span 1; + } + &:nth-child(2) { + grid-column: 2 / span 1; + grid-row: 1 / span 1; + } + &:nth-child(3) { + grid-column: 1 / span 1; + grid-row: 2 / span 1; + } + &:nth-child(4) { + grid-column: 2 / span 1; + grid-row: 2 / span 1; + } + } +} diff --git a/projects/client/src/app/feature/detection/pages/analysis/analysis.component.ts b/projects/client/src/app/feature/detection/pages/analysis/analysis.component.ts new file mode 100644 index 0000000..8eaca5f --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/analysis/analysis.component.ts @@ -0,0 +1,347 @@ +import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from "@angular/core"; +import { AnyObject } from "@cdk/types"; +import { DetectionApiService } from "@client/app/core/services"; +import { PoleItemDTO } from "@client/dtos"; +import { format } from "date-fns"; +import { init, EChartsType } from "echarts"; +import { NzCascaderOption } from "ng-zorro-antd/cascader"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { forkJoin } from "rxjs"; + +type QueryInterface = { + range: string[] | null; + pointId: null | string[]; + features: string[] | null; + zone: number | null; +}; + +const initQuery = { + range: null, + pointId: null, + features: null, + zone: null, +}; + +@Component({ + selector: "app-analysis", + templateUrl: "./analysis.component.html", + styleUrls: ["./analysis.component.less"], +}) +export class AnalysisComponent implements OnInit, AfterViewInit { + constructor(private api: DetectionApiService, private msg: NzMessageService) {} + + points: NzCascaderOption[] = []; + + features: Record = {}; + + query: QueryInterface = JSON.parse(JSON.stringify(initQuery)); + + prevSelectFeatures: string[] = []; + + poles: number[] = []; + + featureChartMap = new Map(); + + @ViewChild("chart1") line!: ElementRef; + + @ViewChild("chart2") bolt!: ElementRef; + + @ViewChild("chart3") pole!: ElementRef; + + @ViewChild("chart4") temperature!: ElementRef; + + echart_line?: EChartsType; + + echart_bolt?: EChartsType; + + echart_pole?: EChartsType; + + echart_temperature?: EChartsType; + + ngOnInit(): void { + this.forkjoinPointAndFeatures(); + } + + ngAfterViewInit(): void { + // if (this.chart1.nativeElement) { + // this.echart1 = this.createChart(this.chart1.nativeElement); + // } + // if (this.chart2.nativeElement) { + // this.echart2 = this.createChart(this.chart2.nativeElement); + // } + // if (this.chart3.nativeElement) { + // this.echart3 = this.createChart(this.chart3.nativeElement); + // } + // if (this.chart4.nativeElement) { + // this.echart4 = this.createChart(this.chart4.nativeElement); + // } + } + + onPointChange(point: Array) { + let poleNumbers = 0; + if (Array.isArray(point) && point.length === 2) { + const selectPoint = this.points.find((f) => f.value === point[0])?.children?.find((f) => f.value === point[1]); + poleNumbers = selectPoint?.["poleNum"] ?? 0; + + const pid = selectPoint?.["pointId"]; + if (pid) { + this.api.getFeatures(pid).subscribe((featureRes) => { + this.features = featureRes.body; + this.query.features = Object.keys(this.features); + setTimeout(() => { + this.getData(); + }, 70); + }); + } + } + this.poles = Array.from({ length: poleNumbers }, (_, idx) => idx + 1); + } + + forkjoinPointAndFeatures() { + forkJoin([this.api.getAllPoint()]).subscribe(([pointData]) => { + const stationGroups = pointData[0]; + this.points = stationGroups.groupList.map((g) => { + return { + label: g.name, + value: g.motorGroupId, + children: g.pointList.map((p) => { + return { + label: p.name, + value: p.pointId, + isLeaf: true, + ...p, + }; + }), + }; + }); + + this.query.pointId = [this.points[0].value, this.points[0]?.children?.[0]?.value]; + this.onPointChange(this.query.pointId); + this.query.zone = 1; + }); + } + + ngModelChange(v: any) {} + + getData() { + const { query } = this; + const q = Object.create(null); + Object.entries(query).forEach(([k, v]) => { + q[k] = v; + if (k === "range" && Array.isArray(v) && v.length === 2) { + const startTime = typeof v[0] === "string" ? v[0] : format(v[0], "yyyy-MM-dd"); + const endTime = typeof v[1] === "string" ? v[1] : format(v[1], "yyyy-MM-dd"); + q.startTime = startTime; + q.endTime = endTime; + } + if (k === "pointId" && Array.isArray(v) && v.length === 2) { + q.pointId = v[1]; + } + }); + if (!q.pointId) { + this.msg.error("请选择机组/监测点"); + return; + } + if (!q.features) { + this.msg.error("请选特征量"); + return; + } + this.prevSelectFeatures = q.features; + this.featureChartMap.clear(); + this.api.getAnalysisChartData(q).subscribe((res) => { + Object.entries(res.body).forEach(([category, data]) => { + let echartDataSet: AnyObject[] = []; + data.forEach((item) => { + let time = echartDataSet.find((f) => f["time"] === item["time"]); + if (time) { + time[item["position"]] = item.value; + } else { + echartDataSet.push({ time: item["time"], [item["position"]]: item.value }); + } + }); + this.featureChartMap.set(category, true); + this.createChart(category, echartDataSet); + }); + }); + } + + search() { + this.getData(); + } + + reset() { + this.query = JSON.parse(JSON.stringify(initQuery)); + } + + echartTitleMap = new Map([ + ["line", { left: "最高变化量:#-@mm", right: `最高变化量产生日期:@` }], + ["bolt", { left: "最大转动角度:#-@°", right: `最大转动角度产生日期:@` }], + ["pole", { left: "开匝磁极:#", right: `最多开匝磁极产生日期:@` }], + ["temperature", { left: "最高变化量:@℃", right: `最高变化量产生日期:@` }], + ]); + + findMaxValue(arr: AnyObject[]) { + arr.forEach((obj) => { + Object.entries(obj).forEach(([k, v], idx) => { + if (idx === 0) { + obj["value"] = v; + obj["valueIdx"] = k; + } + if (k !== "value" && v > obj["value"]) { + obj["value"] = v; + obj["valueIdx"] = k; + } + }); + + // obj["value"] = Math.max(...Object.values(obj).filter((f) => typeof f === "number")); + }); + return arr.reduce((max, current) => { + return current["value"] > max["value"] ? current : max; + }); + } + + createChart(category: string, data: AnyObject[]) { + console.log("category", category, data); + //@ts-expect-error + const el = this[category]; + const echartRef = "echart_" + category; + + if (el && el?.nativeElement) { + const div = el.nativeElement as HTMLDivElement; + //@ts-expect-error + const old: EChartsType = this[echartRef]; + if (old) { + old.dispose(); + } + + const echart = init(el.nativeElement, "dark"); + const dimensions = Object.keys(data[0]).filter((f) => f !== "time"); + //@ts-expect-error + this[echartRef] = echart; + + const txt = this.echartTitleMap.get(category)!; + const max = this.findMaxValue(data); + // console.log("max", max); + let text = [ + `{a|${txt.left.replace("#", "#" + max["valueIdx"]).replace("@", max["value"])}}`, + `{b|${txt.right.replace("@", max["time"])}}`, + ].join(""); + + echart.setOption({ + title: { + text, + show: !!max, + textStyle: { + width: div.clientWidth - 20, + fontWeight: "normal", + rich: { + a: { + fontSize: 14, + color: "#fff", + align: "left", + }, + b: { + align: "right", + color: "#fff", + fontSize: 14, + }, + }, + }, + }, + + backgroundColor: "transparent", + + tooltip: { + trigger: "axis", + axisPointer: { + type: "cross", + label: { + backgroundColor: "#6a7985", + }, + }, + }, + + legend: { + bottom: 0, + left: 0, + formatter: "{name} #", + }, + + dataset: { + dimensions: ["time", ...dimensions], + source: data, + }, + + grid: { + top: "12%", + left: "35", + right: "35", + bottom: "10%", + containLabel: true, + }, + + xAxis: [ + { + type: "category", + boundaryGap: false, + }, + ], + yAxis: [ + { + type: "value", + splitLine: { + show: true, + lineStyle: { + color: "rgba(255, 255, 255, 0.1)", + }, + }, + }, + ], + series: dimensions.reduce((a, c) => { + return a.concat({ + name: c, + type: "line", + areaStyle: { + opacity: "0.2", + }, + emphasis: { + focus: "series", + }, + }); + }, [] as AnyObject[]), + }); + } + } + + downloadChart(type: string) { + const echart = (this[`echart_${type}` as keyof this]); + console.log("type", type, echart); + if (!echart) { + return; + } + const base64String = echart.getDataURL(); + const filename = `image_${type}.png`; + const byteString = atob(base64String.split(",")[1]); + const mimeString = base64String.split(",")[0].split(":")[1].split(";")[0]; + const ab = new ArrayBuffer(byteString.length); + const ia = new Uint8Array(ab); + + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + const blob = new Blob([ab], { type: mimeString }); + const url = URL.createObjectURL(blob); + + const link = document.createElement("a"); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + + setTimeout(() => { + document.body.removeChild(link); + URL.revokeObjectURL(url); + }, 0); + } +} diff --git a/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.html b/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.html new file mode 100644 index 0000000..c81ca23 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.html @@ -0,0 +1,279 @@ + + + +
+
+ + + + +
+
+ + + + + + + + +
+
+ +
+
+

+ 监测点温度 +

+
+ + {{temperature ? (temperature + '℃') :'-'}} + +
+
+
+

+ 引出线变形 +

+
+
+ 最高变化量 +
+
+ {{maxLine.zone}}# - {{maxLine.value}}mm +
+
+
+
+

+ 螺栓松动 +

+
+
+ 最大转动角度 +
+
+ {{maxBolt.zone}}# - {{maxBolt.value}}° +
+
+
+
+

+ 磁极开匝 +

+
+
+ 最大磁极开匝 +
+
+ {{maxPole.zone}}# - {{maxPole.value}} +
+
+
+
+
+
+
+ +
+
+
+ 引出线变形 +
+ + + + + + + + + + + + + + + +
+ 编号 + + #1 + + #2 +
+ 偏移量(mm) + + + + +
+
+
+
+ 螺栓松动 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ 编号 + + #1 + + #2 + + #3 + + #4 + + #5 + + #6 + + #7 + + #8 +
+ 偏移量(°) + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
+ {{selectedZone?.zone}}#磁极 + + 磁极线圈{{selectedZone?.pole?.alarm ? '异常' : '正常'}} +
+
+
+
+ + + + + + + + + + + + + + + + +
+ 引出线变形 + + 检测正常 + + {{line}}#引出线异常 + +
+ 螺栓松动 + + 检测正常 + + + {{line}}#螺栓异常 + +
+ 磁极开匝 + + 检测正常 + + + {{line}}#磁极异常 + +
+
+
+
+ + + +
    +
  • +
    + + +
    + {{ group.name }} +
    +
    + +
    +
    +
      +
    • +
      + {{item.name}} +
      +
      + +
      +
    • +
    +
  • +
+ + +
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.less b/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.less new file mode 100644 index 0000000..ad72587 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.less @@ -0,0 +1,120 @@ +:host { + display: block; + height: 100%; +} + +.switch-btn { + position: absolute; + top: 28px; + right: 130px; +} + +.device-group { + user-select: none; + + .group-title, + .group-child>li { + cursor: pointer; + + &:hover, + &.active { + background-color: var(--white-10); + } + } +} + + + +.grid { + gap: 16px; + grid-template-columns: repeat(30, 1fr); + grid-template-rows: 44vh 174px auto; + + .pictures { + grid-column: 1 / span 15; + grid-row: 1 / span 1; + } + + .graphics { + grid-column: 16 / span 15; + grid-row: 1 / span 2; + + ::ng-deep { + .ant-card-body { + padding: 12px; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.032) 0%, rgba(255, 255, 255, 0.016) 100%); + overflow: hidden; + } + } + } + + .total { + grid-column: 1 / span 15; + grid-row: 2 / span 1; + + b { + font-size: 24px; + font-weight: 400; + } + } + + .selected { + grid-column: 1 / span 15; + grid-row: 3 / span 1; + + table { + display: table; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + + th { + color: var(--purple); + } + + td, + th { + @apply p-2; + border: 1px solid var(--border-color); + + &:first-child { + width: 120px; + } + } + } + } + + .result { + grid-column: 16 / span 15; + grid-row: 3 / span 1; + + &-table { + td { + @apply text-base py-2; + + &:first-child { + width: 120px; + color: var(--purple); + } + } + } + } + + ::ng-deep { + nz-card { + height: 100%; + display: flex; + flex-direction: column; + + .ant-card-body { + flex: 1; + } + } + } +} + +.result-table { + td { + vertical-align: top; + } +} \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.ts b/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.ts new file mode 100644 index 0000000..ad103f6 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/detection-index/detection-index.component.ts @@ -0,0 +1,459 @@ +import { + AfterViewInit, + Component, + ElementRef, + Inject, + OnDestroy, + OnInit, + Renderer2, + TemplateRef, + ViewChild, +} from "@angular/core"; +import { BehaviorSubject, lastValueFrom, Subject, takeUntil } from "rxjs"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { DetectionApiService, WebsocketApiService } from "@client/app/core/services"; +import { PointDTO, PointStatusEnum, PoleItemDTO, PoleQueryDTO, PowerStationDTO } from "@client/dtos"; +import { DecText } from "@cdk/types"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { PoleGroupInterface } from "../../components"; +import { ImageObj, ImagePlayerComponent } from "../../components/image-player/image-player.component"; +import { WebSocketSubject } from "rxjs/webSocket"; + +function createDefaultData(len: number): PoleQueryDTO { + let res: PoleQueryDTO = {}; + Array.from({ length: len }, (_, idx) => { + let zone = idx + 1; + res[zone] = [ + { + type: "bolt", + zone: zone, + position: 1, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 2, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 3, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 4, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 5, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 6, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 7, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "bolt", + zone: zone, + position: 8, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "line", + zone: zone, + position: 1, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "line", + zone: zone, + position: 2, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "pole", + zone: zone, + position: 1, + img: "img1.jpg", + value: 0, + alarm: false, + }, + { + type: "temperature", + zone: zone, + position: 1, + img: "-", + value: 0, + alarm: false, + }, + ]; + }); + + return res; +} + +@Component({ + selector: "app-detection-index", + templateUrl: "./detection-index.component.html", + styleUrls: ["./detection-index.component.less"], +}) +export class DetectionIndexComponent implements OnInit, OnDestroy { + constructor( + private msg: NzMessageService, + private modal: NzModalService, + private api: DetectionApiService, + private ws: WebsocketApiService + ) {} + + unsubscribe$ = new Subject(); + + graphicsProps$ = new BehaviorSubject<{ poles: Array }>({ poles: [] }); + + ws$?: WebSocketSubject; + + images$ = new BehaviorSubject([]); + + @ViewChild(ImagePlayerComponent) imgplayerRef!: ImagePlayerComponent; + + PointStatusEnum = PointStatusEnum; + + allPoint: PowerStationDTO[] = []; + + tempSelectedPoint: PointDTO | null = null; + + selectedPoint: PointDTO | null = null; + + selectedZone?: PoleGroupInterface; + + images: { [PoleZone: number]: ImageObj[] } = {}; + + currentImage: string = ""; + + temperature: string = "-"; + + originaPoleQueryData: PoleQueryDTO = {}; + + poles: PoleGroupInterface[] = []; + + jobId?: string; + + maxLine: { zone: number; value: number } = { zone: 1, value: 0 }; + + maxBolt: { zone: number; value: number } = { zone: 1, value: 0 }; + + maxPole: { zone: number; value: number } = { zone: 1, value: 0 }; + + lineAlarmZones: number[] = []; + + boltAlarmZones: number[] = []; + + poleAlarmZones: number[] = []; + + ngOnInit(): void { + this.connectWs(); + this.getAllPoint(); + } + + ngOnDestroy(): void { + this.unsubscribe$.next(); + this.unsubscribe$.complete(); + } + + connectWs() { + this.ws$ = this.ws.connect("/websocket/amind"); + this.ws$.pipe(takeUntil(this.unsubscribe$)).subscribe((r) => { + if (r && r.title) { + if (r.title === "img") { + if (!this.jobId) { + this.msg.error("没有找到jobId"); + return; + } + const imgs: { zone: number; data: string }[] = r.imgs; + imgs.forEach((item) => { + const imgObj = { jobId: this.jobId!, img: item.data }; + if (Array.isArray(this.images[r.zone])) { + this.images[item.zone].push(imgObj); + } else { + this.images[item.zone] = [imgObj]; + } + if (item.zone === this.selectedZone?.zone) { + this.parsePoleImage(); + } + }); + } + if (r.title === "temperature") { + const temperatureNumber = Number(r.data); + if (!isNaN(temperatureNumber)) { + this.temperature = temperatureNumber.toFixed(1); + } + } + if (r.title === "detect") { + const detectData: PoleItemDTO[] = r.data; + + detectData.forEach((detect) => { + const oldData = this.originaPoleQueryData[detect.zone] ?? []; + this.originaPoleQueryData[detect.zone] = oldData.map((i) => { + if (i.type === detect.type && i.position === detect.position) { + const item = { ...detect, alarm: !!detect.alarm }; + return { + ...i, + ...item, + }; + } + return i; + }); + }); + + this.parsePoleData(this.originaPoleQueryData); + + // const type = r.data.type; + // if (type) { + // const arr = this.originaPoleQueryData[r.zone] ?? []; + // this.originaPoleQueryData[r.zone] = arr.map((i) => { + // if (i.type === r.data?.type && i.position === r.data?.position) { + // return { + // ...i, + // ...r.data, + // }; + // } + // return i; + // }); + + // } + } + } + }); + } + + getImageBase64(imgNames: string[]) {} + + getJobIdByPointId(pointId: DecText) { + this.originaPoleQueryData = createDefaultData(this.selectedPoint!.poleNum); + this.parsePoleData(this.originaPoleQueryData); + this.api.getRealtimeJob(pointId).subscribe((res) => { + const jobId = res.body?.["jobId"]; + this.jobId = jobId; + if (jobId) { + this.getImageByJobId(jobId); + this.getGraphicsDataByJobId(jobId); + } else { + this.msg.error("jobId不存在"); + } + }); + } + + getImageByJobId(jobId: string) { + this.api.getImg(jobId).subscribe((res) => { + Object.entries(res.body).forEach(([zone, imgs]) => { + const zoneNum = Number(zone); + this.images[zoneNum] = imgs.map((img) => ({ img, jobId })); + }); + this.parsePoleImage(); + }); + } + + getGraphicsDataByJobId(jobId: string) { + this.api.getQuery(jobId).subscribe((r) => { + // 根据 query的数据 替换 默认数据 扇区 有可能没有,里面的每一项也有可能没有 + Object.entries(r.body).forEach(([k, v]) => { + const zone = k as any; + // 查找扇区 + const defaultItem = this.originaPoleQueryData[zone]; + if (defaultItem) { + // console.log('this.originaPoleQueryData[zone]', this.originaPoleQueryData[zone], zone) + this.originaPoleQueryData[zone] = defaultItem.map((i) => { + // 查找扇区中的 的 转子 & 线 以及位置 + const queryItem = v.find((f) => f.position === i.position && i.type === f.type); + return queryItem || i; + }); + } + }); + + this.parsePoleData(this.originaPoleQueryData); + }); + } + + parsePoleData(poleDataFromServer: PoleQueryDTO) { + let lineAlarms: number[] = []; + let boltAlarms: number[] = []; + let poleAlarms: number[] = []; + let maxPole = { zone: 0, value: 0 }; + let maxLine = { zone: 0, value: 0 }; + let maxBolt = { zone: 0, value: 0 }; + + const formatedPoles = Object.values(poleDataFromServer).reduce((a, poles, idx) => { + // 获取扇区编号 + const zone = poles[0].zone; + + let bolt: PoleItemDTO[] = []; + let line: PoleItemDTO[] = []; + let pole!: PoleItemDTO; + + poles.forEach((item) => { + if (item.type === "bolt") { + bolt.push(item); + if (item.value > maxBolt.value) { + maxBolt = item; + } + if (item.alarm) { + boltAlarms.push(zone); + } + } + if (item.type === "line") { + line.push(item); + if (item.value > maxLine.value) { + maxLine = item; + } + if (item.alarm) { + lineAlarms.push(zone); + } + } + if (item.type === "pole") { + pole = item; + if (item.alarm) { + poleAlarms.push(zone); + } + if (item.value > maxPole.value) { + maxPole = item; + } + } + }); + + return a.concat({ + bolt, + line, + zone, + pole, + }); + }, [] as PoleGroupInterface[]); + this.poles = formatedPoles; + + if (formatedPoles[0] && !this.selectedZone) { + this.onZoneSelect(formatedPoles[0].zone); + } + + this.maxBolt = maxBolt; + this.maxPole = maxPole; + this.maxLine = maxLine; + + this.lineAlarmZones = [...new Set(lineAlarms)]; + this.boltAlarmZones = [...new Set(boltAlarms)]; + this.poleAlarmZones = [...new Set(poleAlarms)]; + + this.graphicsProps$.next({ poles: formatedPoles }); + } + + getAllPoint() { + this.api.getAllPoint().subscribe((r) => { + this.allPoint = r; + const firstPoint = r?.[0]?.groupList?.[0]?.pointList?.[0]; + if (firstPoint) { + this.selectedPoint = firstPoint; + this.ws$?.next({ status: true, pointId: firstPoint.pointId }); + + this.getJobIdByPointId(firstPoint.pointId); + } + }); + } + + onZoneSelect(zone: number) { + this.selectedZone = this.poles.find((f) => f.zone === zone); + // let maxLine = { zone: 0, value: 0 }; + // let maxBolt = { zone: 0, value: 0 }; + // this.selectedZone?.bolt.forEach((bolt) => { + // if (bolt.value > maxBolt.value) { + // maxBolt = bolt; + // } + // }); + // this.selectedZone?.line.forEach((line) => { + // if (line.value > maxLine.value) { + // maxLine = line; + // } + // }); + // this.maxBolt = maxBolt; + // this.maxLine = maxLine; + if (this.imgplayerRef) { + this.imgplayerRef.reset(); + } + + this.parsePoleImage(); + } + + parsePoleImage() { + let zoneImages: ImageObj[] = []; + if (this.selectedZone) { + zoneImages = this.images[this.selectedZone.zone] ?? []; + } + this.images$.next(zoneImages); + } + + switchDevice(nzContent: TemplateRef<{}>) { + const stationName = this.allPoint[0].name; + this.tempSelectedPoint = this.selectedPoint; + this.modal.create({ + nzTitle: `设备切换-${stationName}`, + nzContent, + nzOnOk: () => { + if (this.tempSelectedPoint) { + this.selectedPoint = this.tempSelectedPoint; + this.ws$?.next({ status: true, pointId: this.selectedPoint.pointId }); + this.getJobIdByPointId(this.selectedPoint.pointId); + this.tempSelectedPoint = null; + this.msg.success(`已选择监测点:${this.selectedPoint!.name}`); + } else { + this.msg.error(`请选择监测点`); + } + }, + }); + } + + handleManualDetection() { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要手动检测?", + nzOnOk: async () => { + const res = await lastValueFrom(this.api.manualDetection(this.selectedPoint!.pointId)); + if (res.success) { + this.msg.success(res.desc); + this.getJobIdByPointId(this.selectedPoint!.pointId); + return true; + } + return false; + }, + }); + } +} diff --git a/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.html b/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.html new file mode 100644 index 0000000..384f3f1 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.html @@ -0,0 +1,182 @@ +
+ +
+
+
+ +

机组/检测点

+

{{point || ''}}

+
+
+
+ +

检测时间

+

{{gmtCreate}}

+
+
+
+ +

检测类型

+

{{type}}

+
+
+
+ +

检测结果

+

+ +

+
+
+
+
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + +
+ + 引出线变形 + + + 检测正常 + + {{line}}#磁极异常 + +
+ + 螺栓松动 + + + 检测正常 + + {{line}}#磁极异常 + +
+ + 磁极开匝 + + + 检测正常 + + {{line}}#磁极异常 + +
+
+
+
+ + + + + + 磁极 + + + 引出线变形(mm) + + + 螺栓松动(°) + + + + + #1 + + + #2 + + + #1 + + + #2 + + + #3 + + + #4 + + + #5 + + + #6 + + + #7 + + + #8 + + + + + + + + {{item.zone}}# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.less b/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.less new file mode 100644 index 0000000..4ee631d --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.less @@ -0,0 +1,83 @@ +:host { + display: flex; + height: 100%; + flex-direction: column; +} + +.auto { + gap: 16px; + grid-template-rows: calc(70% - 16px) 30%; + grid-template-columns: repeat(2, 1fr); + + padding-top: 14px; + flex: 1; + + .images-player-wrapper { + grid-row: 1 / span 1; + grid-column: 1 / span 1; + } + + .result { + grid-row: 2 / span 1; + grid-column: 1 / span 1; + } + + ::ng-deep { + nz-card { + height: 100%; + display: flex; + flex-direction: column; + .ant-card-body { + flex: 1; + } + } + } + + table { + display: table; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + th { + color: var(--purple); + } + td, + th { + padding: 6px 0; + // border: 1px solid var(--border-color); + &:first-child { + width: 120px; + } + } + } + .detail-table { + grid-row: 1 / span 2; + grid-column: 2 / span 1; + ::ng-deep { + table { + display: table; + border-collapse: collapse; + border-spacing: 0; + } + th:not(:last-child) { + border-right: 1px solid var(--border-color); + } + td { + border-bottom: none !important; + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + } + thead { + tr:last-child th { + border-top: 1px solid var(--border-color); + } + } + tbody { + tr:last-child { + border-bottom: 1px solid var(--border-color); + } + } + } + } +} diff --git a/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.ts b/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.ts new file mode 100644 index 0000000..b4eaffd --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/history/history-detail/history-detail.component.ts @@ -0,0 +1,133 @@ +import { Component, OnInit, ViewEncapsulation } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { DetectionApiService, UtilsService } from "@client/app/core/services"; +import { PointStatusEnum, PoleItemDTO, PoleQueryDTO } from "@client/dtos"; +import { BehaviorSubject, forkJoin } from "rxjs"; +import { PoleGroupInterface } from "../../../components"; +import { ImageObj } from "../../../components/image-player/image-player.component"; + +@Component({ + selector: "app-history-detail", + templateUrl: "./history-detail.component.html", + styleUrls: ["./history-detail.component.less"], + // encapsulation: ViewEncapsulation.None, +}) +export class HistoryDetailComponent implements OnInit { + constructor(private api: DetectionApiService, private route: ActivatedRoute, private util: UtilsService) {} + + public PointStatusEnum = PointStatusEnum; + + public point: string = ""; + + public gmtCreate: string = ""; + + public type: string = ""; + + public status: PointStatusEnum = PointStatusEnum.NORMAL; + + public data: PoleGroupInterface[] = []; + + public images$ = new BehaviorSubject([]); + + lineAlarmZones: number[] = []; + + boltAlarmZones: number[] = []; + + ngOnInit(): void { + const id = this.route.snapshot.paramMap.get("id")!; + const { queryParams } = this.route.snapshot; + this.point = (queryParams["motorGroup"] ?? "") + "/" + (queryParams["point"] ?? ""); + this.gmtCreate = queryParams["gmtCreate"]; + this.type = queryParams["type"]; + this.status = Number(queryParams["status"]); + + this.getImageByJobId(id); + + // this.api.getFlatPoints().subscribe(r=> { + + // }) + + this.api.getHistoryDetail(id).subscribe((r: PoleQueryDTO) => { + let lineAlarms: number[] = []; + let boltAlarms: number[] = []; + const poles = Object.values(r).reduce((a, poles, idx) => { + let temperature: PoleItemDTO | null; + // console.log("pole", pole); + if (idx === 0 && poles?.[0]?.type === "temperature") { + temperature = poles[0]; + return a; + } + + const zone = poles[0].zone; + let bolt: PoleItemDTO[] = []; + let line: PoleItemDTO[] = []; + let pole!: PoleItemDTO; + + poles.forEach((item) => { + if (item.type === "temperature") { + temperature = item; + } + if (item.type === "bolt") { + bolt.push(item); + if (item.alarm) { + boltAlarms.push(zone); + } + } + if (item.type === "line") { + line.push(item); + if (item.alarm) { + lineAlarms.push(zone); + } + } + if (item.type === "pole") { + pole = item; + } + }); + + return a.concat({ + bolt, + line, + zone, + pole, + }); + }, [] as PoleGroupInterface[]); + + this.data = poles; + + this.lineAlarmZones = [...new Set(lineAlarms)]; + this.boltAlarmZones = [...new Set(boltAlarms)]; + }); + } + + getImageByJobId(jobId: string) { + this.api.getImg(jobId).subscribe((res) => { + let images: ImageObj[] = []; + Object.values(res.body).forEach((imgs) => { + images = images.concat(imgs.map((img) => ({ jobId, img }))); + }); + console.log("images", images); + this.images$.next(images); + }); + } + getImageByJobId1(jobId: string) { + this.api.getImg(jobId).subscribe(async (imgobj) => { + const images: string[] = []; + Object.values(imgobj).forEach((imgs) => { + images.push(...(imgs)); + }); + + // console.log("images", images); + + // console.time("img to base64"); + // const base64Imgs = await this.util.loadImages(images); + // console.timeEnd("img to base64"); + // console.log("base64Imgs", base64Imgs); + // console.time("bas64"); + // forkJoin([this.api.getBase64Image({ jobID: jobId, img: images[0] })]).subscribe((rr) => { + // console.timeEnd("bas64"); + // }); + // 1111 + // this.images$.next(images); + }); + } +} diff --git a/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.html b/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.html new file mode 100644 index 0000000..17b4739 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.html @@ -0,0 +1,91 @@ + +
+
+ + +
+
+ + + + +
+
+ +
+ +
+ + + + + + +
    +
  • 导出筛选报告
  • +
  • 导出筛选数据
  • +
  • 导出选中报告
  • +
  • 导出选中数据
  • +
+
+ + + + +
+
+
+
+ + + + + + + {{row.motorGroup}}/{{row.point}} + + + + + + {{data}} + + + + - + + + + + + + + + + {{data}} + + + +
+ + +
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.less b/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.less new file mode 100644 index 0000000..8030782 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.less @@ -0,0 +1,3 @@ +nz-card { + height: 100%; +} diff --git a/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.ts b/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.ts new file mode 100644 index 0000000..fc67ff1 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/history/history-list/history-list.component.ts @@ -0,0 +1,164 @@ +import { AfterViewInit, ViewChild } from "@angular/core"; +import { subDays, format } from "date-fns"; +import { Component, OnInit } from "@angular/core"; +import { Router } from "@angular/router"; +import { TableListComponent, TableListOption } from "@cdk/public-api"; +import { AnyObject } from "@cdk/types"; +import { DetectionApiService } from "@client/app/core/services"; +import { PointStatusEnum } from "@client/dtos"; +import { NzCascaderOption } from "ng-zorro-antd/cascader"; +import { HttpResponse } from "@angular/common/http"; +import { finalize } from "rxjs"; + +type QueryInterface = { + range: string[] | null; + pointId: null | string[]; + status: number | null; +}; + +const initQuery = { + range: null, + pointId: null, + status: null, +}; + +@Component({ + selector: "app-history-list", + templateUrl: "./history-list.component.html", + styleUrls: ["./history-list.component.less"], +}) +export class HistoryListComponent implements OnInit, AfterViewInit { + constructor(private api: DetectionApiService, private router: Router) {} + + @ViewChild("tableListRef") public tableListRef!: TableListComponent; + + public tableList = new TableListOption(this.fetchData.bind(this), { + frontPagination: false, + selectable: true, + rowKey: "jobId", + }); + + PointStatusEnum = PointStatusEnum; + + points: NzCascaderOption[] = []; + + query: QueryInterface = JSON.parse(JSON.stringify(initQuery)); + + selectedKeys: string[] = []; + + ngOnInit(): void { + this.initTableList(); + this.parsePoint(); + } + + ngAfterViewInit(): void { + this.tableListRef.props.getState$.subscribe((selected) => { + this.selectedKeys = selected.selectedKeys; + }); + } + + parsePoint() { + this.api.getAllPoint().subscribe((r) => { + const stationGroups = r[0]; + this.points = stationGroups.groupList.map((g) => { + return { + label: g.name, + value: g.motorGroupId, + children: g.pointList.map((p) => { + return { + label: p.name, + value: p.pointId, + isLeaf: true, + }; + }), + }; + }); + }); + } + + fetchData(pager: AnyObject) { + const q = this.formatQuery(); + return this.api.getDetcttionHistoryPage(pager, q); + } + + formatQuery() { + const q = Object.create(null); + Object.entries(this.query).forEach(([k, v]) => { + q[k] = v; + if (k === "range" && Array.isArray(v) && v.length === 2) { + const startTime = typeof v[0] === "string" ? v[0] : format(v[0], "yyyy-MM-dd"); + const endTime = typeof v[1] === "string" ? v[1] : format(v[1], "yyyy-MM-dd"); + q.startTime = startTime; + q.endTime = endTime; + } + if (k === "pointId" && Array.isArray(v) && v.length === 2) { + q.pointId = v[1]; + } + }); + + return q; + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "jobId", title: "序号" }, + { key: "point", title: "机组/监测点" }, + { key: "gmtCreate", title: "检测时间" }, + { key: "type", title: "检测类型" }, + { key: "status", title: "检测状态" }, + { key: "info", title: "异常信息" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "查看详情", + premissions: [], + onClick: (v) => { + const { info, jobId, ...queryParams } = v; + this.router.navigate(["/", "detection", "history", v.jobId], { queryParams }); + }, + }, + ]); + } + + search() { + this.tableListRef.doQuery(); + } + + reset() { + this.query = JSON.parse(JSON.stringify(initQuery)); + // this.tableListRef.reset(); + } + + exportLoading = false; + + export(type: number) { + this.exportLoading = true; + const q = this.formatQuery(); + const method = type % 2 === 0 ? "exportExcel" : "exportWord"; + const query = type <= 2 ? q : { jobs: this.selectedKeys }; + this.api[method](query) + .pipe( + finalize(() => { + this.exportLoading = false; + }) + ) + .subscribe((response) => { + this.downLoadFile(response); + }); + } + downLoadFile(response: HttpResponse) { + const fileNameFromHeader = response.headers.get("Content-Disposition"); + if (fileNameFromHeader) { + const fileName = fileNameFromHeader.split(";")[1].trim().split("=")[1].replace(/"/g, ""); + const blob = new Blob([response.body as any], { type: "application/zip" }); + const downloadLink = document.createElement("a"); + downloadLink.href = URL.createObjectURL(blob); + downloadLink.download = decodeURIComponent(fileName); + document.body.appendChild(downloadLink); + downloadLink.click(); + document.body.removeChild(downloadLink); + } + } +} diff --git a/projects/client/src/app/feature/detection/pages/index.ts b/projects/client/src/app/feature/detection/pages/index.ts new file mode 100644 index 0000000..b9642ab --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/index.ts @@ -0,0 +1,9 @@ +export * from "./analysis/analysis.component"; +export * from "./detection-index/detection-index.component"; +export * from "./history/history-detail/history-detail.component"; +export * from "./history/history-list/history-list.component"; +export * from "./settings/point-setting/point-setting.component"; +export * from "./settings/settings-layout/settings-layout.component"; +export * from "./settings/system-setting/system-setting.component"; +export * from "./settings/algorithm-setting/algorithm-setting.component"; +export * from "./settings/temperature-setting/temperature-setting.component"; diff --git a/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.html b/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.html new file mode 100644 index 0000000..15070a0 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.html @@ -0,0 +1,151 @@ + + + + +
+ + + + + +

检测算法设置

+ + + 螺栓转动角度阈值 + + + + + + + + + + + 引出线变量阈值 + + + + + + + + +

检测设置

+ + + 每日自动检测时间 + + + + + + {{time}} + + + + + + +
+ +
+
+
+
+ + + 延时检测设置 + + + + + + + + + + + 应用机组/检测点 + + + +
+ + + {{p['gname']}}/{{p.name}} + + + +
+
+ + + +
+
+
+
+
+ +
+
+
+ + + +
+ + + 每日自动检测时间 + + + + + + +
+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.less b/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.less new file mode 100644 index 0000000..d4dc61b --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.less @@ -0,0 +1,34 @@ +.btn-group { + border: 1px solid var(--border-color); + + li { + &:not(:last-child) { + a:after { + content: ""; + width: 1px; + height: 70%; + background-color: var(--border-color); + position: absolute; + top: 15%; + right: 0; + } + } + } + + a { + display: flex; + align-items: center; + justify-content: center; + padding: 6px 16px; + position: relative; + color: var(--text-color); + } +} + +.delayDetect { + display: none; + + &.show { + display: inline-block; + } +} \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.ts b/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.ts new file mode 100644 index 0000000..7059c34 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/algorithm-setting/algorithm-setting.component.ts @@ -0,0 +1,200 @@ +import { Component, OnInit, TemplateRef } from "@angular/core"; +import { FormArray, FormGroup, FormBuilder } from "@angular/forms"; +import { AnyObject } from "@cdk/types"; +import { Utils } from "@cdk/utils"; +import { DetectionApiService } from "@client/app/core/services"; +import { AlgorithmDTO, PointDTO } from "@client/dtos"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { finalize } from "rxjs"; +import { PointTableComponent } from "../../../components"; + +@Component({ + selector: "app-algorithm-setting", + templateUrl: "./algorithm-setting.component.html", + styleUrls: ["./algorithm-setting.component.less"], +}) +export class AlgorithmSettingComponent implements OnInit { + constructor( + private modal: NzModalService, + private api: DetectionApiService, + private fb: FormBuilder, + private msg: NzMessageService + ) {} + + formGroup!: FormGroup; + + submitLoading: boolean = false; + + flatPoints: PointDTO[] = []; + + tempTime: Date = new Date(); + + public get algorithmArray(): FormArray { + return this.formGroup.get("algorithm") as FormArray; + } + + ngOnInit(): void { + this.formGroup = this.fb.group({ + algorithm: this.fb.array([]), + }); + this.api.getFlatPoints().subscribe(({ points }) => { + this.flatPoints = points; + }); + this.api.getAlgorithm().subscribe((r) => { + if (r.success) { + if (Array.isArray(r.body)) { + r.body.forEach((item) => { + this.createAlgorithm(item); + }); + } + } + }); + } + + createAlgorithm(v?: AlgorithmDTO) { + let pointIdList: PointDTO[] = []; + if (v?.pointIdList && Array.isArray(v.pointIdList)) { + pointIdList = v.pointIdList.map((i) => this.flatPoints.find((f) => f.pointId === i)!); + } + this.algorithmArray.push( + this.fb.group({ + algorithmConfigId: [v?.algorithmConfigId], + name: [v?.name ?? "检测算法参数" + this.algorithmArray.length], + boltThreshold: [v?.boltThreshold ?? 0], + lineThreshold: [v?.lineThreshold ?? 0], + dailyAutoDetectionTime: [v?.dailyAutoDetectionTime ?? []], + delayDetect: [v?.delayDetect ?? 0], + pointIdList: [pointIdList], + }) + ); + } + + deletItem(i: number) { + this.algorithmArray.removeAt(i); + } + + quickTime(n: number, idx: number) { + const dailyAutoDetectionTime = this.algorithmArray.at(idx).get("dailyAutoDetectionTime"); + const timeArray = this.getTimeArray(n); + dailyAutoDetectionTime?.patchValue([...new Set(timeArray.concat(dailyAutoDetectionTime.value))]); + } + + getTimeArray(n: number) { + let result = []; + let hour = 0; + let minute = 0; + while (hour < 24) { + let timeString = `${hour.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}`; + result.push(timeString); + minute += n; + if (minute >= 60) { + hour += Math.floor(minute / 60); + minute = minute % 60; + } + if (hour >= 24) { + break; + } + } + return result; + } + + removeTime(arrIndex: number, timeIndex: number) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该时间?", + nzOnOk: () => { + const dailyAutoDetectionTime = this.algorithmArray.at(arrIndex).get("dailyAutoDetectionTime"); + const value = (dailyAutoDetectionTime?.value as string[]).filter((_, idx) => idx !== timeIndex); + dailyAutoDetectionTime?.patchValue(value); + }, + }); + } + + removePoint(arrIndex: number, pIndex: number) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要取消选择该监测点?", + nzOnOk: () => { + const pointIdList = this.algorithmArray.at(arrIndex).get("pointIdList"); + const value = (pointIdList?.value as string[]).filter((_, idx) => idx !== pIndex); + pointIdList?.patchValue(value); + }, + }); + } + + selectTime(nzContent: TemplateRef<{}>, idx: number) { + this.modal.create({ + nzTitle: "添加每日自动检测时间", + nzWidth: 480, + nzContent, + nzOnOk: async () => { + if (this.tempTime) { + const dailyAutoDetectionTime = this.algorithmArray.at(idx).get("dailyAutoDetectionTime"); + const value = (dailyAutoDetectionTime?.value as string[]).concat(format(this.tempTime, "HH:mm")); + dailyAutoDetectionTime?.patchValue(value); + this.tempTime = new Date(); + } + }, + }); + } + + onDelayDetectClose(checked: boolean, i: number) { + this.algorithmArray + .at(i) + .get("delayDetect") + ?.patchValue(checked ? null : 0); + } + + onSave() { + if (Utils.validateFormGroup(this.formGroup)) { + let { algorithm } = this.formGroup.value; + if (Array.isArray(algorithm) && algorithm.some((s) => s?.pointIdList?.length === 0)) { + this.msg.error("请添加应用机组/检测点"); + return; + } + algorithm = algorithm.map((i: AnyObject) => ({ + ...i, + pointIdList: i["pointIdList"].map((p: PointDTO) => p.pointId), + })); + this.submitLoading = true; + this.api + .saveAlgorithm(algorithm) + .pipe( + finalize(() => { + this.submitLoading = false; + }) + ) + .subscribe((res) => { + this.msg.success(res.desc); + }); + } + } + + selectPoint(idx: number) { + const pointIdList = this.algorithmArray.at(idx).get("pointIdList"); + + const otherSelected: PointDTO[] = []; + + Array.from({ length: this.algorithmArray.length }, (_, index) => { + if (index !== idx) { + otherSelected.push(...this.algorithmArray.at(index).get("pointIdList")?.value); + } + }); + + this.modal.create({ + nzTitle: "添加监测点", + nzWidth: 640, + nzContent: PointTableComponent, + nzComponentParams: { + currentSelected: pointIdList?.value, + otherSelected, + }, + nzOnOk: async (e: PointTableComponent) => { + const v = e.arrOfChecked; + pointIdList?.patchValue(v); + }, + }); + } +} diff --git a/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.html b/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.html new file mode 100644 index 0000000..ea0b4cf --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.html @@ -0,0 +1,31 @@ + + + + + + + + 检测设备 + + + + + + + + + 数据复位 + + + + + + + + + \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.less b/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.ts b/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.ts new file mode 100644 index 0000000..b29326f --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/point-setting/point-setting.component.ts @@ -0,0 +1,73 @@ +import { NzMessageService } from "ng-zorro-antd/message"; +import { Component, OnInit, TemplateRef } from "@angular/core"; +import { DetectionApiService } from "@client/app/core/services"; +import { PointDTO, PointGroupDTO } from "@client/dtos"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { finalize, lastValueFrom } from "rxjs"; + +@Component({ + selector: "app-point-setting", + templateUrl: "./point-setting.component.html", + styleUrls: ["./point-setting.component.less"], +}) +export class PointSettingComponent implements OnInit { + constructor(private api: DetectionApiService, private modal: NzModalService, private msg: NzMessageService) {} + + points: PointDTO[] = []; + + resetLoading = false; + + saveLoading = false; + + ngOnInit(): void { + this.parsePoint(); + } + + parsePoint(force?: boolean) { + this.api.getAllPoint(force).subscribe((r) => { + const stationGroups = r[0]; + const ps: PointDTO[] = []; + stationGroups.groupList.forEach((g) => { + ps.push(...g.pointList.map((p) => ({ ...p, gname: g.name, enableDetectBool: p.enableDetect === 0 }))); + }); + this.points = ps; + }); + } + + onReset(pid: string) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要复位数据?", + nzOnOk: async () => { + this.resetLoading = true; + const res = await lastValueFrom( + this.api.resetPointData(pid).pipe( + finalize(() => { + this.resetLoading = false; + }) + ) + ); + if (res.success) { + this.msg.success(res.desc); + this.parsePoint(true); + } + }, + }); + } + + async onSave() { + this.saveLoading = true; + const p = this.points.map((p) => ({ pointId: p.pointId, enableDetect: p["enableDetectBool"] ? 0 : 1 })); + const res = await lastValueFrom( + this.api.savePointEnable(p).pipe( + finalize(() => { + this.saveLoading = false; + }) + ) + ); + if (res.success) { + this.msg.success(res.desc); + this.parsePoint(true); + } + } +} diff --git a/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.html b/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.html new file mode 100644 index 0000000..0cab495 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.html @@ -0,0 +1,29 @@ + +
+ +
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.less b/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.less new file mode 100644 index 0000000..b871213 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.less @@ -0,0 +1,25 @@ +:host { + display: flex; + height: 100%; +} + +.menu { + flex-basis: 200px; + + a { + display: block; + padding: 16px 24px; + color: var(--text-color); + border-right: 2px solid transparent; + + &:hover { + color: var(--p); + } + + &.active { + background: var(--blue3-10); + border-right-color: var(--p); + color: var(--p); + } + } +} \ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.ts b/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.ts new file mode 100644 index 0000000..bbd9664 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/settings-layout/settings-layout.component.ts @@ -0,0 +1,8 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "app-settings", + templateUrl: "./settings-layout.component.html", + styleUrls: ["./settings-layout.component.less"], +}) +export class SettingsLayoutComponent {} diff --git a/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.html b/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.html new file mode 100644 index 0000000..96a8e25 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.html @@ -0,0 +1,43 @@ + +
+ 系统版本 +
+
+ {{version}} +
+
+
+
+ + + + + + + 自动导出报告设置 + + +
+ + + + + +
+
+
+ + + 导出文件保存位置 + + +
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.less b/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.less new file mode 100644 index 0000000..b4bebaa --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.less @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + height: 100%; +} diff --git a/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.ts b/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.ts new file mode 100644 index 0000000..7285016 --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/system-setting/system-setting.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Utils } from "@cdk/utils"; +import { DetectionApiService } from "@client/app/core/services"; +import { NzMessageService } from "ng-zorro-antd/message"; + +@Component({ + selector: "app-system-setting", + templateUrl: "./system-setting.component.html", + styleUrls: ["./system-setting.component.less"], +}) +export class SystemSettingComponent implements OnInit { + constructor(private api: DetectionApiService, private msg: NzMessageService) {} + + version: string = ""; + + formGroup = new FormGroup({ + report_auto_export_time: new FormControl(["30"]), + report_auto_export_dir: new FormControl([""]), + }); + + ngOnInit(): void { + this.api.getVersion().subscribe((r) => { + this.version = r.body?.version; + }); + this.getExportConfig("report_auto_export_time"); + this.getExportConfig("report_auto_export_dir"); + } + + getExportConfig(configId: string) { + this.api.getExportConfig({ configId }).subscribe((r) => { + this.formGroup.patchValue({ [configId]: r.body?.value }); + }); + } + + saveConfig() { + if (Utils.validateFormGroup(this.formGroup)) { + const { value } = this.formGroup; + Object.entries(value).forEach(([k, v]) => { + this.api.updateExportConfig({ configId: k, value: v }).subscribe((r) => { + this.msg.success(r.desc); + }); + }); + } + } +} diff --git a/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.html b/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.html new file mode 100644 index 0000000..577f32b --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.html @@ -0,0 +1,72 @@ + + + + +
+ + + + + + + + + + + 检测点温度检测阈值 + + + + + + + + + + + + 应用设备 + + + +
+ + + {{d['gname']}}/{{d.name}} + + + + +
+ +
+ + + + +
+
+
+
+
+ +
+
+ +
\ No newline at end of file diff --git a/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.less b/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.ts b/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.ts new file mode 100644 index 0000000..92df56a --- /dev/null +++ b/projects/client/src/app/feature/detection/pages/settings/temperature-setting/temperature-setting.component.ts @@ -0,0 +1,129 @@ +import { Component, TemplateRef } from "@angular/core"; +import { DetectionApiService } from "@client/app/core/services"; +import { FormArray, FormGroup, FormBuilder } from "@angular/forms"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { DeviceDTO, PointDTO, TemperatureSettingDTO } from "@client/dtos"; +import { DeviceTableComponent } from "../../../components"; +import { Utils } from "@cdk/utils"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { AnyObject } from "@cdk/types"; +import { finalize } from "rxjs"; + +@Component({ + selector: "app-temperature-setting", + templateUrl: "./temperature-setting.component.html", + styleUrls: ["./temperature-setting.component.less"], +}) +export class TemperatureSettingComponent { + constructor( + private modal: NzModalService, + private fb: FormBuilder, + private api: DetectionApiService, + private msg: NzMessageService + ) {} + + formGroup!: FormGroup; + + submitLoading: boolean = false; + + flatPoints: PointDTO[] = []; + + public get settingArray(): FormArray { + return this.formGroup.get("temperature") as FormArray; + } + + ngOnInit(): void { + this.formGroup = this.fb.group({ + temperature: this.fb.array([]), + }); + this.api.getFlatPoints().subscribe(({ points }) => { + this.flatPoints = points; + }); + this.api.getTemperatureSettings().subscribe((r) => { + if (r.success) { + if (Array.isArray(r.body)) { + r.body.forEach((item) => { + this.createAlgorithm(item); + }); + } + } + }); + } + + createAlgorithm(v?: TemperatureSettingDTO) { + this.settingArray.push( + this.fb.group({ + tempThresholdId: [v?.tempThresholdId], + name: [v?.name ?? "检测点温度检测参数" + this.settingArray.length], + tempThreshold: [v?.tempThreshold ?? 0], + deviceIdList: [v?.deviceIdList ?? []], + }) + ); + } + + deletItem(i: number) { + this.settingArray.removeAt(i); + } + + removeDevice(arrIndex: number, deviceIndex: number) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要取消选择该设备?", + nzOnOk: () => { + const deviceIdList = this.settingArray.at(arrIndex).get("deviceIdList"); + const value = (deviceIdList?.value as string[]).filter((_, idx) => idx !== deviceIndex); + deviceIdList?.patchValue(value); + }, + }); + } + + selectPoint(idx: number) { + const deviceIdList = this.settingArray.at(idx).get("deviceIdList"); + const otherSelected: any[] = []; + + Array.from({ length: this.settingArray.length }, (_, index) => { + if (index !== idx) { + console.log(" ", index); + otherSelected.push(...this.settingArray.at(index).get("deviceIdList")?.value); + } + }); + console.log("otherSelected", otherSelected); + this.modal.create({ + nzTitle: "添加设备", + nzWidth: 640, + nzContent: DeviceTableComponent, + nzComponentParams: { + otherSelected, + }, + nzOnOk: async (e) => { + const newVals = e.selectedDevice.concat(deviceIdList?.value); + deviceIdList?.setValue(newVals); + }, + }); + } + + onSave() { + if (Utils.validateFormGroup(this.formGroup)) { + let { temperature } = this.formGroup.value; + if (Array.isArray(temperature) && temperature.some((s) => s?.deviceIdList?.length === 0)) { + this.msg.error("请添加应用设备"); + return; + } + // temperature = temperature.map((i: AnyObject) => ({ + // ...i, + // pointIdList: i["pointIdList"].map((p: PointDTO) => p.pointId), + // })); + this.submitLoading = true; + this.api + .saveTemperatureSetting(temperature) + .pipe( + finalize(() => { + this.submitLoading = false; + }) + ) + .subscribe((res) => { + this.msg.success(res.desc); + }); + } + } +} diff --git a/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.html b/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.html new file mode 100644 index 0000000..46135a6 --- /dev/null +++ b/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.html @@ -0,0 +1,80 @@ +
+ +
+ + +
+ + + +
    + +
  • + +
    +
    {{item.content}}
    +
    {{item.gmtCreate}}
    + +
    +
  • +
    +
+
+ + +
+
+
+
+ +
+
\ No newline at end of file diff --git a/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.less b/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.less new file mode 100644 index 0000000..4699846 --- /dev/null +++ b/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.less @@ -0,0 +1,144 @@ +:host { + display: block; + width: 100vw; + height: 100vh; + overflow: hidden; + background-color: var(--bg-color); +} + +@header-height: 60px; + +.header { + margin-top: 8px; + + height: @header-height; + + .title { + color: var(--title-color); + } + + .dec-logo { + position: absolute; + top: 24px; + left: 32px; + + b { + font-size: 1.5rem; + } + + span { + margin-top: -3px; + margin-left: 4px; + transform: scale(1.05); + font-size: 1.25rem; + } + + a { + display: flex; + align-items: center; + height: 34px; + + img { + display: block; + height: 34px; + margin-right: 12px; + } + + ::ng-deep { + .ant-divider-vertical { + border-left-color: var(--title-color) + } + } + + &:hover { + color: var(--title-color); + } + } + + ::ng-deep { + .ant-divider-vertical { + height: 1.2em; + } + } + } + + .main-nav { + width: 510px; + margin: 1px auto 0; + height: 50px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + // background-color: rgba(255, 255, 255, 0.2); + + // &::after { + // content: ""; + // position: absolute; + // top: 0; + // left: -40px; + // width: calc(100% + 80px); + // height: 0px; + // border-width: 55px; + // border-style: solid; + // border-color: rgba(255, 255, 255, 0.15) transparent transparent transparent; + // } + + .nav-item { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + color: var(--text-color); + font-size: 16px; + position: relative; + + &:hover { + color: var(--p); + } + + &.active { + color: var(--p); + font-weight: bold; + + &::after { + content: ""; + width: 40px; + height: 3px; + background-color: var(--p); + position: absolute; + bottom: -9px; + left: 50%; + transform: translateX(-50%); + } + } + } + } +} + +.right { + position: absolute; + top: 20px; + right: 32px; + + button { + padding-left: 12px; + padding-right: 12px; + } +} + +.app-container { + margin: 16px 32px 32px; +} + +.alert { + .time { + color: var(--gray-2); + } + + nz-divider { + margin: 12px 0 0; + } +} \ No newline at end of file diff --git a/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.ts b/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.ts new file mode 100644 index 0000000..c7c72c1 --- /dev/null +++ b/projects/client/src/app/shared/components/authorization-layout/authorization-layout.component.ts @@ -0,0 +1,50 @@ +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { Component, Inject, OnInit } from "@angular/core"; +import { AuthService, DetectionApiService } from "@client/app/core/services"; +import { AlarmDTO } from "@client/dtos"; +import { DecConfig, decConfigToken } from "@cdk/public-api"; +import { Router } from "@angular/router"; + +@Component({ + selector: "app-authorization-layout", + templateUrl: "./authorization-layout.component.html", + styleUrls: ["./authorization-layout.component.less"], +}) +export class AuthorizationLayoutComponent implements OnInit { + constructor( + private api: DetectionApiService, + private auth: AuthService, + private modal: NzModalService, + private msg: NzMessageService, + @Inject(decConfigToken) private decConfig: Required, + private router: Router + ) {} + + system$ = this.auth.getSystemInfo(); + + notices: AlarmDTO[] = []; + + ngOnInit(): void { + this.getNotice(); + } + + getNotice() { + this.api.getNotice().subscribe((res) => { + this.notices = res.body; + }); + } + + logout() { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要退出登录?", + nzOnOk: () => { + this.msg.success("已退出登录"); + localStorage.removeItem(this.decConfig.localStroageKey); + localStorage.removeItem("auth"); + this.router.navigate([this.decConfig.loginUrl]); + }, + }); + } +} diff --git a/projects/client/src/app/shared/components/bg-border/bg-border.component.html b/projects/client/src/app/shared/components/bg-border/bg-border.component.html new file mode 100644 index 0000000..c45a4ac --- /dev/null +++ b/projects/client/src/app/shared/components/bg-border/bg-border.component.html @@ -0,0 +1,63 @@ +
+ + + + + + +
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/projects/client/src/app/shared/components/bg-border/bg-border.component.less b/projects/client/src/app/shared/components/bg-border/bg-border.component.less new file mode 100644 index 0000000..d81891b --- /dev/null +++ b/projects/client/src/app/shared/components/bg-border/bg-border.component.less @@ -0,0 +1,220 @@ +:host { + display: block; + overflow: hidden; + background-color: var(--bg-color); + pointer-events: none; + position: fixed; + inset: 0; +} + +#point-bg circle { + fill: var(--border-color); +} + + + +.dec-border { + position: fixed; + inset: 0; + + svg { + + rect, + polygon { + fill: var(--border-color); + + } + } + + &::before { + content: ""; + width: 1px; + background-color: var(--border-color); + position: absolute; + top: 310px; + left: 20px; + bottom: 310px; + } + + &::after { + content: ""; + width: 1px; + background-color: var(--border-color); + position: absolute; + top: 310px; + right: 20px; + bottom: 310px; + } + + .border-top { + height: 1px; + position: absolute; + top: 78px; + left: 154px; + right: 154px; + + &::before { + content: ""; + width: calc(50vw - 162px - 306px); + height: 1px; + background-color: var(--border-color); + position: absolute; + top: -70px; + left: 0; + } + + &::after { + content: ""; + width: calc(50vw - 162px - 306px); + height: 1px; + background-color: var(--border-color); + position: absolute; + top: -70px; + right: 0; + } + + .nav-polygon { + width: 610px; + height: 52px; + background-color: var(--nav-bg); + + position: absolute; + top: -70px; + left: 50%; + right: 50%; + transform: translateX(-50%); + bottom: 10px; + clip-path: polygon(0px 0px, 610px 0px, 550px 60px, 60px 60px); + } + + .line-center { + width: 510px; + height: 1px; + background-color: var(--border-color); + position: absolute; + left: 50%; + right: 50%; + bottom: 10px; + transform: translateX(-50%); + + &::before { + content: ""; + width: 85px; + height: 1px; + background-color: var(--border-color); + position: absolute; + top: 0; + left: 0; + transform-origin: bottom left; + transform: rotate(225deg); + } + + &::after { + content: ""; + width: 85px; + height: 1px; + background-color: var(--border-color); + position: absolute; + top: 0; + right: 0; + transform-origin: bottom right; + transform: rotate(135deg); + } + } + } + + .border-bottom { + height: 1px; + position: absolute; + left: 154px; + right: 154px; + bottom: 10px; + + &::before { + content: ""; + width: calc(50vw - 162px - 255px); + height: 1px; + background-color: var(--border-color); + position: absolute; + top: 0; + left: 0; + } + + &::after { + content: ""; + width: calc(50vw - 162px - 255px); + height: 1px; + background-color: var(--border-color); + position: absolute; + top: 0; + right: 0; + } + + .line-center { + width: 510px; + height: 1px; + background-color: var(--border-color); + position: absolute; + left: 50%; + right: 50%; + bottom: 10px; + transform: translateX(-50%); + + &::before { + content: ""; + width: 12px; + height: 1px; + background-color: var(--border-color); + position: absolute; + top: 0; + left: 0; + transform-origin: bottom left; + transform: rotate(135deg); + } + + &::after { + content: ""; + width: 12px; + height: 1px; + background-color: var(--border-color); + position: absolute; + top: 0; + right: 0; + transform-origin: bottom right; + transform: rotate(225deg); + } + } + } + + rect, + polygon { + fill: var(--page-corner-bg); + } + + polyline { + stroke: var(--border-color); + stroke-width: 1; + fill: none; + } + + .top-right { + position: fixed; + top: 0; + right: 0; + transform: rotate(90deg); + } + + .bottom-left { + position: fixed; + bottom: 0; + left: 0; + transform: rotate(-90deg); + } + + .bottom-right { + position: fixed; + bottom: 0; + right: 0; + transform: rotate(180deg); + } +} \ No newline at end of file diff --git a/projects/client/src/app/shared/components/bg-border/bg-border.component.ts b/projects/client/src/app/shared/components/bg-border/bg-border.component.ts new file mode 100644 index 0000000..71597f8 --- /dev/null +++ b/projects/client/src/app/shared/components/bg-border/bg-border.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-bg-border', + templateUrl: './bg-border.component.html', + styleUrls: ['./bg-border.component.less'] +}) +export class BgBorderComponent { + +} diff --git a/projects/client/src/app/shared/components/index.ts b/projects/client/src/app/shared/components/index.ts new file mode 100644 index 0000000..7d6ff56 --- /dev/null +++ b/projects/client/src/app/shared/components/index.ts @@ -0,0 +1,2 @@ +export * from "./authorization-layout/authorization-layout.component"; +export * from "./bg-border/bg-border.component"; diff --git a/projects/client/src/app/shared/directives/dec-corner.directive.ts b/projects/client/src/app/shared/directives/dec-corner.directive.ts new file mode 100644 index 0000000..13d9f08 --- /dev/null +++ b/projects/client/src/app/shared/directives/dec-corner.directive.ts @@ -0,0 +1,19 @@ +import { Directive, ElementRef, Renderer2 } from "@angular/core"; + +@Directive({ + selector: "[decCorner]", +}) +export class DecCornerDirective { + constructor(private el: ElementRef, private rd2: Renderer2) {} + + ngOnInit() { + const cornerWapper = this.rd2.createElement("div"); + this.rd2.setAttribute(cornerWapper, "class", "dec-corner"); + Array.from({ length: 4 }, () => { + const el = this.rd2.createElement("div"); + this.rd2.appendChild(cornerWapper, el); + }); + this.rd2.appendChild(this.el.nativeElement, cornerWapper); + this.rd2.addClass(this.el.nativeElement, "has-corner"); + } +} diff --git a/projects/client/src/app/shared/directives/index.ts b/projects/client/src/app/shared/directives/index.ts new file mode 100644 index 0000000..bf2b63f --- /dev/null +++ b/projects/client/src/app/shared/directives/index.ts @@ -0,0 +1 @@ +export * from "./dec-corner.directive"; diff --git a/projects/client/src/app/shared/ng-zorro.ts b/projects/client/src/app/shared/ng-zorro.ts new file mode 100644 index 0000000..5fd3cf7 --- /dev/null +++ b/projects/client/src/app/shared/ng-zorro.ts @@ -0,0 +1,96 @@ +import { NzGridModule } from "ng-zorro-antd/grid"; +import { NzCardModule } from "ng-zorro-antd/card"; +import { NzStatisticModule } from "ng-zorro-antd/statistic"; +import { NzIconModule } from "ng-zorro-antd/icon"; +import { NzToolTipModule } from "ng-zorro-antd/tooltip"; +import { NzTableModule } from "ng-zorro-antd/table"; +import { NzSegmentedModule } from "ng-zorro-antd/segmented"; +import { NzSpaceModule } from "ng-zorro-antd/space"; +import { NzDatePickerModule } from "ng-zorro-antd/date-picker"; +import { NzListModule } from "ng-zorro-antd/list"; +import { NzInputModule } from "ng-zorro-antd/input"; +import { NzButtonModule } from "ng-zorro-antd/button"; +import { NzTagModule } from "ng-zorro-antd/tag"; +import { NzBadgeModule } from "ng-zorro-antd/badge"; +import { NzPaginationModule } from "ng-zorro-antd/pagination"; +import { NzDividerModule } from "ng-zorro-antd/divider"; +import { NzSelectModule } from "ng-zorro-antd/select"; +import { NzModalModule } from "ng-zorro-antd/modal"; +import { NzMessageModule } from "ng-zorro-antd/message"; +import { NzDrawerModule } from "ng-zorro-antd/drawer"; +import { NzFormModule } from "ng-zorro-antd/form"; +import { NzDescriptionsModule } from "ng-zorro-antd/descriptions"; +import { NzTabsModule } from "ng-zorro-antd/tabs"; +import { NzProgressModule } from "ng-zorro-antd/progress"; +import { NzAvatarModule } from "ng-zorro-antd/avatar"; +import { NzMenuModule } from "ng-zorro-antd/menu"; +import { NzDropDownModule } from "ng-zorro-antd/dropdown"; +import { NzTreeSelectModule } from "ng-zorro-antd/tree-select"; +import { NzRadioModule } from "ng-zorro-antd/radio"; +import { NzCheckboxModule } from "ng-zorro-antd/checkbox"; +import { NzCalendarModule } from "ng-zorro-antd/calendar"; +import { NzSkeletonModule } from "ng-zorro-antd/skeleton"; +import { NzTimelineModule } from "ng-zorro-antd/timeline"; +import { NzEmptyModule } from "ng-zorro-antd/empty"; +import { NzSpinModule } from "ng-zorro-antd/spin"; +import { NzResultModule } from "ng-zorro-antd/result"; +import { NzCascaderModule } from "ng-zorro-antd/cascader"; +import { NzAutocompleteModule } from "ng-zorro-antd/auto-complete"; +import { NzPopoverModule } from "ng-zorro-antd/popover"; +import { NzPageHeaderModule } from "ng-zorro-antd/page-header"; +import { NzTreeModule } from "ng-zorro-antd/tree"; +import { NzSwitchModule } from "ng-zorro-antd/switch"; +import { NzCarouselModule } from "ng-zorro-antd/carousel"; +import { NzTimePickerModule } from "ng-zorro-antd/time-picker"; +import { NzImageModule } from "ng-zorro-antd/image"; +import { NzInputNumberModule } from "ng-zorro-antd/input-number"; + +export const ngZorroModules = [ + NzInputNumberModule, + NzImageModule, + NzTimePickerModule, + NzCarouselModule, + NzSwitchModule, + NzTreeModule, + NzPageHeaderModule, + NzPopoverModule, + NzAutocompleteModule, + NzCascaderModule, + NzResultModule, + NzSpinModule, + NzGridModule, + NzCardModule, + NzStatisticModule, + NzIconModule, + NzToolTipModule, + NzTableModule, + NzSegmentedModule, + NzSpaceModule, + NzDatePickerModule, + NzListModule, + NzInputModule, + NzButtonModule, + NzTagModule, + NzBadgeModule, + NzPaginationModule, + NzDividerModule, + NzSelectModule, + NzSelectModule, + NzModalModule, + NzMessageModule, + NzDrawerModule, + NzFormModule, + NzDescriptionsModule, + NzTabsModule, + NzProgressModule, + NzAvatarModule, + NzMenuModule, + NzDropDownModule, + NzTreeSelectModule, + NzRadioModule, + NzCalendarModule, + NzCheckboxModule, + NzSkeletonModule, + NzTimelineModule, + NzEmptyModule, +]; diff --git a/projects/client/src/app/shared/shared.module.ts b/projects/client/src/app/shared/shared.module.ts new file mode 100644 index 0000000..f0644cd --- /dev/null +++ b/projects/client/src/app/shared/shared.module.ts @@ -0,0 +1,49 @@ +import { RouterModule } from "@angular/router"; +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { ngZorroModules } from "./ng-zorro"; +import { AuthorizationLayoutComponent, BgBorderComponent } from "./components"; +import { DecCornerDirective } from "./directives"; +import { + DecModule, + FormErrorTipsComponent, + InputSpaceErrorDirective, + PublicPathPipe, + TableListModule, + StorageModule, + QuickDateRangeComponent, +} from "@cdk/public-api"; +import { HttpClientModule } from "@angular/common/http"; +import { environment } from "@client/environments/environment"; +import { NgxPermissionsModule } from "ngx-permissions"; + +const ngModules = [CommonModule, HttpClientModule, FormsModule, RouterModule, ReactiveFormsModule]; +const components = [AuthorizationLayoutComponent, BgBorderComponent]; +const directives = [DecCornerDirective]; +const cdks = [ + FormErrorTipsComponent, + InputSpaceErrorDirective, + PublicPathPipe, + TableListModule, + StorageModule, + QuickDateRangeComponent, +]; + +@NgModule({ + declarations: [...components, ...directives], + imports: [ + DecModule.forRoot({ + environment, + isClient: true, + localStroageKey: "clinet_token", + loginUrl: "/auth/login", + }), + NgxPermissionsModule.forChild(), + ...ngZorroModules, + ...ngModules, + ...cdks, + ], + exports: [...ngZorroModules, ...ngModules, ...components, ...directives, ...cdks, NgxPermissionsModule], +}) +export class SharedModule {} diff --git a/projects/client/src/assets/.gitkeep b/projects/client/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/projects/client/src/assets/icons/alert.svg b/projects/client/src/assets/icons/alert.svg new file mode 100644 index 0000000..2cd4da4 --- /dev/null +++ b/projects/client/src/assets/icons/alert.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/bell.svg b/projects/client/src/assets/icons/bell.svg new file mode 100644 index 0000000..9aa95ed --- /dev/null +++ b/projects/client/src/assets/icons/bell.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/disconnect.svg b/projects/client/src/assets/icons/disconnect.svg new file mode 100644 index 0000000..9484f8b --- /dev/null +++ b/projects/client/src/assets/icons/disconnect.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/folder.svg b/projects/client/src/assets/icons/folder.svg new file mode 100644 index 0000000..80ad456 --- /dev/null +++ b/projects/client/src/assets/icons/folder.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/fullscreen.svg b/projects/client/src/assets/icons/fullscreen.svg new file mode 100644 index 0000000..8bcd879 --- /dev/null +++ b/projects/client/src/assets/icons/fullscreen.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/projects/client/src/assets/icons/light.svg b/projects/client/src/assets/icons/light.svg new file mode 100644 index 0000000..0d4a474 --- /dev/null +++ b/projects/client/src/assets/icons/light.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/projects/client/src/assets/icons/lock.svg b/projects/client/src/assets/icons/lock.svg new file mode 100644 index 0000000..f01201b --- /dev/null +++ b/projects/client/src/assets/icons/lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/moon.svg b/projects/client/src/assets/icons/moon.svg new file mode 100644 index 0000000..6f87259 --- /dev/null +++ b/projects/client/src/assets/icons/moon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/projects/client/src/assets/icons/no-image-white.png b/projects/client/src/assets/icons/no-image-white.png new file mode 100644 index 0000000..86ec118 Binary files /dev/null and b/projects/client/src/assets/icons/no-image-white.png differ diff --git a/projects/client/src/assets/icons/no-image.png b/projects/client/src/assets/icons/no-image.png new file mode 100644 index 0000000..d12688d Binary files /dev/null and b/projects/client/src/assets/icons/no-image.png differ diff --git a/projects/client/src/assets/icons/no-image.svg b/projects/client/src/assets/icons/no-image.svg new file mode 100644 index 0000000..dadaa1a --- /dev/null +++ b/projects/client/src/assets/icons/no-image.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/pie-center.svg b/projects/client/src/assets/icons/pie-center.svg new file mode 100644 index 0000000..49d4ad0 --- /dev/null +++ b/projects/client/src/assets/icons/pie-center.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/client/src/assets/icons/power.svg b/projects/client/src/assets/icons/power.svg new file mode 100644 index 0000000..b31c16f --- /dev/null +++ b/projects/client/src/assets/icons/power.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/success.svg b/projects/client/src/assets/icons/success.svg new file mode 100644 index 0000000..bf58abe --- /dev/null +++ b/projects/client/src/assets/icons/success.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/icons/user.svg b/projects/client/src/assets/icons/user.svg new file mode 100644 index 0000000..92fad76 --- /dev/null +++ b/projects/client/src/assets/icons/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/projects/client/src/assets/imgs/logo.png b/projects/client/src/assets/imgs/logo.png new file mode 100644 index 0000000..926913b Binary files /dev/null and b/projects/client/src/assets/imgs/logo.png differ diff --git a/projects/client/src/dtos/alarm.dto.ts b/projects/client/src/dtos/alarm.dto.ts new file mode 100644 index 0000000..f0b7396 --- /dev/null +++ b/projects/client/src/dtos/alarm.dto.ts @@ -0,0 +1,6 @@ +export type AlarmDTO = { + alarmId: string; + content: string; + type: number; + gmtCreate: string; +}; diff --git a/projects/client/src/dtos/algorithm.dto.ts b/projects/client/src/dtos/algorithm.dto.ts new file mode 100644 index 0000000..fbab358 --- /dev/null +++ b/projects/client/src/dtos/algorithm.dto.ts @@ -0,0 +1,11 @@ +import { Augmented } from "@cdk/types"; + +export type AlgorithmDTO = Augmented<{ + algorithmConfigId: string; //参数Id + name: string; + boltThreshold: number; //螺栓阈值 + lineThreshold: number; //引出线阈值 + dailyAutoDetectionTime: string[]; //每日自动检测时间 + delayDetect: number; //延时检测 + pointIdList: string[]; +}>; diff --git a/projects/client/src/dtos/auth.dto.ts b/projects/client/src/dtos/auth.dto.ts new file mode 100644 index 0000000..cece8b7 --- /dev/null +++ b/projects/client/src/dtos/auth.dto.ts @@ -0,0 +1,14 @@ +export type AuthDTO = { + userId: string; + userName: string; + role: string; + permissionList: PermissionDTO[]; +}; + +export type PermissionDTO = { + roleId: string; + name: string; + value: string; + scope: number; + type: number; +}; diff --git a/projects/client/src/dtos/index.ts b/projects/client/src/dtos/index.ts new file mode 100644 index 0000000..7e1f259 --- /dev/null +++ b/projects/client/src/dtos/index.ts @@ -0,0 +1,5 @@ +export * from "./alarm.dto"; +export * from "./algorithm.dto"; +export * from "./auth.dto"; +export * from "./point.dto"; +export * from "./temperature.dto"; diff --git a/projects/client/src/dtos/point.dto.ts b/projects/client/src/dtos/point.dto.ts new file mode 100644 index 0000000..7230ec9 --- /dev/null +++ b/projects/client/src/dtos/point.dto.ts @@ -0,0 +1,71 @@ +import { Augmented } from "@cdk/types"; + +export type PowerStationDTO = Augmented<{ + bizId: string; //电站id + name: string; //电站名称 + address: string; + contact: string; + phone: string; + introduction: string; + groupList: PointGroupDTO[]; +}>; + +export type PointGroupDTO = Augmented<{ + contact: string; + gmtCreate: string; + motorGroupId: string; + name: string; + phone: string; + status: PointStatusEnum; + powerStation: string; + pointList: PointDTO[]; +}>; + +export type PointDTO = Augmented<{ + pointId: string; //检测点id + name: string; //检测点名称 + poleNum: number; //磁极数量 + manualTime: number; + automaticTime: number; + enableDetect: number; + powerStation: string; + motorGroup: string; + boltDetect: number; + lineDetect: number; + poleOpenDetect: number; + pointTempDetect: number; + status: number; //检测点状态0-检测正常,1-检测异常,2-设备掉线 + gmtReset: number; +}>; + +export enum PointStatusEnum { + NORMAL, // 检测正常1 + ABNORMAL, // 检测异常 + DISCONNECT, //设备掉线 +} + +export type PoleItemDTO = { + alarm: boolean; + img: string; + position: number; + type: "bolt" | "line" | "temperature" | "pole"; + value: number; + zone: number; +}; + +export type PoleQueryDTO = { + [k: number]: PoleItemDTO[]; +}; + +export type DeviceDTO = Augmented<{ + gmtCreate: string; + deviceId: string; + type: string; + name: string; + powerStationId: string; + product: string; + motorGroupId: string; + pointId: string; + status: number; //设备状态:0-停用,1-正常,2-离线 + vender: string; +}>; diff --git a/projects/client/src/dtos/temperature.dto.ts b/projects/client/src/dtos/temperature.dto.ts new file mode 100644 index 0000000..1b7bd58 --- /dev/null +++ b/projects/client/src/dtos/temperature.dto.ts @@ -0,0 +1,8 @@ +import { Augmented } from "@cdk/types"; + +export type TemperatureSettingDTO = Augmented<{ + tempThresholdId: string; + name: string; + tempThreshold: number; + deviceIdList: string[]; +}>; diff --git a/projects/client/src/environments/environment.prod.ts b/projects/client/src/environments/environment.prod.ts new file mode 100644 index 0000000..744b0c6 --- /dev/null +++ b/projects/client/src/environments/environment.prod.ts @@ -0,0 +1,6 @@ +export const environment = { + production: true, + clientVersion: "1.0.0", + clientType: "web", + host: "http://47.109.27.8", +}; diff --git a/projects/client/src/environments/environment.ts b/projects/client/src/environments/environment.ts new file mode 100644 index 0000000..811b876 --- /dev/null +++ b/projects/client/src/environments/environment.ts @@ -0,0 +1,19 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false, + clientVersion: "1.0.0", + clientType: "web", + host: "http://47.109.27.8", +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/projects/client/src/favicon.ico b/projects/client/src/favicon.ico new file mode 100644 index 0000000..b25db3a Binary files /dev/null and b/projects/client/src/favicon.ico differ diff --git a/projects/client/src/index.html b/projects/client/src/index.html new file mode 100644 index 0000000..13269e2 --- /dev/null +++ b/projects/client/src/index.html @@ -0,0 +1,69 @@ + + + + + + + + + + + + + +
+
+
+ +
+

+ 加载中... +

+
+
+ + + + + + + \ No newline at end of file diff --git a/projects/client/src/main.ts b/projects/client/src/main.ts new file mode 100644 index 0000000..c58dc05 --- /dev/null +++ b/projects/client/src/main.ts @@ -0,0 +1,7 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/projects/client/src/styles.less b/projects/client/src/styles.less new file mode 100644 index 0000000..962649b --- /dev/null +++ b/projects/client/src/styles.less @@ -0,0 +1,568 @@ +/* You can add global styles to this file, and also import other style files */ +@import "../../../node_modules/ng-zorro-antd/ng-zorro-antd.less"; + +@tailwind utilities; + +@import "./theme.less"; + +body { + color: #333; + font-size: 16px; + // background: var(--bg-color); +} + +ul, +li { + list-style: none; + margin: 0; + padding: 0; +} + +/* 屏幕分辨率放大为 150 */ +@media (-webkit-min-device-pixel-ratio: 1.5), +(min-resolution: 120dpi) { + html { + font-size: 10px; + } +} + +/* 屏幕分辨率放大为 125 */ +@media (-webkit-min-device-pixel-ratio: 1.25) { + html { + font-size: 12px; + } +} + +a { + color: var(--p); +} + +.txt { + color: var(--text-color); +} + +input { + caret-color: #fff; +} + +::-webkit-scrollbar { + width: 8px; + height: 8px; + background-color: transparent; +} + +::-webkit-scrollbar-track { + border-radius: 8px; + background-color: transparent; +} + +::-webkit-scrollbar-thumb { + border-radius: 8px; + background-color: var(--white-10); +} + +/*************reset antd style start*************/ + +.ant-input { + color: var(--input-color); + + &:hover { + border-color: var(--p); + } +} + +nz-input-number { + color: var(--input-color) !important; +} + +.ant-image-preview-operations { + color: var(--text-color) !important; +} + +.ant-checkbox-checked .ant-checkbox-inner { + background-color: var(--p); +} + +.ant-input-group-addon { + color: var(--text-color) !important; +} + +.ant-switch-checked .ant-switch-inner { + color: var(--primary-btn-color) !important; +} + +.ant-btn { + &-primary { + background-color: var(--p); + border-color: var(--p); + color: var(--primary-btn-color); + + &:hover, + &:focus, + &:active { + color: var(--primary-btn-color); + background-color: var(--p); + } + + + } + + + + &-background-ghost { + border-color: var(--border-color) !important; + color: var(--text-color) !important; + + &:hover, + &:focus, + &:active { + border-color: var(--border-color) !important; + } + } + + &-sm { + display: flex; + // flex-direction: column; + align-items: center; + justify-content: center; + height: 26px; + padding: 4px 16px; + } +} + +.ant-card { + background: transparent; + font-size: var(--text-base); + + &:not(.auto-h-card) { + height: 100%; + display: flex; + flex-direction: column; + + .ant-card-body { + flex: 1; + } + } + + &.has-corner { + color: #fff; + } + + &-bordered { + border-color: var(--border-color); + } + + &-head { + min-height: 36px; + padding: 0 16px; + background-color: var(--card-hd-bg-color); + color: var(--card-text-color); + border: none; + font-size: 16px; + font-weight: bold; + } + + &-body { + flex: 1; + padding: 16px; + overflow: auto; + } +} + +.ant-switch-checked .ant-switch-inner { + color: var(--black); +} + +.ant-input-group-addon { + background-color: transparent; + color: #fff; +} + +.ant-image { + &-preview-operations { + background-color: var(--white-40); + color: var(--black); + } + + &-preview { + + .ant-image-preview-switch-left, + .ant-image-preview-switch-right { + background-color: var(--white-40); + color: var(--black); + } + } +} + +.ant-modal { + &-mask { + background-color: rgba(7, 17, 27, 0.65); + backdrop-filter: blur(5px); + } + + &-confirm-title, + &-confirm-content { + color: #fff !important; + } + + &-close { + top: 7px; + right: 16px; + + &-icon { + padding: 2px; + border: 1px solid #fff; + color: #fff; + font-size: 12px; + } + } + + &-header { + background-color: var(--white-6); + // border-bottom-color: var(--border-color); + border: none; + } + + &-title { + color: #fff; + } + + &-footer { + border-top-color: rgba(255, 255, 255, 0.3); + + .ant-btn:not(.ant-btn-primary) { + background-color: transparent; + color: #fff; + } + } + + &-content { + border: 1px solid var(--corner-color); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.08) 100%); + // background-color: rgba(255, 255, 255, 0.2); + backdrop-filter: blur(5px); + color: #fff; + @border-cover-color: #777b9d; // 不能用rgba + + &::before { + content: ""; + position: absolute; + top: -1px; + bottom: -1px; + left: var(--corner-size); + width: calc(100% - var(--corner-size) * 2); + border-top: 1px solid @border-cover-color; + border-bottom: 1px solid @border-cover-color; + z-index: 0; + pointer-events: none; + } + + &::after { + content: ""; + position: absolute; + top: var(--corner-size); + right: -1px; + left: -1px; + height: calc(100% - var(--corner-size) * 2); + border-right: 1px solid @border-cover-color; + border-left: 1px solid @border-cover-color; + z-index: 0; + pointer-events: none; + } + } +} + +.ant-divider { + &-vertical { + border-left-color: var(--fade-white); + } +} + +.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled) { + background-color: var(--p); + border-color: var(--p); + color: var(--primary-btn-color) !important; + + &::before { + content: none; + } +} + +.ant-radio-button-wrapper:hover { + color: var(--text-color); +} + +.ant-radio-button-wrapper { + background-color: transparent; + color: var(--text-color); + + &:not(:last-child) { + border-right-color: transparent; + } + + &:not(:first-child)::before { + height: calc(100% - 12px); + top: 6px; + bottom: 6px; + } +} + +.ant-select { + color: var(--text-color); + + &-dropdown { + background-color: #fff; + } + + &-arrow { + color: var(--text-color); + } + + &-multiple { + .ant-select-selection-item { + color: var(--black); + } + } + + &-clear { + color: var(--text-color); + + &:hover { + color: var(--text-color); + } + + &:active { + color: var(--text-color); + } + } +} + +.ant-picker-separator, +.ant-picker-suffix { + color: var(--text-color) !important; +} + +.ant-picker-input>input { + color: var(--text-color); +} + +.ant-table { + color: var(--table-color); + + .ant-table-tbody>tr.ant-table-placeholder:hover>td { + background-color: transparent; + } + + .ant-table-thead>tr>th:not(:last-child):not(.ant-table-selection-column):not(.ant-table-row-expand-icon-cell):not([colspan])::before { + content: none; + } + + .ant-empty-description { + color: var(--text-color); + } +} + + +.ant-switch-checked { + background-color: var(--p); +} + +.ant-table-thead>tr>th { + border-bottom: none; + padding-top: 8px; + padding-bottom: 8px; + background-color: var(--card-hd-bg-color); +} + +.ant-pagination { + button { + background-color: transparent !important; + color: var(--text-color) !important; + } + + &-options-quick-jumper { + color: var(--text-color); + } + + &-prev, + &-next, + &-jump-prev, + &-jump-next { + color: var(--text-color); + } + + &-item-ellipsis { + color: var(--text-color) !important; + } + + &-item { + background-color: transparent; + border-color: var(--border-color); + color: var(--text-color); + + &:hover { + border-color: var(--border-color); + } + + a { + color: var(--text-color); + + &:hover { + color: var(--text-color); + } + } + + &-active { + background-color: var(--p); + border-color: var(--p); + + a { + color: var(--primary-btn-color) !important; + } + } + + + } +} + +.ant-picker-ranges { + display: flex; + align-items: center; + justify-content: space-between; + + button { + color: var(--text-color); + + &:hover { + color: var(--text-color); + } + } +} + +.ant-tag { + margin-right: 8px; + padding: 7px 12px; + border-radius: 2px; + background-color: var(--tag-bg); + border: none; + color: var(--tag-color); + + &-close-icon { + margin-left: 8px; + color: var(--tag-color); + font-size: 12px; + + &:hover { + color: var(--tag-color); + } + } +} + +.ant-form { + &-item-label>label { + color: var(--text-color); + } + + &-item-explain, + &-item-extra { + color: var(--desc-color); + } + + &-item-extra { + margin-top: 8px; + } +} + +.ant-checkbox { + &-inner { + background-color: transparent; + } +} + +.ant-tree { + &-node-content-wrapper { + // padding: 8px 12px !important; + color: #fff !important; + } +} + +.ant-tooltip { + &-inner { + background-color: #fff; + color: var(--black); + } + + .ant-tooltip-arrow-content::before { + background: #fff; + } +} + +/*************reset antd style end*************/ + +.text-label { + color: var(--purple); +} + +.dec-corner { + @corner-size: var(--corner-size); + + div { + position: absolute; + display: block; + width: @corner-size; + height: @corner-size; + z-index: 10; + + &::before, + &::after { + content: ""; + position: absolute; + background-color: var(--corner-color); + transform-origin: top left; + } + + &::before { + width: 100%; + height: 1px; + } + + &::after { + width: 1px; + height: 100%; + } + + &:nth-child(even) { + &::after { + right: 0; + } + } + + &:nth-child(1) { + top: 0; + left: 0; + } + + &:nth-child(2) { + top: 0; + right: 0; + } + + &:nth-child(3) { + bottom: 0; + left: 0; + + &::before { + bottom: 0; + } + } + + &:nth-child(4) { + bottom: 0; + right: 0; + + &::before { + bottom: 0; + } + } + } +} \ No newline at end of file diff --git a/projects/client/src/theme.less b/projects/client/src/theme.less new file mode 100644 index 0000000..cde47bc --- /dev/null +++ b/projects/client/src/theme.less @@ -0,0 +1,207 @@ +:root { + + + // --primary: rgb(94, 183, 232); + --primary: rgb(94, 183, 232); + + + --p: var(--primary); + + --p-rgb: 0, 57, 144; + + --primary-10: rgba(var(--p-rgb), 0.1); + + --primary-20: rgba(var(--p-rgb), 0.2); + + // 背景色 + --bg-color: #003990; + + // 边框色 #e8e8e8 + --border-color: #e8e8e8; + // --border-color: rgba(255, 255, 255, 0.2); + + + + // 顶部菜单背景 + --nav-bg: #e8e8e8; + + //文字颜色 + --text-color: #333; + + --thead-color: var(--text-color); + + --table-color: var(--text-color); + + --input-color: var(--text-color); + + // 标题颜色 + --title-color: var(--p); + + --desc-color: #898989; + + --thead-bg: var(--black-10); + + --tag-bg: #d1e7f4; + + --tag-color: #008cd6; + + --primary-btn-color: #fff; + + + --card-text-color: #fff; + + --card-text-color: #333; + + + --card-hd-bg-color: #e0e7f1; + + --corner-color: #003990; + + + + // ------------ + + + + + // --theme: #003990; + + // --theme-rgb: 0, 57, 144; + + // --theme-30: rgba(var(--theme-rgb), 0.3); + + // --theme-20: rgba(var(--theme-rgb), 0.2); + + // --theme-10: rgba(var(--theme-rgb), 0.1); + + // --theme-6: rgba(var(--theme-rgb), 0.06); + + + --bg-jianbian: linear-gradient(90deg, #003990 0%, #008cd6 100%); + + --blue-1: #0050a4; + + --blue-2: #008cd6; + + --blue-3: #5eb7e8; + + --blue3-rgb: 94, 183, 232; + + --blue3-10: rgba(var(--blue3-rgb), 0.1); + + --blue3-20: rgba(var(--blue3-rgb), 0.2); + + --blue-4: #9fd9f6; + + --green-1: #009944; + + --green-2: #a5d4ad; + + --red-1: #e60012; + + --red-2: #c8161d; + + --yellow: #f6ad3c; + + --dark-blue: #252166; + + --purple: #80abed; + + --black: #2c2c35; + + --black-10: rgba(0, 0, 0, 0.1); + + --gray-1: #898989; + --gray-2: #b2b3b3; + --gray-3: #cfd0d0; + --gray-4: #d9dada; + --gray-5: #e2e3e3; + --gray-6: #f7f8f8; + + --white: #ffffff; + + --white-6: rgba(255, 255, 255, 0.06); + --white-10: rgba(255, 255, 255, 0.1); + --white-20: rgba(255, 255, 255, 0.2); + --white-30: rgba(255, 255, 255, 0.3); + --white-40: rgba(255, 255, 255, 0.4); + --white-70: rgba(255, 255, 255, 0.7); + + --text-base: 16px; + + --cornerColor: red; + + + + --page-corner-bg: var(--white-30); + + --fade-white: rgba(255, 255, 255, 0.6); + + --corner-size: 6px; + + + + --btn-primary-hover-bg: var(--blue-2); + --btn-ghost-hover-border-color: var(--blue-3); +} + +@border-color-base: var(--border-color); + +// @component-background: transparent; + +@input-bg: transparent; + +@select-background: transparent; + +@picker-bg: transparent; + +@height-base: 36px; + +@primary-color: #003990; + + + +@btn-padding-horizontal-base: 16px; + +@card-head-padding: 6px; + +@radio-button-bg: #1e3571; + +@radio-button-color: #fff; + +@radio-solid-checked-color: #fff; + +@dropdown-menu-bg: #fff; + +@table-bg: transparent; + +@table-header-bg: var(--white-10); + +@table-header-color: var(--table-color); + +@table-row-hover-bg: transparent; + +// @table-border-color: var(--border-color); +@table-border-color: rgba(255, 255, 255, 0.2); + +@table-padding-vertical: 12px; + +@modal-header-padding: 7px 16px; + +@modal-header-close-size: 16px; + +@modal-body-padding: 16px; + +@tree-bg: transparent; + +@tree-title-height: 40px; + +.c-red { + color: var(--red-1); +} + +.c-green { + color: var(--green-1); +} + +// @card-head-padding-sm: 10px; \ No newline at end of file diff --git a/projects/client/tsconfig.app.json b/projects/client/tsconfig.app.json new file mode 100644 index 0000000..e4e0762 --- /dev/null +++ b/projects/client/tsconfig.app.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/projects/client/tsconfig.spec.json b/projects/client/tsconfig.spec.json new file mode 100644 index 0000000..4ac6c85 --- /dev/null +++ b/projects/client/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} \ No newline at end of file diff --git a/projects/manage/proxy.conf.json b/projects/manage/proxy.conf.json new file mode 100644 index 0000000..4b1b430 --- /dev/null +++ b/projects/manage/proxy.conf.json @@ -0,0 +1,15 @@ +{ + "/api": { + "target": "http://47.109.27.8:8081", + "secure": false + }, + "/record": { + "target": "http://47.109.27.8", + "secure": false + }, + "/websocket": { + "target": "http://47.109.27.8:8081", + "secure": false, + "ws": true + } +} diff --git a/projects/manage/src/app/app-routing.module.ts b/projects/manage/src/app/app-routing.module.ts new file mode 100644 index 0000000..f191ace --- /dev/null +++ b/projects/manage/src/app/app-routing.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from "@angular/core"; +import { Routes, RouterModule } from "@angular/router"; +import { authGuard } from "./core/gaurd/auth.guard"; + +const routes: Routes = [ + { + path: "auth", + loadChildren: () => import("./feature/auth/auth.module").then((m) => m.AuthModule), + }, + { + path: "manage", + loadChildren: () => import("./feature/manage/manage.module").then((m) => m.ManageModule), + canActivateChild: [authGuard], + }, + + { + path: "**", + redirectTo: "manage", + }, +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule], +}) +export class AppRoutingModule {} diff --git a/projects/manage/src/app/app.component.html b/projects/manage/src/app/app.component.html new file mode 100644 index 0000000..90c6b64 --- /dev/null +++ b/projects/manage/src/app/app.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/manage/src/app/app.component.less b/projects/manage/src/app/app.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/app.component.ts b/projects/manage/src/app/app.component.ts new file mode 100644 index 0000000..6870cb1 --- /dev/null +++ b/projects/manage/src/app/app.component.ts @@ -0,0 +1,35 @@ +import { Component } from "@angular/core"; +import { AuthInterface } from "@cdk/types"; +import { NgxPermissionsService } from "ngx-permissions"; + +@Component({ + selector: "app-root", + templateUrl: "./app.component.html", + styleUrls: ["./app.component.less"], +}) +export class AppComponent { + constructor(private permissionsService: NgxPermissionsService) {} + + isCollapsed = false; + + ngOnInit() { + // const auth = localStorage.getItem("auth"); + // if (auth) { + // try { + // const authData = JSON.parse(auth) as AuthInterface; + // if (Array.isArray(authData.permissionList)) { + // const permissionList = authData.permissionList; + // const permissions = permissionList.reduce((a, c) => { + // if (c.scope === 1 && c.value === "true") { + // return a.concat(c.roleId); + // } + // return a; + // }, [] as string[]); + // this.permissionsService.loadPermissions(permissions); + // } + // } catch (error) {} + // } + } + + async getUserInfo(id: number) {} +} diff --git a/projects/manage/src/app/app.module.ts b/projects/manage/src/app/app.module.ts new file mode 100644 index 0000000..1d67ee5 --- /dev/null +++ b/projects/manage/src/app/app.module.ts @@ -0,0 +1,46 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA, APP_INITIALIZER } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; + +import { AppRoutingModule } from "./app-routing.module"; +import { AppComponent } from "./app.component"; +import { NZ_I18N } from "ng-zorro-antd/i18n"; +import { zh_CN } from "ng-zorro-antd/i18n"; +import { HashLocationStrategy, LocationStrategy, registerLocaleData } from "@angular/common"; +import zh from "@angular/common/locales/zh"; + +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; + +import { SharedModule } from "./shared/shared.module"; +import { NgxPermissionsModule, NgxPermissionsService } from "ngx-permissions"; +import { AuthInterface, DecModule } from "@cdk/public-api"; +import { environment } from "@manage/environments/environment"; +import { HttpClient, HttpClientModule } from "@angular/common/http"; + +registerLocaleData(zh); + +@NgModule({ + declarations: [AppComponent], + imports: [ + BrowserModule, + BrowserAnimationsModule, + HttpClientModule, + // SharedModule, + AppRoutingModule, + DecModule.forRoot({ + environment, + localStroageKey: "manage_token", + loginUrl: "/auth/login", + }), + NgxPermissionsModule.forRoot(), + ], + providers: [ + { provide: NZ_I18N, useValue: zh_CN }, + { + provide: LocationStrategy, + useClass: HashLocationStrategy, + }, + ], + bootstrap: [AppComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], +}) +export class AppModule {} diff --git a/projects/manage/src/app/core/gaurd/auth.guard.ts b/projects/manage/src/app/core/gaurd/auth.guard.ts new file mode 100644 index 0000000..a01d0fb --- /dev/null +++ b/projects/manage/src/app/core/gaurd/auth.guard.ts @@ -0,0 +1,50 @@ +import { inject } from "@angular/core"; +import { Router } from "@angular/router"; +import { AuthInterface, decConfigToken } from "@cdk/public-api"; +import { map } from "rxjs"; +import { ManageApiService } from "../services"; +import { NgxPermissionsService } from "ngx-permissions"; + +export const authGuard = () => { + const api = inject(ManageApiService); + const router = inject(Router); + const decConfig = inject(decConfigToken); + const token = localStorage.getItem(decConfig.localStroageKey); + + if (!token) { + router.navigate([decConfig.loginUrl]); + return false; + } + + return api.getAllPoint().pipe( + map((res) => { + if (res) { + return true; + } else { + router.navigate([decConfig.loginUrl]); + return false; + } + }) + ); + + // const permissionsService = inject(NgxPermissionsService); + // const auth = localStorage.getItem("auth"); + // if (auth) { + // try { + // const authData = JSON.parse(auth) as AuthInterface; + + // if (Array.isArray(authData.permissionList)) { + // const permissionList = authData.permissionList; + // const permissions = permissionList.reduce((a, c) => { + // if (c.scope === 1 && c.value === "true") { + // return a.concat(c.roleId); + // } + // return a; + // }, [] as string[]); + // permissionsService.loadPermissions(permissions); + // console.log("this.permissionsService.getPermissions()", permissionsService.getPermissions()); + // } + // } catch (error) {} + // } + return true; +}; diff --git a/projects/manage/src/app/core/gaurd/permisson.guard.ts b/projects/manage/src/app/core/gaurd/permisson.guard.ts new file mode 100644 index 0000000..5781d5b --- /dev/null +++ b/projects/manage/src/app/core/gaurd/permisson.guard.ts @@ -0,0 +1,65 @@ +import { inject } from "@angular/core"; +import { + ActivatedRoute, + ActivatedRouteSnapshot, + CanActivateChildFn, + CanActivateFn, + Route, + Router, + RouterStateSnapshot, +} from "@angular/router"; +import { AuthInterface, decConfigToken } from "@cdk/public-api"; +import { map } from "rxjs"; +import { ManageApiService } from "../services"; +import { NgxPermissionsService } from "ngx-permissions"; + +export const PermissionLoadGuard: CanActivateFn = async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const router = inject(Router); + const permissionsService = inject(NgxPermissionsService); + + const auth = localStorage.getItem("auth"); + const children = route.parent!.routeConfig!.children; + let availableRedirect: Route = children?.find((f) => f.path === "forbidden")!; + if (auth) { + try { + const authData = JSON.parse(auth) as AuthInterface; + if (Array.isArray(authData.permissionList)) { + const permissionList = authData.permissionList; + const permissions = permissionList.reduce((a, c) => { + if (c.scope === 1 && c.value === "true") { + return a.concat(c.roleId); + } + return a; + }, [] as string[]); + permissionsService.loadPermissions(permissions); + } + } catch (error) {} + } + return true; +}; +export const PermissionGuard: CanActivateFn = async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + const router = inject(Router); + const permissionsService = inject(NgxPermissionsService); + console.log("permissionsService.getPermissions()", state); + const currentOnly = route.data["permissions"]?.only; + if (Array.isArray(currentOnly)) { + const allow = await permissionsService.hasPermission(currentOnly); + if (state.url === "/manage/station" && !allow) { + const routers = route.parent?.routeConfig?.children; + if (Array.isArray(routers)) { + for (let child of routers) { + const only = child.data?.["permissions"]?.only; + if (Array.isArray(only) && (await permissionsService.hasPermission(only))) { + router.navigate(["/manage/", child.path]); + + break; + } + console.log("child", child); + } + } + // router + } + return allow; + } + return true; +}; diff --git a/projects/manage/src/app/core/services/auth-api.service.ts b/projects/manage/src/app/core/services/auth-api.service.ts new file mode 100644 index 0000000..755ac9e --- /dev/null +++ b/projects/manage/src/app/core/services/auth-api.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthApiService { + + constructor() { } +} diff --git a/projects/manage/src/app/core/services/index.ts b/projects/manage/src/app/core/services/index.ts new file mode 100644 index 0000000..0fbe332 --- /dev/null +++ b/projects/manage/src/app/core/services/index.ts @@ -0,0 +1,2 @@ +export * from "./auth-api.service"; +export * from "./manage-api.service"; diff --git a/projects/manage/src/app/core/services/manage-api.service.ts b/projects/manage/src/app/core/services/manage-api.service.ts new file mode 100644 index 0000000..9aa79fd --- /dev/null +++ b/projects/manage/src/app/core/services/manage-api.service.ts @@ -0,0 +1,330 @@ +import { map, of, tap } from "rxjs"; +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; +import { AnyObject, Augmented, DecText, PageResult, ResponseType } from "@cdk/types"; +import { OptionItemInterface, UserDTO, UserRoleDTO } from "@manage/dtos"; +import { PermissionItmeInterface } from "@manage/app/feature/manage/pages"; + +@Injectable({ + providedIn: "root", +}) +export class ManageApiService { + constructor(private http: HttpClient) {} + + getRoleList() { + return this.http.post>("/api/user/selectRole", null); + } + + saveRole(data: Partial) { + const url = data["roleId"] ? "/api/user/updateRole" : "/api/user/addRole"; + return this.http.post(url, data); + } + + deleteRole(roleId: DecText) { + return this.http.post("/api/user/deleteRole", { roleId }); + } + + deleteUser(uid: DecText) { + return this.http.post("/api/user/deleteUser", { uid }); + } + + saveUser(data: AnyObject) { + const url = data["id"] ? "/api/user/updateUser" : "/api/user/addUser"; + return this.http.post(url, data); + } + + getUserPage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post>("/api/user/selectUser", q).pipe( + map((t) => { + return { + total: t.body.length, + content: t.body, + }; + }) + ); + } + + uploadLogo(f: FormData) { + return this.http.post("/api/config/upload", f); + } + + getSystemInfo() { + return this.http.post("/api/config/selectSystemInfo", {}); + } + + getSystemThemes() { + return this.http.post>("/api/config/selectTheme", {}); + } + + deleteOneofTheme(themeId: string) { + return this.http.post("/api/config/deleteTheme", { themeId }); + } + + saveSyetemTheme(data: {}) { + return this.http.post("/api/config/updateTheme", data); + } + + saveSyetemInfo(data: {}) { + return this.http.post("/api/config/updateSystemInfo", data); + } + + deleteOneofSystemInfo(systemInfoId: string) { + return this.http.post("/api/config/deleteSystemInfo", { systemInfoId }); + } + + getStationPage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post("/api/powerStation/select", q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.data, + }; + }) + ); + } + + getRolePermissions(roleId: string) { + return this.http.post>("/api/user/selectPermission", { roleId }); + } + + updateRolePermission(roleId: string, permissionList: AnyObject[]) { + return this.http.post("/api/user/updatePermission", { roleId, permissionList }); + } + + getAllStation() { + return this.http.post>("/api/powerStation/dropDownBox", {}).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + ...i, + label: i["powerStationName"], + value: i["powerStationId"], + })); + } + return []; + }) + ); + } + + saveStation(data: AnyObject) { + const url = data["powerStationId"] ? "/api/powerStation/update" : "/api/powerStation/add"; + return this.http.post(url, data); + } + + delStation(data: AnyObject) { + return this.http.post("/api/powerStation/del", data); + } + + getGroupPage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post("/api/motorGroup/select", q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.data, + }; + }) + ); + } + + getAllGroup() { + return this.http.post("/api/motorGroup/dropDownBox", {}).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + ...i, + label: i["motorGroupName"], + value: i["motorGroupId"], + })); + } + return []; + }) + ); + } + + saveGroup(data: AnyObject) { + const url = data["motorGroupId"] ? "/api/motorGroup/update" : "/api/motorGroup/add"; + return this.http.post(url, data); + } + + delGroup(data: AnyObject) { + return this.http.post("/api/motorGroup/del", data); + } + + getPointPage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post("/api/point/select", q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.data, + }; + }) + ); + } + + getAllPoint(powerStationId?: string) { + return this.http.post("/api/point/dropDownBox", { powerStationId }).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + ...i, + label: i["name"], + value: i["pointId"], + })); + } + return []; + }) + ); + } + + savePoint(data: AnyObject) { + const url = data["pointId"] ? "/api/point/update" : "/api/point/add"; + return this.http.post(url, data); + } + + delPoint(data: AnyObject) { + return this.http.post("/api/point/del", data); + } + + updatePointDetectStatus(data: AnyObject) { + return this.http.post("/api/point/updateDetect", data); + } + + getAlgorithmPage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post("/api/algorithm/select", q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.data, + }; + }) + ); + } + + getAlgorithmSource() { + return this.http.post("/api/algorithm/source", {}).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + label: i, + value: i, + })); + } + return []; + }) + ); + } + + getAlgorithmNameBySource(source: string) { + return this.http.post("/api/algorithm/name", { source }).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + label: i, + value: i, + })); + } + return []; + }) + ); + } + + uploadAlgorithmFile(data: FormData) { + return this.http.post("/api/algorithm/upload", data); + } + + saveAlgorithm(data: AnyObject) { + const url = data["algorithmId"] ? "/api/algorithm/update" : "/api/algorithm/add"; + return this.http.post(url, data); + } + + getAlgorithmPoints(data: AnyObject) { + return this.http.post("/api/algorithm/selectPoints", data); + } + + getAlgorithmDetail(data: AnyObject) { + return this.http.post("/api/algorithm/selectDetail", data); + } + + delAlgorithm(data: AnyObject) { + return this.http.post("/api/algorithm/del", data); + } + + getDevicePage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post("/api/device/query", q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.data, + }; + }) + ); + } + + getTemperatureDevicePage(page: {}, query: {}) { + const q = Object.assign({}, page, query); + return this.http.post("/api/device/selectTempSensor", q).pipe( + map((t) => { + return { + ...t.body, + content: t.body.data, + }; + }) + ); + } + + getTemperatureDeviceTypes() { + return this.http.post("/api/device/getSensorTypes", {}).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + label: i["type"], + value: i["typeId"], + })); + } + return []; + }) + ); + } + + updateDeviceStatus(data: AnyObject) { + return this.http.post("/api/device/deactivate", data); + } + + deleteDevice(data: AnyObject) { + return this.http.post("/api/device/del", data); + } + + saveDevice(data: AnyObject) { + const url = data["deviceId"] ? "/api/device/update" : "/api/device/add"; + return this.http.post(url, data); + } + + getDeviceTypes() { + return this.http.post("/api/device/getTypes", {}).pipe( + map((res) => { + if (Array.isArray(res.body)) { + return res.body.map((i) => ({ + label: i["vender"], + value: i["venderId"], + })); + } + return []; + }) + ); + } + + saveTemperatureDevice(data: AnyObject) { + const url = data["deviceId"] ? "/api/device/updateTempSensor" : "/api/device/addTempSensor"; + return this.http.post(url, data); + } + + deleteTemperatureDevice(data: AnyObject) { + return this.http.post("/api/device/deleteTempSensor", data); + } +} diff --git a/projects/manage/src/app/feature/auth/auth-routing.module.ts b/projects/manage/src/app/feature/auth/auth-routing.module.ts new file mode 100644 index 0000000..80cd35a --- /dev/null +++ b/projects/manage/src/app/feature/auth/auth-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; +import { LoginComponent } from "./pages"; + +const routes: Routes = [ + { + path: "login", + component: LoginComponent, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class AuthRoutingModule {} diff --git a/projects/manage/src/app/feature/auth/auth.module.ts b/projects/manage/src/app/feature/auth/auth.module.ts new file mode 100644 index 0000000..c899f84 --- /dev/null +++ b/projects/manage/src/app/feature/auth/auth.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { SharedModule } from "@manage/app/shared/shared.module"; +import { LoginComponent } from "./pages"; +import { AuthRoutingModule } from "./auth-routing.module"; + +@NgModule({ + declarations: [LoginComponent], + imports: [AuthRoutingModule, SharedModule], +}) +export class AuthModule {} diff --git a/projects/manage/src/app/feature/auth/pages/index.ts b/projects/manage/src/app/feature/auth/pages/index.ts new file mode 100644 index 0000000..97961b0 --- /dev/null +++ b/projects/manage/src/app/feature/auth/pages/index.ts @@ -0,0 +1 @@ +export * from "./login/login.component"; diff --git a/projects/manage/src/app/feature/auth/pages/login/login.component.html b/projects/manage/src/app/feature/auth/pages/login/login.component.html new file mode 100644 index 0000000..daf1f0e --- /dev/null +++ b/projects/manage/src/app/feature/auth/pages/login/login.component.html @@ -0,0 +1,59 @@ +
+ +
+ + +
+ +
+
\ No newline at end of file diff --git a/projects/manage/src/app/feature/auth/pages/login/login.component.less b/projects/manage/src/app/feature/auth/pages/login/login.component.less new file mode 100644 index 0000000..9126753 --- /dev/null +++ b/projects/manage/src/app/feature/auth/pages/login/login.component.less @@ -0,0 +1,49 @@ +:host { + display: block; + width: 100vw; + height: 100vh; + position: relative; + background-image: url(../../../../../assets/imgs/bg.jpg); + background-repeat: no-repeat; + background-size: cover; + &::after { + content: ""; + position: absolute; + inset: 0; + background-color: rgba(0, 0, 0, 0.3); + } +} + +.login { + position: relative; + z-index: 1; + h1 { + margin-bottom: 24px; + font-size: 24px; + font-weight: 400; + color: #fff; + } + + .logo { + display: inline-block; + height: 36px; + } + + .form { + width: 400px; + margin: 0 auto; + background-color: #fff; + border-radius: 6px; + } + + p { + font-size: 16px; + line-height: 24px; + letter-spacing: 0.23em; + text-shadow: 0px 8px 20px rgba(0, 0, 0, 0.1); + } + + .btn { + margin-top: 16px; + } +} diff --git a/projects/manage/src/app/feature/auth/pages/login/login.component.ts b/projects/manage/src/app/feature/auth/pages/login/login.component.ts new file mode 100644 index 0000000..3f2e2a1 --- /dev/null +++ b/projects/manage/src/app/feature/auth/pages/login/login.component.ts @@ -0,0 +1,48 @@ +import { Router } from "@angular/router"; +import { Component, Inject, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Utils } from "@cdk/utils"; +import { DecValidators } from "@cdk/validators"; +import { PUBLIC_PATH } from "@cdk/dec-module/base-href"; +import { AuthService } from "@client/app/core/services"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { finalize, lastValueFrom, tap } from "rxjs"; + +@Component({ + selector: "app-login", + templateUrl: "./login.component.html", + styleUrls: ["./login.component.less"], +}) +export class LoginComponent implements OnInit { + constructor( + @Inject(PUBLIC_PATH) public baseHref: string, + private msg: NzMessageService, + private api: AuthService, + private router: Router + ) {} + + public loginForm = new FormGroup({ + uid: new FormControl("", [DecValidators.required("请输入账户")]), + password: new FormControl("", [DecValidators.required("请输入密码")]), + }); + + public loading: boolean = false; + + ngOnInit(): void {} + + async onLogin() { + if (Utils.validateFormGroup(this.loginForm)) { + const { value } = this.loginForm; + this.loading = true; + const res = await lastValueFrom( + this.api.login(value).pipe( + finalize(() => { + this.loading = false; + }) + ) + ); + this.msg.success(res.desc); + this.router.navigate(["/"]); + } + } +} diff --git a/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.html b/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.html new file mode 100644 index 0000000..f2f6faa --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.html @@ -0,0 +1,67 @@ +
+ + + 电站 + + + + + + + + + 机组 + + + + + + + + + + + + + + + + +
+
+ + + + + + 机组/监测点 + 所属电站 + + + + + + {{ data['motorGroup'] }}/ {{data['point']}} + {{ data['powerStation'] }} + + + +
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.less b/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.ts b/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.ts new file mode 100644 index 0000000..51448e6 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/algorithm-point-select/algorithm-point-select.component.ts @@ -0,0 +1,118 @@ +import { Component, inject, OnInit } from "@angular/core"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { NZ_MODAL_DATA } from "ng-zorro-antd/modal"; + +@Component({ + selector: "app-algorithm-point-select", + templateUrl: "./algorithm-point-select.component.html", + styleUrls: ["./algorithm-point-select.component.less"], +}) +export class AlgorithmPointSelectComponent implements OnInit { + constructor(private api: ManageApiService) {} + + query = { + powerStationId: "", + motorGroupId: "", + }; + + props = inject(NZ_MODAL_DATA); + + currentGroups = []; + + checked = false; + + loading = false; + + indeterminate = false; + + listOfData: readonly AnyObject[] = []; + + listOfCurrentPageData: readonly AnyObject[] = []; + + setOfCheckedId = new Set(); + + setOfDataFromServer: AnyObject[] = []; + + public get selectedPoint(): AnyObject[] { + return this.setOfDataFromServer.filter((f) => this.setOfCheckedId.has(f["id"])); + } + + ngOnInit(): void { + this.props["val"]?.forEach((p: AnyObject) => { + this.setOfCheckedId.add(p["pointId"]); + }); + this.onSearch(); + } + + onStationChange(powerStationId: string) { + this.currentGroups = this.props["groups"].filter((f: AnyObject) => f["powerStationId"] === powerStationId); + } + + onSearch() { + this.api + .getAlgorithmPoints({ + algorithmId: this.props["algorithmId"] ?? "", + ...this.query, + }) + .subscribe((res) => { + if (Array.isArray(res.body)) { + this.listOfData = res.body.map((i) => { + return { + ...i, + id: i.pointId, + disabled: i.flag === 2, + }; + }); + } else { + this.listOfData = []; + } + this.listOfData.forEach((i) => { + if (!this.setOfDataFromServer.some((s) => s["id"] === i["id"])) { + this.setOfDataFromServer.push(i); + } + }); + // this.setOfCheckedId.clear(); + this.refreshCheckedStatus(); + }); + } + + onReset() { + this.query = { + powerStationId: "", + motorGroupId: "", + }; + this.onSearch(); + } + + updateCheckedSet(id: number, checked: boolean): void { + if (checked) { + this.setOfCheckedId.add(id); + } else { + this.setOfCheckedId.delete(id); + } + } + + onCurrentPageDataChange(listOfCurrentPageData: readonly AnyObject[]): void { + this.listOfCurrentPageData = listOfCurrentPageData; + this.refreshCheckedStatus(); + } + + refreshCheckedStatus(): void { + const listOfEnabledData = this.listOfCurrentPageData.filter(({ disabled }) => !disabled); + this.checked = listOfEnabledData?.length > 0 && listOfEnabledData.every(({ id }) => this.setOfCheckedId.has(id)); + this.indeterminate = listOfEnabledData.some(({ id }) => this.setOfCheckedId.has(id)) && !this.checked; + } + + onItemChecked(id: number, checked: boolean): void { + this.updateCheckedSet(id, checked); + this.refreshCheckedStatus(); + } + + onAllChecked(checked: boolean): void { + this.listOfCurrentPageData + .filter(({ disabled }) => !disabled) + .forEach(({ id }) => this.updateCheckedSet(id, checked)); + this.refreshCheckedStatus(); + } +} diff --git a/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.html b/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.html new file mode 100644 index 0000000..142ff36 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.html @@ -0,0 +1,91 @@ +
+ + + 电站 + + + + + + + + + + 机组/检测点 + + + + + + + + + + 相机型号 + + + + + + + + + + 相机SN码 + + + + + + + + 相机名称 + + + + + + + + 帧率 + + + + + + + + + + 曝光时间 + + + + + + + + + + PLC-IP + + + + + + + + PLC延时参数 + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.less b/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.ts b/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.ts new file mode 100644 index 0000000..139c29c --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/camera-form/camera-form.component.ts @@ -0,0 +1,70 @@ +import { Component, Input } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { DecValidators } from "@cdk/public-api"; +import { Utils } from "@cdk/utils"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; + +@Component({ + selector: "app-camera-form", + templateUrl: "./camera-form.component.html", + styleUrls: ["./camera-form.component.less"], +}) +export class CameraFormComponent { + constructor(private api: ManageApiService) {} + + @Input() public value?: any; + + @Input() public deviceTypes: OptionItemInterface[] = []; + + @Input() public stations: OptionItemInterface[] = []; + + groupAndPoint: OptionItemInterface[] = []; + + public formGroup = new FormGroup({ + deviceId: new FormControl(), + powerStationId: new FormControl("", [DecValidators.required("请选择电站")]), + motorGroupId: new FormControl(""), + pointId: new FormControl("", [DecValidators.required("请选择机组/检测点")]), + name: new FormControl("", [DecValidators.required("请输入相机名称"), DecValidators.maxLength(50)]), + vender: new FormControl("", [DecValidators.required("请输入相机型号")]), + sn: new FormControl("", [DecValidators.required("请输入相机SN码"), DecValidators.maxLength(50)]), + fps: new FormControl("", [DecValidators.required("请输入帧率"), DecValidators.maxLength(50)]), + exposureTime: new FormControl("", [DecValidators.required("请输入曝光时间"), DecValidators.maxLength(50)]), + plcIp: new FormControl("", [DecValidators.required("请输入PLC-IP"), DecValidators.maxLength(50)]), + plcDelay: new FormControl("", [DecValidators.required("请输入PLC延时参数"), DecValidators.maxLength(50)]), + }); + + public ngOnInit(): void { + this.formGroup.get("powerStationId")?.valueChanges.subscribe((sid) => { + this.formGroup.patchValue({ + pointId: null, + motorGroupId: null, + }); + if (sid) { + this.api.getAllPoint(sid).subscribe((res) => { + this.groupAndPoint = res; + }); + } + }); + // this.formGroup.get("pointId")?.valueChanges.subscribe((pid) => { + // const item = this.groupAndPoint.find((f) => f.value === pid); + // this.formGroup.get("motorGroupId")?.setValue(item?.["motorGroupId"]); + // }); + if (this.value) { + this.formGroup.patchValue(this.value); + } + } + + public getValues() { + let values = null; + if (Utils.validateFormGroup(this.formGroup)) { + const { pointId } = this.formGroup.value; + const item = this.groupAndPoint.find((f) => f.value === pointId); + + this.formGroup.value["motorGroupId"] = item!["motorGroupId"]; + values = this.formGroup.value; + } + return values; + } +} diff --git a/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.html b/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.html new file mode 100644 index 0000000..ba41001 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.html @@ -0,0 +1,19 @@ +
+
+
+ +
+ +
+ + {{_color}} + +
+ + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.less b/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.less new file mode 100644 index 0000000..8d76c9e --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.less @@ -0,0 +1,20 @@ +:host { + display: block; + width: 100%; + height: 100%; +} +.form-control { + padding: 4px 12px; + border-radius: 4px; + border: 1px solid var(--border-color); +} + +.trigger { + padding: 4px; + border: 1px solid var(--border-color); + cursor: pointer; +} + +.color-picker { + box-shadow: none; +} diff --git a/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.ts b/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.ts new file mode 100644 index 0000000..a0e2815 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/color-picker/color-picker.component.ts @@ -0,0 +1,60 @@ +import { Component, EventEmitter, HostBinding, HostListener, Input, OnInit, Output } from "@angular/core"; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms"; +import { Color, ColorPickerControl } from "@iplab/ngx-color-picker"; + +@Component({ + selector: "app-color-picker", + templateUrl: "./color-picker.component.html", + styleUrls: ["./color-picker.component.less"], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: ColorPickerComponent, + }, + ], +}) +export class ColorPickerComponent implements OnInit, ControlValueAccessor { + constructor() {} + + @Input() mode: "simple" | "elaborate" = "elaborate"; + + @Input() public set color(color: string) { + this.colorControl.setValueFrom(color); + this._color = color; + } + + @Output() public colorChange: EventEmitter = new EventEmitter(); + + public colorControl = new ColorPickerControl(); + + public _color: string = " "; + + public ngOnInit() { + this.colorControl.valueChanges.subscribe((value: Color) => { + const color = value.toRgbaString(); + this._color = color; + this.onChange(color); + this.colorChange.emit(color); + }); + } + + onChange(v: string) {} + + onTouch(v: string) {} + + writeValue(obj: string): void { + this.colorControl.setValueFrom(obj); + this._color = obj; + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.onTouch = fn; + } + + setDisabledState?(isDisabled: boolean): void {} +} diff --git a/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.html b/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.html new file mode 100644 index 0000000..a753299 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.html @@ -0,0 +1,4 @@ +
+ +

你没有此页面的访问权限。

+
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.less b/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.ts b/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.ts new file mode 100644 index 0000000..3bdfe40 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/forbidden/forbidden.component.ts @@ -0,0 +1,14 @@ +import { ActivatedRoute, Router } from "@angular/router"; +import { Component, OnInit } from "@angular/core"; +import { NgxPermissionsService } from "ngx-permissions"; + +@Component({ + selector: "app-forbidden", + templateUrl: "./forbidden.component.html", + styleUrls: ["./forbidden.component.less"], +}) +export class ForbiddenComponent implements OnInit { + constructor(private perm: NgxPermissionsService, private router: Router, private route: ActivatedRoute) {} + + async ngOnInit() {} +} diff --git a/projects/manage/src/app/feature/manage/components/home/home.component.html b/projects/manage/src/app/feature/manage/components/home/home.component.html new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/home/home.component.less b/projects/manage/src/app/feature/manage/components/home/home.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/home/home.component.ts b/projects/manage/src/app/feature/manage/components/home/home.component.ts new file mode 100644 index 0000000..ed7d59e --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/home/home.component.ts @@ -0,0 +1,30 @@ +import { Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { NgxPermissionsService } from "ngx-permissions"; + +@Component({ + selector: "app-home", + templateUrl: "./home.component.html", + styleUrls: ["./home.component.less"], +}) +export class HomeComponent { + constructor(private perm: NgxPermissionsService, private router: Router, private route: ActivatedRoute) {} + + async ngOnInit() { + const children = this.route.parent?.routeConfig?.children; + if (Array.isArray(children)) { + for (const child of children) { + if (child.path === this.route.routeConfig?.path) { + continue; + } + const only = child.data?.["permissions"]?.only; + if (Array.isArray(only)) { + if (await this.perm.hasPermission(only)) { + this.router.navigate(["/manage", child.path]); + break; + } + } + } + } + } +} diff --git a/projects/manage/src/app/feature/manage/components/index.ts b/projects/manage/src/app/feature/manage/components/index.ts new file mode 100644 index 0000000..70422c5 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/index.ts @@ -0,0 +1,15 @@ +export * from "./layout/layout.component"; +export * from "./page/page.component"; +export * from "./station-form/station-form.component"; +export * from "./machine-form/machine-form.component"; +export * from "./point-form/point-form.component"; +export * from "./system-user-layout/system-user-layout.component"; +export * from "./user-form/user-form.component"; +export * from "./camera-form/camera-form.component"; +export * from "./temperature-form/temperature-form.component"; +export * from "./color-picker/color-picker.component"; +export * from "./algorithm-point-select/algorithm-point-select.component"; + +export * from "./forbidden/forbidden.component"; +export * from "./notfound/notfound.component"; +export * from "./home/home.component"; diff --git a/projects/manage/src/app/feature/manage/components/layout/layout.component.html b/projects/manage/src/app/feature/manage/components/layout/layout.component.html new file mode 100644 index 0000000..f9142ef --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/layout/layout.component.html @@ -0,0 +1,138 @@ + + +
+ +
+ +
+
+
+ + +
+ + + +
+ + + + + + +
    +
  • 退出登录
  • +
+
+
+
+
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/layout/layout.component.less b/projects/manage/src/app/feature/manage/components/layout/layout.component.less new file mode 100644 index 0000000..41bc9ea --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/layout/layout.component.less @@ -0,0 +1,84 @@ +:host { + display: flex; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +@height: 48px; + +.app-layout { + height: 100vh; +} + +.menu-sidebar { + position: relative; + z-index: 10; + height: 100%; + box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); +} + +.header-trigger { + display: inline-flex; + align-items: center; + height: @height; + padding: 0 24px; + font-size: 18px; + cursor: pointer; + transition: all 0.3s, padding 0s; +} + +.trigger:hover { + color: #1890ff; +} + +.sidebar-logo { + position: relative; + height: @height; + margin: 12px 0; + padding-left: 12px; + overflow: hidden; + line-height: @height; + background: #001529; + transition: all 0.3s; +} + +.sidebar-logo img { + display: inline-block; + // width: 32px; + height: 32px; + vertical-align: middle; +} + +.sidebar-logo h1 { + display: inline-block; + margin: 0 0 0 6px; + color: #fff; + font-weight: 600; + font-size: 16px; + font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; + vertical-align: middle; +} + +nz-header { + padding: 0; + width: 100%; + height: @height; + z-index: 2; +} + +.app-header { + position: relative; + height: @height; + padding: 0; + background: #fff; + box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); +} + +// nz-content { +// margin: 16px; +// } + +.inner-content { + height: 100%; +} diff --git a/projects/manage/src/app/feature/manage/components/layout/layout.component.ts b/projects/manage/src/app/feature/manage/components/layout/layout.component.ts new file mode 100644 index 0000000..2e791bb --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/layout/layout.component.ts @@ -0,0 +1,74 @@ +import { Component } from "@angular/core"; +import { NavigationEnd, Router } from "@angular/router"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { NgxPermissionsService } from "ngx-permissions"; +import { filter, Subject, takeUntil } from "rxjs"; +import { PermissionItmeInterface } from "../../pages"; +import { AuthInterface } from "@cdk/types"; + +@Component({ + selector: "app-layout", + templateUrl: "./layout.component.html", + styleUrls: ["./layout.component.less"], +}) +export class LayoutComponent { + constructor( + private router: Router, + private modal: NzModalService, + private msg: NzMessageService, + private permissionsService: NgxPermissionsService + ) { + this.router.events + .pipe( + takeUntil(this.unSubscribe$), + filter((e): e is NavigationEnd => e instanceof NavigationEnd) + ) + .subscribe((e) => { + this.currentUrl = e.url; + }); + } + + unSubscribe$ = new Subject(); + + isCollapsed = false; + + currentUrl: string = ""; + + userName = ""; + + ngOnInit() { + const auth = localStorage.getItem("auth"); + + if (auth) { + try { + const authData = JSON.parse(auth) as AuthInterface; + if (authData.userName) { + this.userName = authData.userName; + } + if (Array.isArray(authData.permissionList)) { + const permissionList = authData.permissionList; + const permissions = permissionList.reduce((a, c) => { + if (c.scope === 1 && c.value === "true") { + return a.concat(c.roleId); + } + return a; + }, [] as string[]); + this.permissionsService.loadPermissions(permissions); + } + } catch (error) {} + } + } + + louout() { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要退出登录?", + nzOnOk: () => { + localStorage.clear(); + this.msg.success("已退出登录"); + this.router.navigate(["/auth/login"]); + }, + }); + } +} diff --git a/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.html b/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.html new file mode 100644 index 0000000..85e0b94 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.html @@ -0,0 +1,40 @@ +
+ + + 电站 + + + + + + + + 机组编号 + + + + + + + + + + 联系人 + + + + + + + + 联系电话 + + + + + + +
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.less b/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.ts b/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.ts new file mode 100644 index 0000000..a34c574 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/machine-form/machine-form.component.ts @@ -0,0 +1,40 @@ +import { Component, Input } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { DecValidators } from "@cdk/public-api"; +import { Utils } from "@cdk/utils"; +import { OptionItemInterface } from "@manage/dtos"; + +@Component({ + selector: "app-machine-form", + templateUrl: "./machine-form.component.html", + styleUrls: ["./machine-form.component.less"], +}) +export class MachineFormComponent { + constructor() {} + + @Input() public value?: any; + + @Input() public stations: OptionItemInterface[] = []; + + public formGroup = new FormGroup({ + motorGroupId: new FormControl(), + number: new FormControl("", [DecValidators.required("请输入编号"), DecValidators.maxLength(50)]), + powerStationId: new FormControl("", [DecValidators.required("请选择电站")]), + contact: new FormControl("", [DecValidators.maxLength(50)]), + phone: new FormControl("", [DecValidators.maxLength(50)]), + }); + + public ngOnInit(): void { + if (this.value) { + this.formGroup.patchValue(this.value); + } + } + + public getValues() { + let values = null; + if (Utils.validateFormGroup(this.formGroup)) { + values = this.formGroup.value; + } + return values; + } +} diff --git a/projects/manage/src/app/feature/manage/components/notfound/notfound.component.html b/projects/manage/src/app/feature/manage/components/notfound/notfound.component.html new file mode 100644 index 0000000..df4b62f --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/notfound/notfound.component.html @@ -0,0 +1,6 @@ +
+ +

+ 此页面未找到。 +

+
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/notfound/notfound.component.less b/projects/manage/src/app/feature/manage/components/notfound/notfound.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/notfound/notfound.component.ts b/projects/manage/src/app/feature/manage/components/notfound/notfound.component.ts new file mode 100644 index 0000000..0368db3 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/notfound/notfound.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-notfound', + templateUrl: './notfound.component.html', + styleUrls: ['./notfound.component.less'] +}) +export class NotfoundComponent { + +} diff --git a/projects/manage/src/app/feature/manage/components/page/page.component.html b/projects/manage/src/app/feature/manage/components/page/page.component.html new file mode 100644 index 0000000..d5b26fd --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/page/page.component.html @@ -0,0 +1,12 @@ + + + +
+ +
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/page/page.component.less b/projects/manage/src/app/feature/manage/components/page/page.component.less new file mode 100644 index 0000000..b4bebaa --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/page/page.component.less @@ -0,0 +1,5 @@ +:host { + display: flex; + flex-direction: column; + height: 100%; +} diff --git a/projects/manage/src/app/feature/manage/components/page/page.component.ts b/projects/manage/src/app/feature/manage/components/page/page.component.ts new file mode 100644 index 0000000..99ab104 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/page/page.component.ts @@ -0,0 +1,13 @@ +import { Component, Input, ViewEncapsulation } from "@angular/core"; + +@Component({ + selector: "app-page", + templateUrl: "./page.component.html", + styleUrls: ["./page.component.less"], + // encapsulation: ViewEncapsulation.None, +}) +export class PageComponent { + constructor() {} + + @Input() pageTitle: string = ""; +} diff --git a/projects/manage/src/app/feature/manage/components/point-form/point-form.component.html b/projects/manage/src/app/feature/manage/components/point-form/point-form.component.html new file mode 100644 index 0000000..2821983 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/point-form/point-form.component.html @@ -0,0 +1,63 @@ +
+ + + 电站 + + + + + + + + 机组 + + + + + + + + 检测点 + + + + + + + + 磁极数量 + + + + + + + + + + + 手动检测时长 + + + + + + + + + + + 自动检测时长 + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/point-form/point-form.component.less b/projects/manage/src/app/feature/manage/components/point-form/point-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/point-form/point-form.component.ts b/projects/manage/src/app/feature/manage/components/point-form/point-form.component.ts new file mode 100644 index 0000000..a98766f --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/point-form/point-form.component.ts @@ -0,0 +1,65 @@ +import { Component, Input } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { DecValidators } from "@cdk/public-api"; +import { Utils } from "@cdk/utils"; +import { OptionItemInterface } from "@manage/dtos"; + +@Component({ + selector: "app-point-form", + templateUrl: "./point-form.component.html", + styleUrls: ["./point-form.component.less"], +}) +export class PointFormComponent { + constructor() {} + + @Input() public value?: any; + + @Input() public stations: OptionItemInterface[] = []; + + @Input() public groups: OptionItemInterface[] = []; + + currentGroups: OptionItemInterface[] = []; + + public formGroup = new FormGroup({ + pointId: new FormControl(), + name: new FormControl("", [DecValidators.required("请输入检测点"), DecValidators.maxLength(50)]), + powerStationId: new FormControl("", [DecValidators.required("请选择电站")]), + motorGroupId: new FormControl("", [DecValidators.required("请选择机组")]), + poleNum: new FormControl("", [ + DecValidators.required("请输入磁极数量"), + DecValidators.min(1), + DecValidators.max(999), + ]), + manualTime: new FormControl("", [ + DecValidators.required("请输入手动检测时长"), + DecValidators.min(0), + DecValidators.max(600), + ]), + automaticTime: new FormControl("", [ + DecValidators.required("请输入自动检测时长"), + DecValidators.min(0), + DecValidators.max(600), + ]), + }); + + public ngOnInit(): void { + this.formGroup.get("powerStationId")?.valueChanges.subscribe((powerStationId) => { + this.currentGroups = this.groups.filter((f) => f["powerStationId"] === powerStationId); + const motorGroupId = this.formGroup.get("motorGroupId"); + if (!this.currentGroups.some((s) => s.value === motorGroupId?.value)) { + motorGroupId?.setValue(null); + } + }); + if (this.value) { + this.formGroup.patchValue(this.value); + } + } + + public getValues() { + let values = null; + if (Utils.validateFormGroup(this.formGroup)) { + values = this.formGroup.value; + } + return values; + } +} diff --git a/projects/manage/src/app/feature/manage/components/station-form/station-form.component.html b/projects/manage/src/app/feature/manage/components/station-form/station-form.component.html new file mode 100644 index 0000000..5e4869c --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/station-form/station-form.component.html @@ -0,0 +1,45 @@ +
+ + + 电站名称 + + + + + + + + 地址 + + + + + + + + 联系人 + + + + + + + + 联系电话 + + + + + + + + 电站简介 + + + + + +
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/station-form/station-form.component.less b/projects/manage/src/app/feature/manage/components/station-form/station-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/station-form/station-form.component.ts b/projects/manage/src/app/feature/manage/components/station-form/station-form.component.ts new file mode 100644 index 0000000..7732ac4 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/station-form/station-form.component.ts @@ -0,0 +1,39 @@ +import { Component, Input } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { DecValidators } from "@cdk/public-api"; +import { Utils } from "@cdk/utils"; +import { OptionItemInterface } from "@manage/dtos"; + +@Component({ + selector: "app-station-form", + templateUrl: "./station-form.component.html", + styleUrls: ["./station-form.component.less"], +}) +export class StationFormComponent { + constructor() {} + + @Input() public value?: any; + + public formGroup = new FormGroup({ + powerStationId: new FormControl(), + name: new FormControl("", [DecValidators.required("请输入名称"), DecValidators.maxLength(50)]), + address: new FormControl("", [DecValidators.maxLength(50)]), + contact: new FormControl("", [DecValidators.maxLength(50)]), + phone: new FormControl("", [DecValidators.maxLength(50)]), + introduction: new FormControl("", [DecValidators.maxLength(200)]), + }); + + public ngOnInit(): void { + if (this.value) { + this.formGroup.patchValue(this.value); + } + } + + public getValues() { + let values = null; + if (Utils.validateFormGroup(this.formGroup)) { + values = this.formGroup.value; + } + return values; + } +} diff --git a/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.html b/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.html new file mode 100644 index 0000000..a8228fd --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.html @@ -0,0 +1,77 @@ + +
+
+ +
+
    +
  • +
    + + {{role.roleName}} + +
    + + +
    +
    +
  • + + +
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + +
+
+
+ + +
+ + + 角色名称 + + + + + +
+
+ + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.less b/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.less new file mode 100644 index 0000000..4951830 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.less @@ -0,0 +1,10 @@ +.role-item { + .actions { + display: none; + } + &:hover { + .actions { + display: block; + } + } +} diff --git a/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.ts b/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.ts new file mode 100644 index 0000000..bd4bc9c --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/system-user-layout/system-user-layout.component.ts @@ -0,0 +1,103 @@ +import { lastValueFrom } from "rxjs"; +import { ManageApiService } from "@manage/app/core/services"; +import { Component, OnInit, TemplateRef, ViewEncapsulation } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Utils } from "@cdk/utils"; +import { DecValidators } from "@cdk/validators"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { UserRoleDTO } from "@manage/dtos"; +import { ActivatedRoute, Router } from "@angular/router"; + +@Component({ + selector: "app-system-user-layout", + templateUrl: "./system-user-layout.component.html", + styleUrls: ["./system-user-layout.component.less"], + encapsulation: ViewEncapsulation.None, +}) +export class SystemUserLayoutComponent implements OnInit { + constructor( + private modal: NzModalService, + private msg: NzMessageService, + private api: ManageApiService, + private router: Router, + private route: ActivatedRoute + ) {} + + tab: string = "0"; + + roles: UserRoleDTO[] = []; + + currentRole!: UserRoleDTO; + + formGroup = new FormGroup({ + roleId: new FormControl(), + roleName: new FormControl("", [DecValidators.required("请输入角色名称"), DecValidators.maxLength(50)]), + }); + + ngOnInit(): void { + this.getRoleList(); + this.route.queryParams.subscribe((res) => { + this.tab = res?.["tab"] ?? "0"; + }); + } + + getRoleList() { + this.api.getRoleList().subscribe((res) => { + this.roles = res.body.sort((a, b) => (a.isRoot === b.isRoot ? 0 : a.isRoot ? -1 : 1)); + if (!this.currentRole) { + this.currentRole = this.roles?.[0]; + } + }); + } + + openForm(nzContent: TemplateRef<{}>, e: Event, v?: UserRoleDTO) { + e.stopPropagation(); + if (v) { + this.formGroup.patchValue(v); + } + this.modal.create({ + nzTitle: v ? "编辑管理员角色" : "添加管理员角色", + nzContent, + nzOnCancel: this.onFormCancel.bind(this), + nzOnOk: async () => { + if (Utils.validateFormGroup(this.formGroup)) { + await lastValueFrom(this.api.saveRole(this.formGroup.value)); + this.msg.success("保存成功"); + this.getRoleList(); + this.onFormCancel(); + return true; + } + return false; + }, + }); + } + + onFormCancel() { + this.formGroup.reset({ + roleName: "", + roleId: void 0, + }); + } + + onDeleteRole(v: UserRoleDTO) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该角色", + nzOnOk: async () => { + await lastValueFrom(this.api.deleteRole(v.roleId!)); + this.msg.success("删除成功"); + this.getRoleList(); + }, + }); + } + + onSelectedIndexChange(idx: number) { + this.router.navigate(["/manage/system/user"], { + queryParams: { + tab: idx, + }, + queryParamsHandling: "merge", + }); + } +} diff --git a/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.html b/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.html new file mode 100644 index 0000000..fa018d8 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.html @@ -0,0 +1,63 @@ +
+ + + 电站 + + + + + + + + + + 机组/检测点 + + + + + + + + + + 关联设备 + + + + + + + + + + 传感器型号 + + + + + + + + + 传感器名称 + + + + + + + + 串口号 + + + + + + + + +
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.less b/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.ts b/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.ts new file mode 100644 index 0000000..0c740b4 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/temperature-form/temperature-form.component.ts @@ -0,0 +1,88 @@ +import { Component, Input } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { AnyObject, DecValidators } from "@cdk/public-api"; +import { Utils } from "@cdk/utils"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { distinctUntilChanged } from "rxjs"; + +@Component({ + selector: "app-temperature-form", + templateUrl: "./temperature-form.component.html", + styleUrls: ["./temperature-form.component.less"], +}) +export class TemperatureFormComponent { + constructor(private api: ManageApiService) {} + + @Input() public value?: any; + + @Input() public stations: OptionItemInterface[] = []; + + @Input() public typeList: OptionItemInterface[] = []; + + groupAndPoint: OptionItemInterface[] = []; + + cameraList: OptionItemInterface[] = []; + + public formGroup = new FormGroup({ + deviceId: new FormControl(), + powerStationId: new FormControl("", [DecValidators.required("请选择电站")]), + motorGroupId: new FormControl(""), + pointId: new FormControl("", [DecValidators.required("请选择机组/检测点")]), + relatedDeviceId: new FormControl("", [DecValidators.required("请选择关联设备")]), + name: new FormControl("", [DecValidators.required("请输入传感器名称"), DecValidators.maxLength(50)]), + typeId: new FormControl("", [DecValidators.required("请输入传感器型号")]), + serialPort: new FormControl(""), + }); + + public ngOnInit(): void { + this.formGroup + .get("powerStationId") + ?.valueChanges.pipe(distinctUntilChanged()) + .subscribe((sid) => { + this.formGroup.get("pointId")?.setValue(null); + if (sid) { + this.api.getAllPoint(sid).subscribe((res) => { + this.groupAndPoint = res; + this.formGroup.get("pointId")?.patchValue(this.formGroup.get("pointId")?.value!); + }); + } + }); + this.formGroup + .get("pointId") + ?.valueChanges.pipe(distinctUntilChanged()) + .subscribe((pid) => { + this.formGroup.patchValue({ + relatedDeviceId: null, + }); + + if (pid) { + this.getCameraListByPointId(pid); + } + }); + + if (this.value) { + this.formGroup.patchValue(this.value); + } + } + + getCameraListByPointId(pointId: string) { + this.api.getDevicePage({}, { pointId }).subscribe((res) => { + if (Array.isArray(res["data"])) { + this.cameraList = res.data.map((i: AnyObject) => ({ value: i["deviceId"], label: i["name"] })); + } + }); + } + + public getValues() { + let values = null; + if (Utils.validateFormGroup(this.formGroup)) { + const { pointId } = this.formGroup.value; + const item = this.groupAndPoint.find((f) => f.value === pointId); + + this.formGroup.value["motorGroupId"] = item!["motorGroupId"]; + values = this.formGroup.value; + } + return values; + } +} diff --git a/projects/manage/src/app/feature/manage/components/user-form/user-form.component.html b/projects/manage/src/app/feature/manage/components/user-form/user-form.component.html new file mode 100644 index 0000000..67fc5b8 --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/user-form/user-form.component.html @@ -0,0 +1,30 @@ +
+ + + 账号 + + + + + + + + 姓名 + + + + + + + + 密码 + + + + + + +
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/components/user-form/user-form.component.less b/projects/manage/src/app/feature/manage/components/user-form/user-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/components/user-form/user-form.component.ts b/projects/manage/src/app/feature/manage/components/user-form/user-form.component.ts new file mode 100644 index 0000000..61c7fbc --- /dev/null +++ b/projects/manage/src/app/feature/manage/components/user-form/user-form.component.ts @@ -0,0 +1,38 @@ +import { ManageApiService } from "@manage/app/core/services"; +import { Component, Input } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { DecValidators } from "@cdk/public-api"; +import { Utils } from "@cdk/utils"; +import { UserDTO } from "@manage/dtos"; + +@Component({ + selector: "app-user-form", + templateUrl: "./user-form.component.html", + styleUrls: ["./user-form.component.less"], +}) +export class UserFormComponent { + constructor(private api: ManageApiService) {} + + @Input() public value?: UserDTO; + + public formGroup = new FormGroup({ + id: new FormControl(), + uid: new FormControl("", [DecValidators.required("请输入账号"), DecValidators.maxLength(50)]), + userName: new FormControl("", [DecValidators.required("请输入姓名"), DecValidators.maxLength(50)]), + password: new FormControl("", [DecValidators.required("请输入密码"), DecValidators.maxLength(50)]), + }); + + public ngOnInit(): void { + if (this.value) { + this.formGroup.patchValue(this.value); + } + } + + public getValues() { + let values = null; + if (Utils.validateFormGroup(this.formGroup)) { + values = this.formGroup.value; + } + return values; + } +} diff --git a/projects/manage/src/app/feature/manage/manage-routing.module.ts b/projects/manage/src/app/feature/manage/manage-routing.module.ts new file mode 100644 index 0000000..a492af4 --- /dev/null +++ b/projects/manage/src/app/feature/manage/manage-routing.module.ts @@ -0,0 +1,209 @@ +import { PointComponent } from "./pages/point/point.component"; +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; +import { + ForbiddenComponent, + HomeComponent, + LayoutComponent, + NotfoundComponent, + SystemUserLayoutComponent, +} from "./components"; +import { + MachineComponent, + StationComponent, + PermissionComponent, + UserListComponent, + CameraComponent, + TemperatureComponent, + AlgorithmListComponent, + AlgorithmFormComponent, + SystemInfoComponent, + SystemThemeComponent, +} from "./pages"; +import { NgxPermissionsGuard } from "ngx-permissions"; +import { PermissionGuard, PermissionLoadGuard } from "@manage/app/core/gaurd/permisson.guard"; + +const routes: Routes = [ + { + path: "", + component: LayoutComponent, + canActivateChild: [PermissionLoadGuard], + children: [ + { + path: "", + pathMatch: "full", + redirectTo: "home", + }, + { + path: "home", + component: HomeComponent, + }, + { + path: "station", + component: StationComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_powerstation"], + redirectTo: "/manage/forbidden", + }, + }, + }, + { + path: "machine", + component: MachineComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_motorgroup"], + redirectTo: "/manage/forbidden", + }, + }, + }, + { + path: "point", + component: PointComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_point"], + redirectTo: "/manage/forbidden", + }, + }, + }, + { + path: "device", + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_device_camer_plc", "role_device_tempsensor"], + redirectTo: "/manage/forbidden", + }, + }, + children: [ + { + path: "", + pathMatch: "full", + redirectTo: "camera", + }, + { + path: "camera", + component: CameraComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_device_camer_plc"], + redirectTo: "/manage/forbidden", + }, + }, + }, + { + path: "temperature", + component: TemperatureComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_device_tempsensor"], + redirectTo: "/manage/forbidden", + }, + }, + }, + ], + }, + { + path: "algorithm", + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_algorithm"], + redirectTo: "/manage/forbidden", + }, + }, + children: [ + { + path: "", + pathMatch: "full", + redirectTo: "list", + }, + { + path: "list", + component: AlgorithmListComponent, + }, + { + path: "form/:id", + component: AlgorithmFormComponent, + }, + ], + }, + { + path: "system", + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_sys_info", "role_sys_theme", "role_sys_user"], + redirectTo: "/manage/forbidden", + }, + }, + children: [ + { + path: "info", + component: SystemInfoComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_sys_info"], + redirectTo: "/manage/forbidden", + }, + }, + }, + { + path: "theme", + component: SystemThemeComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_sys_theme"], + redirectTo: "/manage/forbidden", + }, + }, + }, + { + path: "user", + component: SystemUserLayoutComponent, + canActivate: [NgxPermissionsGuard], + data: { + permissions: { + only: ["role_sys_user"], + redirectTo: "/manage/forbidden", + }, + }, + // children: [ + // { + // path: "list", + // component: UserListComponent, + // }, + // { + // path: "role", + // component: RoleComponent, + // }, + // ], + }, + ], + }, + { + path: "forbidden", + component: ForbiddenComponent, + }, + { + path: "**", + component: NotfoundComponent, + }, + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class ManageRoutingModule {} diff --git a/projects/manage/src/app/feature/manage/manage.module.ts b/projects/manage/src/app/feature/manage/manage.module.ts new file mode 100644 index 0000000..9eb7774 --- /dev/null +++ b/projects/manage/src/app/feature/manage/manage.module.ts @@ -0,0 +1,67 @@ +import { NgModule } from "@angular/core"; +import { ColorPickerModule } from "@iplab/ngx-color-picker"; +import { ManageRoutingModule } from "./manage-routing.module"; +import { SharedModule } from "@manage/app/shared/shared.module"; + +import { + LayoutComponent, + PageComponent, + StationFormComponent, + MachineFormComponent, + PointFormComponent, + SystemUserLayoutComponent, + UserFormComponent, + CameraFormComponent, + TemperatureFormComponent, + ColorPickerComponent, + AlgorithmPointSelectComponent, + ForbiddenComponent, + NotfoundComponent, + HomeComponent, +} from "./components"; +import { + StationComponent, + MachineComponent, + PointComponent, + UserListComponent, + CameraComponent, + TemperatureComponent, + AlgorithmListComponent, + AlgorithmFormComponent, + SystemInfoComponent, + SystemThemeComponent, + PermissionComponent, +} from "./pages"; +import { NgxPermissionsModule } from "ngx-permissions"; + +@NgModule({ + declarations: [ + LayoutComponent, + PageComponent, + StationComponent, + StationFormComponent, + MachineComponent, + MachineFormComponent, + PointComponent, + PointFormComponent, + SystemUserLayoutComponent, + UserListComponent, + PermissionComponent, + UserFormComponent, + CameraComponent, + TemperatureComponent, + CameraFormComponent, + TemperatureFormComponent, + AlgorithmListComponent, + AlgorithmFormComponent, + SystemInfoComponent, + SystemThemeComponent, + ColorPickerComponent, + AlgorithmPointSelectComponent, + ForbiddenComponent, + NotfoundComponent, + HomeComponent, + ], + imports: [SharedModule, ManageRoutingModule, ColorPickerModule, NgxPermissionsModule.forChild()], +}) +export class ManageModule {} diff --git a/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.html b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.html new file mode 100644 index 0000000..768b367 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.html @@ -0,0 +1,75 @@ + +
+ + + + 算法来源 + + + + + + + + 算法 + + + + + + + + 算法文件 + + + +
+ {{fileName}} +
+ +
+
+
+ + + + 算法应用机组/检测点 + + + +
+ + {{p['powerStation']}}/{{p['motorGroup']}}/{{p['point']}} + + + + +
+
+
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.less b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.ts b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.ts new file mode 100644 index 0000000..3083772 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-form/algorithm-form.component.ts @@ -0,0 +1,164 @@ +import { AnyObject } from "./../../../../../../../../cdk/src/types/index"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { FormBuilder, FormControl, FormGroup } from "@angular/forms"; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { finalize } from "rxjs"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { DecValidators } from "@cdk/validators"; +import { Utils } from "@cdk/utils"; +import { AlgorithmPointSelectComponent } from "../../../components"; + +@Component({ + selector: "app-algorithm-form", + templateUrl: "./algorithm-form.component.html", + styleUrls: ["./algorithm-form.component.less"], +}) +export class AlgorithmFormComponent implements OnInit { + constructor( + private route: ActivatedRoute, + private router: Router, + private api: ManageApiService, + private fb: FormBuilder, + private msg: NzMessageService, + private modal: NzModalService + ) {} + + id: null | string = null; + + source: OptionItemInterface[] = []; + + algorithms: OptionItemInterface[] = []; + + stations: OptionItemInterface[] = []; + + groups: OptionItemInterface[] = []; + + form!: FormGroup; + + importDataLoading = false; + + submitLoading = false; + + get points() { + return this.form.get("points") as FormControl; + } + + ngOnInit(): void { + const id = this.route.snapshot.paramMap.get("id"); + const query = this.route.snapshot.queryParamMap; + + this.id = id === "create" ? null : id; + + this.initForm(); + + if (this.id) { + this.api.getAlgorithmDetail({ algorithmId: this.id }).subscribe((res) => { + this.form.patchValue({ + ...res.body, + points: res.body?.["ranges"] ?? [], + }); + }); + query.keys.forEach((i) => { + this.form.patchValue({ + [i]: query.get(i), + }); + }); + } + + this.api.getAlgorithmSource().subscribe((source) => { + this.source = source; + }); + + this.api.getAllStation().subscribe((res) => { + this.stations = res; + }); + this.api.getAllGroup().subscribe((res) => { + this.groups = res; + }); + } + + initForm() { + this.form = this.fb.group({ + algorithmName: this.fb.control("", [DecValidators.required()]), + source: this.fb.control("", [DecValidators.required()]), + algorithmFileName: this.fb.control(""), + points: this.fb.control([]), + }); + this.form.get("source")?.valueChanges.subscribe((source) => { + this.form.get("algorithmName")?.setValue(null); + if (source) { + this.api.getAlgorithmNameBySource(source).subscribe((res) => { + this.algorithms = res; + }); + } + }); + } + + onFileChange(e: Event) { + const target = e.target as HTMLInputElement; + const file = target.files![0]; + target.value = ""; + const formData = new FormData(); + formData.append("file", file); + this.importDataLoading = true; + this.api + .uploadAlgorithmFile(formData) + .pipe( + finalize(() => { + this.importDataLoading = false; + }) + ) + .subscribe(() => { + this.msg.success("上传成功"); + this.form.patchValue({ + algorithmFileName: file.name, + }); + }); + } + + showPointSelectModal() { + this.modal.create({ + nzTitle: "添加机组监测点", + nzWidth: 820, + nzData: { + algorithmId: this.id, + stations: this.stations, + groups: this.groups, + val: this.points.value, + }, + nzContent: AlgorithmPointSelectComponent, + nzOnOk: (e) => { + const points = e.selectedPoint; + this.points.setValue(points); + }, + }); + } + + onRemovePoint(idx: number) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该监测点?", + nzOnOk: () => { + const val = (this.points?.value ?? []) as AnyObject[]; + this.points.setValue(val.filter((_, i) => idx !== i)); + }, + }); + } + + onSubmit() { + if (Utils.validateFormGroup(this.form)) { + this.api + .saveAlgorithm({ + ...this.form.value, + algorithmId: this.id, + }) + .subscribe((res) => { + this.msg.success(res.desc); + this.router.navigate(["/manage/algorithm/list"]); + }); + } + } +} diff --git a/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.html b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.html new file mode 100644 index 0000000..dcbba18 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.html @@ -0,0 +1,32 @@ + + + + + + + + + + + 算法名称 + + + + + + + + 算法来源 + + + + + + + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.less b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.ts b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.ts new file mode 100644 index 0000000..43c917e --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/algorithm/algorithm-list/algorithm-list.component.ts @@ -0,0 +1,87 @@ +import { lastValueFrom } from "rxjs"; +import { Component, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; + +@Component({ + selector: "app-algorithm-list", + templateUrl: "./algorithm-list.component.html", + styleUrls: ["./algorithm-list.component.less"], +}) +export class AlgorithmListComponent { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private msg: NzMessageService + ) {} + + public tableList = new TableListOption(this.fetchData.bind(this)); + + source: OptionItemInterface[] = []; + + public queryForm = new FormGroup({ + algorithmName: new FormControl(""), + source: new FormControl(""), + }); + + ngOnInit(): void { + this.initTableList(); + this.api.getAlgorithmSource().subscribe((source) => { + this.source = source; + }); + } + + fetchData(query: AnyObject, pager: AnyObject) { + return this.api.getAlgorithmPage(pager, query); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "name", title: "算法名称" }, + { key: "source", title: "算法来源" }, + { key: "group_point_num", title: "关联机组/监测点数量" }, + { key: "gmtCreate", title: "添加时间" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "编辑", + premissions: [], + onClick: (v) => { + this.router.navigate(["/manage/algorithm/form", v["algorithmId"]], { + queryParams: { + algorithmName: v["name"], + source: v["source"], + }, + }); + }, + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该算法?", + nzOnOk: async () => { + await lastValueFrom(this.api.delAlgorithm(v)); + this.tableList.run(); + this.msg.success("删除成功"); + }, + }); + } +} diff --git a/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.html b/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.html new file mode 100644 index 0000000..9714031 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.html @@ -0,0 +1,80 @@ + + + + + + + + + + + 名称/SN码 + + + + + + + + 电站 + + + + + + + + + 机组/检测点 + + + + + + + + + 状态 + + + + + + + + + + + + + + + + + + + {{data}} + + + + + + + + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.less b/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.ts b/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.ts new file mode 100644 index 0000000..7d7236a --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/device/camera/camera.component.ts @@ -0,0 +1,184 @@ +import { finalize, lastValueFrom } from "rxjs"; +import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; +import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { CameraFormComponent } from "../../../components"; +import { OptionItemInterface } from "@manage/dtos"; + +@Component({ + selector: "app-camera", + templateUrl: "./camera.component.html", + styleUrls: ["./camera.component.less"], +}) +export class CameraComponent { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private drawer: NzDrawerService, + private msg: NzMessageService + ) {} + + @ViewChild("formFooter") formFooter!: TemplateRef<{}>; + + deviceTypes: OptionItemInterface[] = []; + + stations: OptionItemInterface[] = []; + + groupAndPoint: OptionItemInterface[] = []; + + submitLoading = false; + + public tableList = new TableListOption(this.fetchData.bind(this)); + + public queryForm = new FormGroup({ + name: new FormControl(""), + powerStationId: new FormControl(""), + motorGroupId: new FormControl(""), + pointId: new FormControl(""), + status: new FormControl(""), + }); + + public drawerRef?: NzDrawerRef; + + ngOnInit(): void { + this.initTableList(); + this.queryForm.get("powerStationId")?.valueChanges.subscribe((sid) => { + this.queryForm.get("pointId")?.setValue(null); + if (sid) { + this.api.getAllPoint(sid).subscribe((res) => { + this.groupAndPoint = res; + }); + } + }); + this.queryForm.get("pointId")?.valueChanges.subscribe((pid) => { + const item = this.groupAndPoint.find((f) => f.value === pid); + + this.queryForm.get("motorGroupId")?.setValue(item?.["motorGroupId"]); + }); + this.api.getDeviceTypes().subscribe((deviceTypes) => { + this.deviceTypes = deviceTypes; + }); + this.api.getAllStation().subscribe((stations) => { + this.stations = stations; + }); + } + + fetchData(query: AnyObject, pager: AnyObject) { + return this.api.getDevicePage(pager, query); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "name", title: "相机名称" }, + { key: "sn", title: "SN码" }, + { key: "plcIp", title: "PLC-IP" }, + { key: "powerStation", title: "所属电站" }, + { key: "group_Point", title: "机组/检测点" }, + { key: "fps", title: "帧率(fps)" }, + { key: "exposureTime", title: "曝光时间(ms)" }, + { key: "status", title: "工作状态" }, + { key: "gmtCreate", title: "添加日期" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "停用", + premissions: [], + visible: (v) => { + return v["status"] === 1; + }, + onClick: this.updateStatus.bind(this), + }, + { + title: "启用", + premissions: [], + visible: (v) => { + return v["status"] === 0; + }, + onClick: this.updateStatus.bind(this), + }, + { + title: "编辑", + premissions: [], + onClick: this.openForm.bind(this), + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该相机?", + nzOnOk: async () => { + await lastValueFrom(this.api.deleteDevice(v)); + this.tableList.run(); + this.msg.success("删除成功"); + }, + }); + } + + updateStatus(v: AnyObject) { + const text = v["status"] === 0 ? "启用" : "停用"; + const status = v["status"] === 0 ? 1 : 0; + this.modal.confirm({ + nzTitle: "警告", + nzContent: `是否要${text}该相机?`, + nzOnOk: async () => { + const res = await lastValueFrom(this.api.updateDeviceStatus({ ...v, status })); + this.tableList.run(); + this.msg.success(res.desc); + }, + }); + } + + openForm(v?: any) { + this.drawerRef = this.drawer.create({ + nzTitle: v ? "编辑相机" : "新增相机", + nzWidth: 660, + nzContent: CameraFormComponent, + nzContentParams: { value: v, deviceTypes: this.deviceTypes, stations: this.stations }, + nzOnCancel: this.onCancel.bind(this), + nzFooter: this.formFooter, + }); + } + + async onCancel() { + this.drawerRef?.close(); + } + + submitForm() { + if (this.drawerRef) { + const form = this.drawerRef.getContentComponent()!; + const value = form.getValues(); + this.submitLoading = true; + if (value) { + this.api + .saveDevice(value) + .pipe( + finalize(() => { + this.submitLoading = false; + }) + ) + .subscribe(() => { + this.msg.success("保存成功"); + this.onCancel(); + this.tableList.run(); + }); + } + } + } +} diff --git a/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.html b/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.html new file mode 100644 index 0000000..b581f57 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.html @@ -0,0 +1,67 @@ + + + + + + + + + + + 名称/串口 + + + + + + + + 电站 + + + + + + + + 机组/检测点 + + + + + + + + 状态 + + + + + + + + + + + + + + + + + + + {{data}} + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.less b/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.ts b/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.ts new file mode 100644 index 0000000..22b4882 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/device/temperature/temperature.component.ts @@ -0,0 +1,129 @@ +import { NzDrawerRef, NzDrawerService } from "ng-zorro-antd/drawer"; +import { Component, OnInit, TemplateRef, ViewChild } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { TemperatureFormComponent } from "../../../components"; +import { OptionItemInterface } from "@manage/dtos"; +import { lastValueFrom } from "rxjs"; + +@Component({ + selector: "app-temperature", + templateUrl: "./temperature.component.html", + styleUrls: ["./temperature.component.less"], +}) +export class TemperatureComponent { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private msg: NzMessageService + ) {} + + @ViewChild("formFooter") formFooter!: TemplateRef<{}>; + + public tableList = new TableListOption(this.fetchData.bind(this)); + + public queryForm = new FormGroup({ + nameOrSerialPort: new FormControl(""), + powerStationId: new FormControl(""), + pointId: new FormControl(""), + status: new FormControl(""), + }); + + deviceTypes: OptionItemInterface[] = []; + + stations: OptionItemInterface[] = []; + + groupAndPoint: OptionItemInterface[] = []; + + typeList: OptionItemInterface[] = []; + + ngOnInit(): void { + this.initTableList(); + + this.queryForm.get("powerStationId")?.valueChanges.subscribe((sid) => { + this.queryForm.get("pointId")?.setValue(null); + if (sid) { + this.api.getAllPoint(sid).subscribe((res) => { + this.groupAndPoint = res; + }); + } + }); + + this.api.getAllStation().subscribe((stations) => { + this.stations = stations; + }); + this.api.getTemperatureDeviceTypes().subscribe((res) => { + this.typeList = res; + }); + } + + fetchData(query: AnyObject, pager: AnyObject) { + return this.api.getTemperatureDevicePage(pager, query); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "name", title: "测温传感器名称" }, + { key: "type", title: "传感器类型" }, + { key: "powerStation", title: "所属电站" }, + { key: "group_Point", title: "机组/检测点" }, + { key: "relatedDevice", title: "关联设备" }, + { key: "status", title: "测温传感器状态" }, + { key: "gmtCreate", title: "添加时间" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "编辑", + premissions: [], + onClick: this.openForm.bind(this), + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该传感器?", + + nzOnOk: async () => { + const res = await lastValueFrom(this.api.deleteTemperatureDevice(v)); + this.tableList.run(); + this.msg.success(res.desc); + }, + }); + } + + openForm(v?: any) { + this.modal.create({ + nzTitle: v ? "编辑传感器" : "新增传感器", + nzWidth: 660, + nzContent: TemperatureFormComponent, + nzComponentParams: { value: v, stations: this.stations, typeList: this.typeList }, + nzOnOk: async (e) => { + const value = e.getValues(); + if (value) { + console.log("value", value); + const res = await lastValueFrom(this.api.saveTemperatureDevice(value)); + this.msg.success(res.desc); + this.tableList.run(); + return true; + } + return false; + }, + }); + } +} diff --git a/projects/manage/src/app/feature/manage/pages/index.ts b/projects/manage/src/app/feature/manage/pages/index.ts new file mode 100644 index 0000000..157bea5 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/index.ts @@ -0,0 +1,14 @@ +export * from "./station/station.component"; +export * from "./machine/machine.component"; +export * from "./point/point.component"; + +export * from "./device/camera/camera.component"; +export * from "./device/temperature/temperature.component"; + +export * from "./system/user/user-list/user-list.component"; +export * from "./system/user/permission/permission.component"; +export * from "./system/system-info/system-info.component"; +export * from "./system/system-theme/system-theme.component"; + +export * from "./algorithm/algorithm-list/algorithm-list.component"; +export * from "./algorithm/algorithm-form/algorithm-form.component"; diff --git a/projects/manage/src/app/feature/manage/pages/machine/machine.component.html b/projects/manage/src/app/feature/manage/pages/machine/machine.component.html new file mode 100644 index 0000000..67cc7ad --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/machine/machine.component.html @@ -0,0 +1,31 @@ + + + + + + + + + + + 机组编号 + + + + + + + + 电站 + + + + + + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/machine/machine.component.less b/projects/manage/src/app/feature/manage/pages/machine/machine.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/machine/machine.component.ts b/projects/manage/src/app/feature/manage/pages/machine/machine.component.ts new file mode 100644 index 0000000..507afb8 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/machine/machine.component.ts @@ -0,0 +1,111 @@ +import { lastValueFrom } from "rxjs"; +import { Component, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { MachineFormComponent } from "../../components"; + +@Component({ + selector: "app-machine", + templateUrl: "./machine.component.html", + styleUrls: ["./machine.component.less"], +}) +export class MachineComponent { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private msg: NzMessageService + ) {} + + stations: OptionItemInterface[] = []; + + public tableList = new TableListOption(this.fetchData.bind(this)); + + public queryForm = new FormGroup({ + number: new FormControl(""), + powerStationId: new FormControl(""), + }); + + ngOnInit(): void { + this.initTableList(); + this.api.getAllStation().subscribe((res) => { + this.stations = res; + }); + } + + fetchData(query: AnyObject, pager: AnyObject) { + return this.api.getGroupPage(pager, query); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "name", title: "机组编号" }, + { key: "powerStation", title: "所属电站" }, + { key: "pointNum", title: "监测点数量" }, + { key: "contact", title: "联系人" }, + { key: "phone", title: "联系电话" }, + { key: "gmtCreate", title: "添加日期" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "编辑", + premissions: [], + onClick: this.openForm.bind(this), + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "是否要删除该机组?", + nzClassName: "danger-confirm", + nzContent: "警告:删除后将删除该机组及机组下所有检测点信息,且不可恢复。", + nzOkDanger: true, + nzOnOk: async () => { + await lastValueFrom(this.api.delGroup(v)); + this.tableList.run(); + this.msg.success("删除成功"); + }, + }); + } + + openForm(v?: any) { + let value = Object.create(null); + if (v) { + value = { + ...v, + number: v["name"]?.split("#")?.[0], + }; + } + this.modal.create({ + nzTitle: v ? "编辑机组" : "新增机组", + nzContent: MachineFormComponent, + nzComponentParams: { value, stations: this.stations }, + nzOnOk: async (e) => { + const value = e.getValues(); + if (value) { + await lastValueFrom(this.api.saveGroup(value)); + this.msg.success("保存成功"); + this.tableList.run(); + return true; + } + + return false; + }, + }); + } +} diff --git a/projects/manage/src/app/feature/manage/pages/point/point.component.html b/projects/manage/src/app/feature/manage/pages/point/point.component.html new file mode 100644 index 0000000..b8a59e1 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/point/point.component.html @@ -0,0 +1,65 @@ + + + + + + + + + + + 检测点名称 + + + + + + + + 电站 + + + + + + + + + 机组 + + + + + + + + + + + + + + + + + + + + {{data}} + + + + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/point/point.component.less b/projects/manage/src/app/feature/manage/pages/point/point.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/point/point.component.ts b/projects/manage/src/app/feature/manage/pages/point/point.component.ts new file mode 100644 index 0000000..2841848 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/point/point.component.ts @@ -0,0 +1,137 @@ +import { lastValueFrom } from "rxjs"; +import { Component, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { PointFormComponent } from "../../components"; + +@Component({ + selector: "app-point", + templateUrl: "./point.component.html", + styleUrls: ["./point.component.less"], +}) +export class PointComponent { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private msg: NzMessageService + ) {} + + public tableList = new TableListOption(this.fetchData.bind(this)); + + stations: OptionItemInterface[] = []; + + groups: OptionItemInterface[] = []; + + currentGroups: OptionItemInterface[] = []; + + public queryForm = new FormGroup({ + id: new FormControl(""), + powerStationId: new FormControl(""), + motorGroupId: new FormControl(""), + name: new FormControl(""), + }); + + ngOnInit(): void { + this.initTableList(); + this.queryForm.get("powerStationId")?.valueChanges.subscribe((powerStationId) => { + this.currentGroups = this.groups.filter((f) => f["powerStationId"] === powerStationId); + this.queryForm.get("motorGroupId")?.setValue(null); + }); + this.api.getAllStation().subscribe((res) => { + this.stations = res; + this.queryForm.get("powerStationId"); + }); + this.api.getAllGroup().subscribe((res) => { + this.groups = res; + }); + } + + fetchData(query: AnyObject, pager: AnyObject) { + return this.api.getPointPage(pager, query); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "name", title: "检测点名称" }, + { key: "motorGroup", title: "机组编号" }, + { key: "poleNum", title: "磁极数量" }, + { key: "boltDetect", title: "螺栓松动检测" }, + { key: "lineDetect", title: "引出线变形检测" }, + { key: "poleOpenDetect", title: "磁极开匝检测" }, + { key: "pointTempDetect", title: "检测点温度检测" }, + { key: "gmtCreate", title: "添加日期" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "编辑", + premissions: [], + onClick: this.openForm.bind(this), + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "是否要删除该检测点?", + nzClassName: "danger-confirm", + nzContent: "警告:删除后将删除该检测点信息,且不可恢复。", + nzOkDanger: true, + nzOnOk: async () => { + await lastValueFrom(this.api.delPoint(v)); + this.tableList.run(); + this.msg.success("删除成功"); + }, + }); + } + + onDetectChange(k: string, row: AnyObject) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该检测类型?", + nzOnOk: async () => { + await lastValueFrom( + this.api.updatePointDetectStatus({ + ...row, + [k]: !row[k], + }) + ); + this.tableList.run(); + this.msg.success("操作成功"); + }, + }); + } + + openForm(v?: any) { + this.modal.create({ + nzTitle: v ? "编辑检测点" : "新增检测点", + nzContent: PointFormComponent, + nzComponentParams: { value: v, stations: this.stations, groups: this.groups }, + nzOnOk: async (e) => { + const value = e.getValues(); + if (value) { + await lastValueFrom(this.api.savePoint(value)); + this.msg.success("保存成功"); + this.tableList.run(); + return true; + } + + return false; + }, + }); + } +} diff --git a/projects/manage/src/app/feature/manage/pages/station/station.component.html b/projects/manage/src/app/feature/manage/pages/station/station.component.html new file mode 100644 index 0000000..36bc6a5 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/station/station.component.html @@ -0,0 +1,22 @@ + + + + + + + + + + + 电站名称 + + + + + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/station/station.component.less b/projects/manage/src/app/feature/manage/pages/station/station.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/station/station.component.ts b/projects/manage/src/app/feature/manage/pages/station/station.component.ts new file mode 100644 index 0000000..11073c4 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/station/station.component.ts @@ -0,0 +1,97 @@ +import { lastValueFrom } from "rxjs"; +import { Component, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { StationFormComponent } from "../../components"; +import { OptionItemInterface } from "@manage/dtos"; + +@Component({ + selector: "app-station", + templateUrl: "./station.component.html", + styleUrls: ["./station.component.less"], +}) +export class StationComponent implements OnInit { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private msg: NzMessageService + ) {} + + public tableList = new TableListOption(this.fetchData.bind(this)); + + public queryForm = new FormGroup({ + name: new FormControl(""), + }); + + ngOnInit(): void { + this.initTableList(); + } + + fetchData(query: AnyObject, pager: AnyObject) { + return this.api.getStationPage(pager, query); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "name", title: "电站名称" }, + { key: "address", title: "地址", width: "40%" }, + { key: "groupNum", title: "机组数量" }, + { key: "contact", title: "联系人" }, + { key: "phone", title: "联系电话" }, + { key: "gmtCreate", title: "添加时间" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "编辑", + premissions: [], + onClick: this.openForm.bind(this), + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "是否要删除该电站?", + nzClassName: "danger-confirm", + nzContent: "警告:删除后将删除该电站及电站下所有机组、检测点信息,且不可恢复。", + nzOkDanger: true, + nzOnOk: async () => { + await lastValueFrom(this.api.delStation(v)); + this.tableList.run(); + this.msg.success("删除成功"); + }, + }); + } + + openForm(v?: any) { + this.modal.create({ + nzTitle: v ? "编辑电站" : "新增电站", + nzContent: StationFormComponent, + nzComponentParams: { value: v }, + nzOnOk: async (e) => { + const value = e.getValues(); + if (value) { + await lastValueFrom(this.api.saveStation(value)); + this.msg.success("保存成功"); + this.tableList.run(); + return true; + } + return false; + }, + }); + } +} diff --git a/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.html b/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.html new file mode 100644 index 0000000..08ff020 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.html @@ -0,0 +1,102 @@ + + +
+ + + + + + + + + + 前端检测系统logo + + + +
+ +
+ + +
+
+ +
+ + +
+
+ + + 企业名称 + + + + + + + + 前端检测系统名称 + + + + + + + + 应用电站 + + + + + + +
+ +
+ +
+ +
+ + +
+
+
+ + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.less b/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.ts b/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.ts new file mode 100644 index 0000000..721e563 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/system-info/system-info.component.ts @@ -0,0 +1,158 @@ +import { Component, OnInit } from "@angular/core"; +import { FormArray, FormBuilder, FormGroup } from "@angular/forms"; +import { AnyObject } from "@cdk/types"; +import { Utils } from "@cdk/utils"; +import { DecValidators } from "@cdk/validators"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { finalize, lastValueFrom } from "rxjs"; + +@Component({ + selector: "app-system-info", + templateUrl: "./system-info.component.html", + styleUrls: ["./system-info.component.less"], +}) +export class SystemInfoComponent implements OnInit { + constructor( + private fb: FormBuilder, + private msg: NzMessageService, + private api: ManageApiService, + private modal: NzModalService + ) {} + + formGroup!: FormGroup; + + public get infos(): FormArray { + return this.formGroup.get("infos") as FormArray; + } + + loading = true; + + uploadLoading = false; + + submitLoading = false; + + stations: OptionItemInterface[] = []; + + // currentStations: OptionItemInterface[] = []; + + ngOnInit(): void { + this.api.getAllStation().subscribe((res) => { + this.stations = res; + }); + this.getInfo(); + this.formGroup = this.fb.group({ + infos: this.fb.array([]), + }); + } + + getInfo() { + this.api + .getSystemInfo() + .pipe( + finalize(() => { + this.loading = false; + }) + ) + .subscribe((res) => { + if (Array.isArray(res.body)) { + this.infos.clear(); + res.body.forEach((i) => { + this.newInfo(i); + }); + } + }); + } + + newInfo(value?: AnyObject) { + const powerStations = (value?.["powerStations"] ?? []) as AnyObject[]; + const powerStationsVal = powerStations.map((i) => i["powerStationId"]); + const infoGroup = this.fb.group({ + systemInfoId: this.fb.control(value?.["systemInfoId"]), + systemInfoName: this.fb.control(value?.["systemInfoName"], [DecValidators.required()]), + reservedField: this.fb.control(value?.["reservedField"]), + logoImg: this.fb.control(value?.["logoImg"], [DecValidators.required()]), + logoFileName: this.fb.control(value?.["logoFileName"], [DecValidators.required()]), + powerStations: this.fb.control(powerStationsVal, []), + }); + this.infos.push(infoGroup); + return infoGroup; + } + + onFileChange(e: Event, index: number) { + const target = e.target as HTMLInputElement; + const file = target.files![0]; + target.value = ""; + const formData = new FormData(); + const fileReader = new FileReader(); + fileReader.onload = () => { + const base64 = fileReader.result as string; + this.infos.at(index).get("logoImg")?.setValue(base64.split("base64,")[1]); + }; + formData.append("file", file); + this.uploadLoading = true; + this.api + .uploadLogo(formData) + .pipe( + finalize(() => { + this.uploadLoading = false; + }) + ) + .subscribe((r) => { + this.msg.success(r.desc); + fileReader.readAsDataURL(file); + this.infos.at(index).get("logoFileName")?.setValue(file.name); + }); + } + + deleteItem(idx: number) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该信息策略?", + nzOnOk: async () => { + const systemInfoId: string = this.infos.at(idx).get("systemInfoId")?.value; + if (systemInfoId) { + await lastValueFrom(this.api.deleteOneofSystemInfo(systemInfoId)); + } + this.infos.removeAt(idx); + this.msg.success("删除成功"); + }, + }); + } + + onSelectOpen(idx: number) { + const currentInfoStations = (this.infos.at(idx).get("powerStations")?.value ?? []) as string[]; + const allStation = this.infos.controls.reduce( + (a, c) => a.concat(c.get("powerStations")?.value ?? []), + [] as string[] + ); + this.stations = this.stations.map((i) => { + i["disabled"] = false; + if (allStation.some((s) => s === i.value)) { + if (!currentInfoStations.some((s) => s === i.value)) { + i["disabled"] = true; + } + } + return i; + }); + } + + onSubmit() { + if (Utils.validateFormGroup(this.formGroup)) { + this.submitLoading = true; + this.api + .saveSyetemInfo(this.formGroup.value.infos) + .pipe( + finalize(() => { + this.submitLoading = false; + }) + ) + .subscribe((res) => { + this.msg.success(res.desc); + this.getInfo(); + }); + } + } +} diff --git a/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.html b/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.html new file mode 100644 index 0000000..3516a87 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.html @@ -0,0 +1,182 @@ + + +
+ + + + + + + + + + 应用电站 + + + + + + + + + + + 主题色 + + + + + + + + + 主题色文字颜色 + + + + + + + + + 背景颜色 + + + + + + + + + 边框颜色 + + + + + + + + + 顶部菜单背景色 + + + + + + + + + 系统标题颜色 + + + + + + + + 文字颜色 + + + + + + + + + 描述文字颜色 + + + + + + + + + 表头背景色 + + + + + + + + + 标签背景色 + + + + + + + + + 标签文字颜色 + + + + + + + + + 卡片文字颜色 + + + + + + + + 卡片头部背景色 + + + + + + + + 卡片角颜色 + + + + + + + + + + + + +
+ +
+ + +
+
+
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.less b/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.ts b/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.ts new file mode 100644 index 0000000..032c6c6 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/system-theme/system-theme.component.ts @@ -0,0 +1,141 @@ +import { Component, OnInit } from "@angular/core"; +import { FormArray, FormBuilder, FormGroup } from "@angular/forms"; +import { AnyObject } from "@cdk/types"; +import { Utils } from "@cdk/utils"; +import { DecValidators } from "@cdk/validators"; +import { ManageApiService } from "@manage/app/core/services"; +import { OptionItemInterface } from "@manage/dtos"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { finalize, lastValueFrom } from "rxjs"; + +@Component({ + selector: "app-system-theme", + templateUrl: "./system-theme.component.html", + styleUrls: ["./system-theme.component.less"], +}) +export class SystemThemeComponent { + constructor( + private fb: FormBuilder, + private api: ManageApiService, + private msg: NzMessageService, + private modal: NzModalService + ) {} + + formGroup!: FormGroup; + + public get themes(): FormArray { + return this.formGroup.get("themes") as FormArray; + } + + stations: OptionItemInterface[] = []; + + loading = true; + + submitLoading = false; + + ngOnInit(): void { + this.api.getAllStation().subscribe((res) => { + this.stations = res; + }); + this.getThemes(); + this.formGroup = this.fb.group({ + themes: this.fb.array([]), + }); + } + + getThemes() { + this.api + .getSystemThemes() + .pipe( + finalize(() => { + this.loading = false; + }) + ) + .subscribe((res) => { + if (Array.isArray(res.body)) { + this.themes.clear(); + res.body.forEach((i) => { + this.newTheme(i); + }); + } + }); + } + + newTheme(v?: AnyObject) { + const powerStations = (v?.["powerStationList"] ?? []) as AnyObject[]; + const powerStationsVal = powerStations.map((i) => i["powerStationId"]); + + const themeGroup = this.fb.group({ + themeId: this.fb.control(v?.["themeId"]), + powerStationList: this.fb.control(powerStationsVal), + themeName: this.fb.control(v?.["themeName"] ?? ""), + + primary: this.fb.control(v?.["primary"] ?? "rgba(255,255,255,1)"), + primary_btn_color: this.fb.control(v?.["primary_btn_color"] ?? "rgba(255,255,255,1)"), + bg_color: this.fb.control(v?.["bg_color"] ?? "rgba(255,255,255,1)"), + border_color: this.fb.control(v?.["border_color"] ?? "rgba(255,255,255,1)"), + title_color: this.fb.control(v?.["title_color"] ?? "rgba(255,255,255,1)"), + nav_bg: this.fb.control(v?.["nav_bg"] ?? "rgba(255,255,255,1)"), + text_color: this.fb.control(v?.["text_color"] ?? "rgba(255,255,255,1)"), + desc_color: this.fb.control(v?.["desc_color"] ?? "rgba(255,255,255,1)"), + thead_bg: this.fb.control(v?.["thead_bg"] ?? "rgba(255,255,255,1)"), + tag_bg: this.fb.control(v?.["tag_bg"] ?? "rgba(255,255,255,1)"), + tag_color: this.fb.control(v?.["tag_color"] ?? "rgba(255,255,255,1)"), + card_text_color: this.fb.control(v?.["card_text_color"] ?? "rgba(255,255,255,1)"), + card_hd_bg_color: this.fb.control(v?.["card_hd_bg_color"] ?? "rgba(255,255,255,1)"), + corner_color: this.fb.control(v?.["corner_color"] ?? "rgba(255,255,255,1)"), + }); + this.themes.push(themeGroup); + return themeGroup; + } + + deleteItem(idx: number) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该主题策略?", + nzOnOk: async () => { + const themeId: string = this.themes.at(idx).get("systemInfoId")?.value; + if (themeId) { + await lastValueFrom(this.api.deleteOneofTheme(themeId)); + } + this.themes.removeAt(idx); + this.msg.success("删除成功"); + }, + }); + } + + onSelectOpen(idx: number) { + const currentInfoStations = (this.themes.at(idx).get("powerStationList")?.value ?? []) as string[]; + const allStation = this.themes.controls.reduce( + (a, c) => a.concat(c.get("powerStationList")?.value ?? []), + [] as string[] + ); + this.stations = this.stations.map((i) => { + i["disabled"] = false; + if (allStation.some((s) => s === i.value)) { + if (!currentInfoStations.some((s) => s === i.value)) { + i["disabled"] = true; + } + } + return i; + }); + } + + onSubmit() { + if (Utils.validateFormGroup(this.formGroup)) { + this.submitLoading = true; + this.api + .saveSyetemTheme(this.formGroup.value.themes) + .pipe( + finalize(() => { + this.submitLoading = false; + }) + ) + .subscribe((res) => { + this.msg.success(res.desc); + this.getThemes(); + }); + } + } +} diff --git a/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.html b/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.html new file mode 100644 index 0000000..b8b38f4 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.html @@ -0,0 +1,30 @@ + + +
+
+ +
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + +
\ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.less b/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.ts b/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.ts new file mode 100644 index 0000000..0de0702 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/user/permission/permission.component.ts @@ -0,0 +1,172 @@ +import { ManageApiService } from "@manage/app/core/services"; +import { Component, Input, OnChanges, OnInit, SimpleChanges } from "@angular/core"; +import { OptionItemInterface } from "@manage/dtos"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { finalize } from "rxjs"; + +const defaultAllPermissions = [ + { + permissionId: "role_powerstation", + permissionName: "电站管理", + value: true, + scope: 1, //0-前端页面,1-后台管理 + }, + { + permissionId: "role_motorgroup", + permissionName: "机组管理", + value: true, + scope: 1, + }, + { + permissionId: "role_point", + permissionName: "检测点管理", + value: true, + scope: 1, + }, + { + permissionId: "role_device_camer_plc", + permissionName: "设备管理-相机/PLC管理", + value: true, + scope: 1, + }, + { + permissionId: "role_device_tempsensor", + permissionName: "设备管理-测温传感器管理", + value: true, + scope: 1, + }, + { + permissionId: "role_algorithm", + permissionName: "算法模型管理", + value: true, + scope: 1, + }, + { + permissionId: "role_sys_info", + permissionName: "系统管理-系统信息管理", + value: true, + scope: 1, + }, + { + permissionId: "role_sys_theme", + permissionName: "系统管理-主题管理", + value: true, + scope: 1, + }, + { + permissionId: "role_sys_user", + permissionName: "系统管理-用户管理", + value: true, + scope: 1, + }, + { + permissionId: "role_pole", + permissionName: "检测页面", + value: true, + scope: 0, + }, + { + permissionId: "role_history", + permissionName: "历史数据", + value: true, + scope: 0, + }, + { + permissionId: "role_analysis", + permissionName: "数据分析", + value: true, + scope: 0, + }, + { + permissionId: "role_settings_show", + permissionName: "高级设置-检测点检测管理", + value: true, + scope: 0, + }, + { + permissionId: "role_settings_bolt", + permissionName: "高级设置-检测算法设置", + value: true, + scope: 0, + }, + { + permissionId: "role_settings_temp", + permissionName: "高级设置-工作保护温度设置", + value: true, + scope: 0, + }, + { + permissionId: "role_settings_sys", + permissionName: "高级设置-系统设置", + value: true, + scope: 0, + }, +]; + +export type PermissionItmeInterface = (typeof defaultAllPermissions)[number]; + +@Component({ + selector: "app-permission", + templateUrl: "./permission.component.html", + styleUrls: ["./permission.component.less"], +}) +export class PermissionComponent implements OnInit, OnChanges { + constructor(private api: ManageApiService, private msg: NzMessageService) {} + + @Input() role: any; + + public permissions: PermissionItmeInterface[] = defaultAllPermissions; + + public client: PermissionItmeInterface[] = []; + + public manage: PermissionItmeInterface[] = []; + + submitLoading = false; + + ngOnInit(): void { + this.permissions.forEach((i) => { + if (i.scope === 0) { + this.client.push(i); + } else { + this.manage.push(i); + } + }); + } + + getPermission() { + this.api.getRolePermissions(this.role.roleId).subscribe((res) => { + if (Array.isArray(res.body)) { + this.client = []; + this.manage = []; + this.permissions.forEach((i) => { + const item = res.body.find((f) => f.permissionId === i.permissionId && i.scope === f.scope) ?? i; + if (i.scope === 0) { + this.client.push(item); + } else { + this.manage.push(item); + } + }); + } + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes["role"]?.currentValue) { + this.getPermission(); + } + } + + onSave() { + this.submitLoading = true; + this.api + .updateRolePermission(this.role.roleId, this.client.concat(this.manage)) + .pipe( + finalize(() => { + this.submitLoading = false; + }) + ) + .subscribe((res) => { + this.msg.success(res.desc); + }); + } +} diff --git a/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.html b/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.html new file mode 100644 index 0000000..feedb10 --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.html @@ -0,0 +1,20 @@ + + + + + + + + + + 姓名 + + + + + + + \ No newline at end of file diff --git a/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.less b/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.less new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.ts b/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.ts new file mode 100644 index 0000000..b9f83db --- /dev/null +++ b/projects/manage/src/app/feature/manage/pages/system/user/user-list/user-list.component.ts @@ -0,0 +1,105 @@ +import { Component, Input, OnInit, SimpleChanges } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; +import { Router } from "@angular/router"; +import { TableListOption } from "@cdk/table-list"; +import { AnyObject } from "@cdk/types"; +import { ManageApiService } from "@manage/app/core/services"; +import { UserRoleDTO } from "@manage/dtos"; +import { format } from "date-fns"; +import { NzMessageService } from "ng-zorro-antd/message"; +import { NzModalService } from "ng-zorro-antd/modal"; +import { lastValueFrom } from "rxjs"; +import { UserFormComponent } from "../../../../components"; + +@Component({ + selector: "app-user-list", + templateUrl: "./user-list.component.html", + styleUrls: ["./user-list.component.less"], +}) +export class UserListComponent { + constructor( + private api: ManageApiService, + private router: Router, + private modal: NzModalService, + private msg: NzMessageService + ) {} + + @Input() role!: UserRoleDTO; + + public tableList = new TableListOption(this.fetchData.bind(this), { + manual: true, + }); + + public queryForm = new FormGroup({ + userName: new FormControl(""), + }); + + ngOnInit(): void { + this.initTableList(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes["role"]?.currentValue) { + this.tableList.run(); + } + } + + fetchData(query: AnyObject, pager: AnyObject) { + query["role"] = this.role.roleId; + return this.api.getUserPage(query, pager); + } + + initTableList() { + this.tableList.scroll = { x: null }; + this.tableList = this.tableList.setColumns([ + { key: "uid", title: "用户" }, + { key: "userName", title: "姓名" }, + { key: "role", title: "角色" }, + { key: "gmtCreate", title: "添加时间" }, + ]); + + this.tableList = this.tableList.setOptions([ + { + title: "编辑", + premissions: [], + onClick: this.openForm.bind(this), + }, + { + title: "删除", + premissions: [], + onClick: this.deleteItem.bind(this), + }, + ]); + } + + deleteItem(v: any) { + this.modal.confirm({ + nzTitle: "警告", + nzContent: "是否要删除该用户?", + nzOnOk: async () => { + await lastValueFrom(this.api.deleteUser(v.uid!)); + this.tableList.run(); + this.msg.success("删除成功"); + }, + }); + } + + openForm(v?: any) { + this.modal.create({ + nzTitle: v ? "编辑用户" : "新增用户", + nzContent: UserFormComponent, + nzComponentParams: { value: v }, + nzOnOk: async (e) => { + const value = e.getValues(); + if (value) { + const vals = Object.assign({}, value, { role: this.role.roleId! }); + await lastValueFrom(this.api.saveUser(vals)); + this.msg.success("保存成功"); + this.tableList.run(); + return true; + } + return false; + }, + }); + } +} diff --git a/projects/manage/src/app/icons-provider.module.ts b/projects/manage/src/app/icons-provider.module.ts new file mode 100644 index 0000000..8096966 --- /dev/null +++ b/projects/manage/src/app/icons-provider.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { NZ_ICONS, NzIconModule } from 'ng-zorro-antd/icon'; + +import { + MenuFoldOutline, + MenuUnfoldOutline, + FormOutline, + DashboardOutline +} from '@ant-design/icons-angular/icons'; + +const icons = [MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, FormOutline]; + +@NgModule({ + imports: [NzIconModule], + exports: [NzIconModule], + providers: [ + { provide: NZ_ICONS, useValue: icons } + ] +}) +export class IconsProviderModule { +} diff --git a/projects/manage/src/app/shared/components/index.ts b/projects/manage/src/app/shared/components/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/app/shared/ng-zorro.ts b/projects/manage/src/app/shared/ng-zorro.ts new file mode 100644 index 0000000..d429aee --- /dev/null +++ b/projects/manage/src/app/shared/ng-zorro.ts @@ -0,0 +1,100 @@ +import { NzGridModule } from "ng-zorro-antd/grid"; +import { NzCardModule } from "ng-zorro-antd/card"; +import { NzStatisticModule } from "ng-zorro-antd/statistic"; +import { NzIconModule } from "ng-zorro-antd/icon"; +import { NzToolTipModule } from "ng-zorro-antd/tooltip"; +import { NzTableModule } from "ng-zorro-antd/table"; +import { NzSegmentedModule } from "ng-zorro-antd/segmented"; +import { NzSpaceModule } from "ng-zorro-antd/space"; +import { NzDatePickerModule } from "ng-zorro-antd/date-picker"; +import { NzListModule } from "ng-zorro-antd/list"; +import { NzInputModule } from "ng-zorro-antd/input"; +import { NzButtonModule } from "ng-zorro-antd/button"; +import { NzTagModule } from "ng-zorro-antd/tag"; +import { NzBadgeModule } from "ng-zorro-antd/badge"; +import { NzPaginationModule } from "ng-zorro-antd/pagination"; +import { NzDividerModule } from "ng-zorro-antd/divider"; +import { NzSelectModule } from "ng-zorro-antd/select"; +import { NzModalModule } from "ng-zorro-antd/modal"; +import { NzMessageModule } from "ng-zorro-antd/message"; +import { NzDrawerModule } from "ng-zorro-antd/drawer"; +import { NzFormModule } from "ng-zorro-antd/form"; +import { NzDescriptionsModule } from "ng-zorro-antd/descriptions"; +import { NzTabsModule } from "ng-zorro-antd/tabs"; +import { NzProgressModule } from "ng-zorro-antd/progress"; +import { NzAvatarModule } from "ng-zorro-antd/avatar"; +import { NzMenuModule } from "ng-zorro-antd/menu"; +import { NzDropDownModule } from "ng-zorro-antd/dropdown"; +import { NzTreeSelectModule } from "ng-zorro-antd/tree-select"; +import { NzRadioModule } from "ng-zorro-antd/radio"; +import { NzCheckboxModule } from "ng-zorro-antd/checkbox"; +import { NzCalendarModule } from "ng-zorro-antd/calendar"; +import { NzSkeletonModule } from "ng-zorro-antd/skeleton"; +import { NzTimelineModule } from "ng-zorro-antd/timeline"; +import { NzEmptyModule } from "ng-zorro-antd/empty"; +import { NzSpinModule } from "ng-zorro-antd/spin"; +import { NzResultModule } from "ng-zorro-antd/result"; +import { NzCascaderModule } from "ng-zorro-antd/cascader"; +import { NzAutocompleteModule } from "ng-zorro-antd/auto-complete"; +import { NzPopoverModule } from "ng-zorro-antd/popover"; +import { NzPageHeaderModule } from "ng-zorro-antd/page-header"; +import { NzTreeModule } from "ng-zorro-antd/tree"; +import { NzSwitchModule } from "ng-zorro-antd/switch"; +import { NzCarouselModule } from "ng-zorro-antd/carousel"; +import { NzTimePickerModule } from "ng-zorro-antd/time-picker"; +import { NzImageModule } from "ng-zorro-antd/image"; +import { NzInputNumberModule } from "ng-zorro-antd/input-number"; +import { NzLayoutModule } from "ng-zorro-antd/layout"; +import { NzBreadCrumbModule } from "ng-zorro-antd/breadcrumb"; + +export const ngZorroModules = [ + NzBreadCrumbModule, + NzLayoutModule, + NzInputNumberModule, + NzImageModule, + NzTimePickerModule, + NzCarouselModule, + NzSwitchModule, + NzTreeModule, + NzPageHeaderModule, + NzPopoverModule, + NzAutocompleteModule, + NzCascaderModule, + NzResultModule, + NzSpinModule, + NzGridModule, + NzCardModule, + NzStatisticModule, + NzIconModule, + NzToolTipModule, + NzTableModule, + NzSegmentedModule, + NzSpaceModule, + NzDatePickerModule, + NzListModule, + NzInputModule, + NzButtonModule, + NzTagModule, + NzBadgeModule, + NzPaginationModule, + NzDividerModule, + NzSelectModule, + NzSelectModule, + NzModalModule, + NzMessageModule, + NzDrawerModule, + NzFormModule, + NzDescriptionsModule, + NzTabsModule, + NzProgressModule, + NzAvatarModule, + NzMenuModule, + NzDropDownModule, + NzTreeSelectModule, + NzRadioModule, + NzCalendarModule, + NzCheckboxModule, + NzSkeletonModule, + NzTimelineModule, + NzEmptyModule, +]; diff --git a/projects/manage/src/app/shared/shared.module.ts b/projects/manage/src/app/shared/shared.module.ts new file mode 100644 index 0000000..56fdc0d --- /dev/null +++ b/projects/manage/src/app/shared/shared.module.ts @@ -0,0 +1,38 @@ +import { RouterModule } from "@angular/router"; +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { HttpClientModule } from "@angular/common/http"; +import { ngZorroModules } from "./ng-zorro"; +// import { AuthorizationLayoutComponent, BgBorderComponent } from "./components"; +// import { DecCornerDirective } from "./directives"; +import { + DecModule, + FormErrorTipsComponent, + InputSpaceErrorDirective, + PublicPathPipe, + TableListModule, + StorageModule, + QuickDateRangeComponent, +} from "@cdk/public-api"; +import { environment } from "@manage/environments/environment"; +import { NgxPermissionsModule } from "ngx-permissions"; + +const ngModules = [CommonModule, HttpClientModule, FormsModule, RouterModule, ReactiveFormsModule]; +const components: any = []; +const directives: any[] = []; +const cdks = [ + FormErrorTipsComponent, + InputSpaceErrorDirective, + PublicPathPipe, + TableListModule, + StorageModule, + QuickDateRangeComponent, +]; + +@NgModule({ + declarations: [...components, ...directives], + imports: [DecModule, ...ngZorroModules, ...ngModules, ...cdks], + exports: [...ngZorroModules, ...ngModules, ...components, ...directives, ...cdks], +}) +export class SharedModule {} diff --git a/projects/manage/src/assets/.gitkeep b/projects/manage/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/projects/manage/src/assets/imgs/bg.jpg b/projects/manage/src/assets/imgs/bg.jpg new file mode 100644 index 0000000..31bed57 Binary files /dev/null and b/projects/manage/src/assets/imgs/bg.jpg differ diff --git a/projects/manage/src/assets/imgs/logo.png b/projects/manage/src/assets/imgs/logo.png new file mode 100644 index 0000000..926913b Binary files /dev/null and b/projects/manage/src/assets/imgs/logo.png differ diff --git a/projects/manage/src/dtos/index.ts b/projects/manage/src/dtos/index.ts new file mode 100644 index 0000000..03a3989 --- /dev/null +++ b/projects/manage/src/dtos/index.ts @@ -0,0 +1,33 @@ +import { Augmented } from "@cdk/types"; + +export type OptionItemInterface = Augmented<{ + /** + * 名称 + */ + label: string; + /** + * 类型 + */ + type?: string | number; + /** + * 值 + */ + value: number | string; +}>; + +export type UserRoleDTO = Augmented<{ + roleId?: number; + isRoot?: boolean; + roleName: string; +}>; + +/** + * User + */ +export type UserDTO = Augmented<{ + uid: string; + userId: string; + gmtCreate: string; + name: string; + role: string; +}>; diff --git a/projects/manage/src/environments/environment.prod.ts b/projects/manage/src/environments/environment.prod.ts new file mode 100644 index 0000000..744b0c6 --- /dev/null +++ b/projects/manage/src/environments/environment.prod.ts @@ -0,0 +1,6 @@ +export const environment = { + production: true, + clientVersion: "1.0.0", + clientType: "web", + host: "http://47.109.27.8", +}; diff --git a/projects/manage/src/environments/environment.ts b/projects/manage/src/environments/environment.ts new file mode 100644 index 0000000..53a3573 --- /dev/null +++ b/projects/manage/src/environments/environment.ts @@ -0,0 +1,20 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false, + clientVersion: "1.0.0", + clientType: "web", + host: "http://47.109.27.8", + mock: true, +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/plugins/zone-error'; // Included with Angular CLI. diff --git a/projects/manage/src/favicon.ico b/projects/manage/src/favicon.ico new file mode 100644 index 0000000..b25db3a Binary files /dev/null and b/projects/manage/src/favicon.ico differ diff --git a/projects/manage/src/index.html b/projects/manage/src/index.html new file mode 100644 index 0000000..5136003 --- /dev/null +++ b/projects/manage/src/index.html @@ -0,0 +1,68 @@ + + + + + + 东方电气 · 转子检测监控管理系统 + + + + + + + +
+
+
+ +
+

+ 加载中... +

+
+
+ + + + + + \ No newline at end of file diff --git a/projects/manage/src/main.ts b/projects/manage/src/main.ts new file mode 100644 index 0000000..4e0605c --- /dev/null +++ b/projects/manage/src/main.ts @@ -0,0 +1,8 @@ +import { platformBrowserDynamic } from "@angular/platform-browser-dynamic"; + +import { AppModule } from "./app/app.module"; +import { environment } from "./environments/environment"; + +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.error(err)); diff --git a/projects/manage/src/styles.less b/projects/manage/src/styles.less new file mode 100644 index 0000000..5def5d5 --- /dev/null +++ b/projects/manage/src/styles.less @@ -0,0 +1,43 @@ +// Custom Theming for NG-ZORRO +// For more information: https://ng.ant.design/docs/customize-theme/en +@import "../../../node_modules/ng-zorro-antd/ng-zorro-antd.less"; + +// Override less variables to here +// View all variables: https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/components/style/themes/default.less + +// @primary-color: #1890ff; +/* You can add global styles to this file, and also import other style files */ + +@tailwind utilities; + +:root { + --p: @primary-color; + --p-rgb: 24 144 255; + + --border-color: #e8e8e8; +} + +.danger-confirm { + .ant-modal-confirm-content { + color: red; + } +} + +.upload-btn { + position: relative; + + input { + display: block; + height: 100%; + background-color: red; + position: absolute; + inset: 0; + opacity: 0; + font-size: 0; + cursor: pointer; + } +} + +.footer-wapper { + border-top: 1px solid #e8e8e8; +} \ No newline at end of file diff --git a/projects/manage/tsconfig.app.json b/projects/manage/tsconfig.app.json new file mode 100644 index 0000000..e4e0762 --- /dev/null +++ b/projects/manage/tsconfig.app.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/projects/manage/tsconfig.spec.json b/projects/manage/tsconfig.spec.json new file mode 100644 index 0000000..a9c0752 --- /dev/null +++ b/projects/manage/tsconfig.spec.json @@ -0,0 +1,14 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..4ea57b3 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./projects/**/*.{html,ts}"], + theme: { + extend: {}, + }, + plugins: [], +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..634614d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,45 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@cdk/*": [ + "./projects/cdk/src/*", + "dist/cdk", + ], + "@client/*": [ + "./projects/client/src/*", + ], + "@manage/*": [ + "./projects/manage/src/*", + ], + }, + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "ES2022", + "module": "ES2022", + "useDefineForClassFields": false, + "lib": [ + "ES2022", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} \ No newline at end of file