feat: 改进api生成方式
This commit is contained in:
		
							
								
								
									
										300
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										300
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -40,10 +40,13 @@
 | 
			
		||||
        "@vue/tsconfig": "^0.7.0",
 | 
			
		||||
        "autoprefixer": "^10.4.20",
 | 
			
		||||
        "daisyui": "^5.0.0",
 | 
			
		||||
        "node-fetch": "^3.3.2",
 | 
			
		||||
        "npm-run-all2": "^7.0.2",
 | 
			
		||||
        "nswag": "^14.3.0",
 | 
			
		||||
        "postcss": "^8.5.3",
 | 
			
		||||
        "tailwindcss": "^4.0.12",
 | 
			
		||||
        "ts-node": "^10.9.2",
 | 
			
		||||
        "tsx": "^4.20.3",
 | 
			
		||||
        "typescript": "~5.7.3",
 | 
			
		||||
        "unplugin-vue-components": "^28.8.0",
 | 
			
		||||
        "vite": "^6.1.0",
 | 
			
		||||
@@ -542,6 +545,30 @@
 | 
			
		||||
        "node": ">=6.9.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@cspotcode/source-map-support": {
 | 
			
		||||
      "version": "0.8.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
 | 
			
		||||
      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jridgewell/trace-mapping": "0.3.9"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=12"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
 | 
			
		||||
      "version": "0.3.9",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
 | 
			
		||||
      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jridgewell/resolve-uri": "^3.0.3",
 | 
			
		||||
        "@jridgewell/sourcemap-codec": "^1.4.10"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@esbuild/aix-ppc64": {
 | 
			
		||||
      "version": "0.25.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz",
 | 
			
		||||
@@ -1742,6 +1769,34 @@
 | 
			
		||||
        "vue": "^2.7.0 || ^3.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@tsconfig/node10": {
 | 
			
		||||
      "version": "1.0.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
 | 
			
		||||
      "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@tsconfig/node12": {
 | 
			
		||||
      "version": "1.0.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
 | 
			
		||||
      "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@tsconfig/node14": {
 | 
			
		||||
      "version": "1.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@tsconfig/node16": {
 | 
			
		||||
      "version": "1.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@tsconfig/node22": {
 | 
			
		||||
      "version": "22.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.1.tgz",
 | 
			
		||||
@@ -2181,6 +2236,19 @@
 | 
			
		||||
        "node": ">=0.4.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/acorn-walk": {
 | 
			
		||||
      "version": "8.3.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
 | 
			
		||||
      "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "acorn": "^8.11.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.4.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/alien-signals": {
 | 
			
		||||
      "version": "1.0.13",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz",
 | 
			
		||||
@@ -2228,6 +2296,13 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/jonschlinkert"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/arg": {
 | 
			
		||||
      "version": "4.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/aria-hidden": {
 | 
			
		||||
      "version": "1.2.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
 | 
			
		||||
@@ -2476,6 +2551,13 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/mesqueeb"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/create-require": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/cross-spawn": {
 | 
			
		||||
      "version": "7.0.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
 | 
			
		||||
@@ -2530,6 +2612,16 @@
 | 
			
		||||
        "url": "https://github.com/saadeghi/daisyui?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/data-uri-to-buffer": {
 | 
			
		||||
      "version": "4.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 12"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/de-indent": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
 | 
			
		||||
@@ -2620,6 +2712,16 @@
 | 
			
		||||
        "node": ">=8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/diff": {
 | 
			
		||||
      "version": "4.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "BSD-3-Clause",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.3.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/echarts": {
 | 
			
		||||
      "version": "5.6.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
 | 
			
		||||
@@ -2791,6 +2893,30 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/fetch-blob": {
 | 
			
		||||
      "version": "3.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "funding": [
 | 
			
		||||
        {
 | 
			
		||||
          "type": "github",
 | 
			
		||||
          "url": "https://github.com/sponsors/jimmywarting"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "paypal",
 | 
			
		||||
          "url": "https://paypal.me/jimmywarting"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "node-domexception": "^1.0.0",
 | 
			
		||||
        "web-streams-polyfill": "^3.0.3"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^12.20 || >= 14.13"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/figures": {
 | 
			
		||||
      "version": "6.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
 | 
			
		||||
@@ -2820,6 +2946,19 @@
 | 
			
		||||
        "node": ">=8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/formdata-polyfill": {
 | 
			
		||||
      "version": "4.0.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
 | 
			
		||||
      "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "fetch-blob": "^3.1.2"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=12.20.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/fraction.js": {
 | 
			
		||||
      "version": "4.3.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
 | 
			
		||||
@@ -2891,6 +3030,19 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/get-tsconfig": {
 | 
			
		||||
      "version": "4.10.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
 | 
			
		||||
      "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "resolve-pkg-maps": "^1.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/glob-parent": {
 | 
			
		||||
      "version": "5.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
 | 
			
		||||
@@ -3519,6 +3671,13 @@
 | 
			
		||||
        "@jridgewell/sourcemap-codec": "^1.5.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/make-error": {
 | 
			
		||||
      "version": "1.3.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
 | 
			
		||||
      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "ISC"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/marked": {
 | 
			
		||||
      "version": "12.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz",
 | 
			
		||||
@@ -3672,6 +3831,46 @@
 | 
			
		||||
        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/node-domexception": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
 | 
			
		||||
      "deprecated": "Use your platform's native DOMException instead",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "funding": [
 | 
			
		||||
        {
 | 
			
		||||
          "type": "github",
 | 
			
		||||
          "url": "https://github.com/sponsors/jimmywarting"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "type": "github",
 | 
			
		||||
          "url": "https://paypal.me/jimmywarting"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10.5.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/node-fetch": {
 | 
			
		||||
      "version": "3.3.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
 | 
			
		||||
      "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "data-uri-to-buffer": "^4.0.0",
 | 
			
		||||
        "fetch-blob": "^3.1.4",
 | 
			
		||||
        "formdata-polyfill": "^4.0.10"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "type": "opencollective",
 | 
			
		||||
        "url": "https://opencollective.com/node-fetch"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/node-releases": {
 | 
			
		||||
      "version": "2.0.19",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
 | 
			
		||||
@@ -4065,6 +4264,16 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/antfu"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/resolve-pkg-maps": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/rfdc": {
 | 
			
		||||
      "version": "1.4.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
 | 
			
		||||
@@ -4316,6 +4525,50 @@
 | 
			
		||||
      "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==",
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ts-node": {
 | 
			
		||||
      "version": "10.9.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
 | 
			
		||||
      "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@cspotcode/source-map-support": "^0.8.0",
 | 
			
		||||
        "@tsconfig/node10": "^1.0.7",
 | 
			
		||||
        "@tsconfig/node12": "^1.0.7",
 | 
			
		||||
        "@tsconfig/node14": "^1.0.0",
 | 
			
		||||
        "@tsconfig/node16": "^1.0.2",
 | 
			
		||||
        "acorn": "^8.4.1",
 | 
			
		||||
        "acorn-walk": "^8.1.1",
 | 
			
		||||
        "arg": "^4.1.0",
 | 
			
		||||
        "create-require": "^1.1.0",
 | 
			
		||||
        "diff": "^4.0.1",
 | 
			
		||||
        "make-error": "^1.1.1",
 | 
			
		||||
        "v8-compile-cache-lib": "^3.0.1",
 | 
			
		||||
        "yn": "3.1.1"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "ts-node": "dist/bin.js",
 | 
			
		||||
        "ts-node-cwd": "dist/bin-cwd.js",
 | 
			
		||||
        "ts-node-esm": "dist/bin-esm.js",
 | 
			
		||||
        "ts-node-script": "dist/bin-script.js",
 | 
			
		||||
        "ts-node-transpile-only": "dist/bin-transpile.js",
 | 
			
		||||
        "ts-script": "dist/bin-script-deprecated.js"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "@swc/core": ">=1.2.50",
 | 
			
		||||
        "@swc/wasm": ">=1.2.50",
 | 
			
		||||
        "@types/node": "*",
 | 
			
		||||
        "typescript": ">=2.7"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependenciesMeta": {
 | 
			
		||||
        "@swc/core": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        },
 | 
			
		||||
        "@swc/wasm": {
 | 
			
		||||
          "optional": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ts-results-es": {
 | 
			
		||||
      "version": "5.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ts-results-es/-/ts-results-es-5.0.1.tgz",
 | 
			
		||||
@@ -4328,6 +4581,26 @@
 | 
			
		||||
      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
 | 
			
		||||
      "license": "0BSD"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/tsx": {
 | 
			
		||||
      "version": "4.20.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz",
 | 
			
		||||
      "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "esbuild": "~0.25.0",
 | 
			
		||||
        "get-tsconfig": "^4.7.5"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "tsx": "dist/cli.mjs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=18.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "optionalDependencies": {
 | 
			
		||||
        "fsevents": "~2.3.3"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/typed-function": {
 | 
			
		||||
      "version": "4.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz",
 | 
			
		||||
@@ -4487,6 +4760,13 @@
 | 
			
		||||
        "browserslist": ">= 4.21.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/v8-compile-cache-lib": {
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/vite": {
 | 
			
		||||
      "version": "6.3.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
 | 
			
		||||
@@ -4789,6 +5069,16 @@
 | 
			
		||||
        "typescript": ">=5.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/web-streams-polyfill": {
 | 
			
		||||
      "version": "3.3.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
 | 
			
		||||
      "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 8"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/webpack-virtual-modules": {
 | 
			
		||||
      "version": "0.6.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
 | 
			
		||||
@@ -4819,6 +5109,16 @@
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "ISC"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/yn": {
 | 
			
		||||
      "version": "3.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/yocto-queue": {
 | 
			
		||||
      "version": "1.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz",
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,7 @@
 | 
			
		||||
    "preview": "vite preview",
 | 
			
		||||
    "build-only": "vite build",
 | 
			
		||||
    "type-check": "vue-tsc --build",
 | 
			
		||||
    "pregen-api": "cd server && dotnet run --property:Configuration=Release &",
 | 
			
		||||
    "gen-api": "npx nswag openapi2tsclient /input:http://localhost:5000/swagger/v1/swagger.json /output:src/APIClient.ts",
 | 
			
		||||
    "postgen-api": "pkill server"
 | 
			
		||||
    "gen-api": "npx tsx scripts/GenerateWebAPI.ts"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@svgdotjs/svg.js": "^3.2.4",
 | 
			
		||||
@@ -46,10 +44,13 @@
 | 
			
		||||
    "@vue/tsconfig": "^0.7.0",
 | 
			
		||||
    "autoprefixer": "^10.4.20",
 | 
			
		||||
    "daisyui": "^5.0.0",
 | 
			
		||||
    "node-fetch": "^3.3.2",
 | 
			
		||||
    "npm-run-all2": "^7.0.2",
 | 
			
		||||
    "nswag": "^14.3.0",
 | 
			
		||||
    "postcss": "^8.5.3",
 | 
			
		||||
    "tailwindcss": "^4.0.12",
 | 
			
		||||
    "ts-node": "^10.9.2",
 | 
			
		||||
    "tsx": "^4.20.3",
 | 
			
		||||
    "typescript": "~5.7.3",
 | 
			
		||||
    "unplugin-vue-components": "^28.8.0",
 | 
			
		||||
    "vite": "^6.1.0",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										335
									
								
								scripts/GenerateWebAPI.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								scripts/GenerateWebAPI.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,335 @@
 | 
			
		||||
import { spawn, exec, ChildProcess } from 'child_process';
 | 
			
		||||
import { promisify } from 'util';
 | 
			
		||||
import fetch from 'node-fetch';
 | 
			
		||||
 | 
			
		||||
const execAsync = promisify(exec);
 | 
			
		||||
 | 
			
		||||
async function waitForServer(url: string, maxRetries: number = 30, interval: number = 1000): Promise<boolean> {
 | 
			
		||||
  for (let i = 0; i < maxRetries; i++) {
 | 
			
		||||
    try {
 | 
			
		||||
      const response = await fetch(url);
 | 
			
		||||
      if (response.ok) {
 | 
			
		||||
        console.log('✓ Server is ready');
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      // Server not ready yet
 | 
			
		||||
    }
 | 
			
		||||
    console.log(`Waiting for server... (${i + 1}/${maxRetries})`);
 | 
			
		||||
    await new Promise(resolve => setTimeout(resolve, interval));
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 改进全局变量类型
 | 
			
		||||
let serverProcess: ChildProcess | null = null;
 | 
			
		||||
let webProcess: ChildProcess | null = null;
 | 
			
		||||
 | 
			
		||||
async function startWeb(): Promise<ChildProcess> {
 | 
			
		||||
  console.log('Starting Vite frontend...');
 | 
			
		||||
  return new Promise((resolve, reject) => {
 | 
			
		||||
    const process = spawn('npm', ['run', 'dev'], {
 | 
			
		||||
      stdio: 'pipe'
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let webStarted = false;
 | 
			
		||||
 | 
			
		||||
    process.stdout?.on('data', (data) => {
 | 
			
		||||
      const output = data.toString();
 | 
			
		||||
      console.log(`Web: ${output}`);
 | 
			
		||||
      
 | 
			
		||||
      // 检查 Vite 是否已启动
 | 
			
		||||
      if ((output.includes('Local:') || output.includes('ready in')) && !webStarted) {
 | 
			
		||||
        webStarted = true;
 | 
			
		||||
        resolve(process);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    process.stderr?.on('data', (data) => {
 | 
			
		||||
      console.error(`Web Error: ${data}`);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    process.on('error', (error) => {
 | 
			
		||||
      reject(error);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    process.on('exit', (code, signal) => {
 | 
			
		||||
      console.log(`Web process exited with code ${code} and signal ${signal}`);
 | 
			
		||||
      if (!webStarted) {
 | 
			
		||||
        reject(new Error(`Web process exited unexpectedly with code ${code}`));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 存储进程引用
 | 
			
		||||
    webProcess = process;
 | 
			
		||||
    
 | 
			
		||||
    // 超时处理
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      if (!webStarted) {
 | 
			
		||||
        reject(new Error('Web server failed to start within timeout'));
 | 
			
		||||
      }
 | 
			
		||||
    }, 30000); // 30秒超时
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function startServer(): Promise<ChildProcess> {
 | 
			
		||||
  console.log('Starting .NET server...');
 | 
			
		||||
  return new Promise((resolve, reject) => {
 | 
			
		||||
    const process = spawn('dotnet', ['run', '--property:Configuration=Release'], {
 | 
			
		||||
      cwd: 'server',
 | 
			
		||||
      stdio: 'pipe'
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let serverStarted = false;
 | 
			
		||||
 | 
			
		||||
    process.stdout?.on('data', (data) => {
 | 
			
		||||
      const output = data.toString();
 | 
			
		||||
      console.log(`Server: ${output}`);
 | 
			
		||||
      
 | 
			
		||||
      // 检查服务器是否已启动
 | 
			
		||||
      if (output.includes('Now listening on:') && !serverStarted) {
 | 
			
		||||
        serverStarted = true;
 | 
			
		||||
        resolve(process);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    process.stderr?.on('data', (data) => {
 | 
			
		||||
      console.error(`Server Error: ${data}`);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    process.on('error', (error) => {
 | 
			
		||||
      reject(error);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    process.on('exit', (code, signal) => {
 | 
			
		||||
      console.log(`Server process exited with code ${code} and signal ${signal}`);
 | 
			
		||||
      if (!serverStarted) {
 | 
			
		||||
        reject(new Error(`Server process exited unexpectedly with code ${code}`));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 存储进程引用
 | 
			
		||||
    serverProcess = process;
 | 
			
		||||
    
 | 
			
		||||
    // 超时处理
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      if (!serverStarted) {
 | 
			
		||||
        reject(new Error('Server failed to start within timeout'));
 | 
			
		||||
      }
 | 
			
		||||
    }, 30000); // 30秒超时
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function stopServer(): Promise<void> {
 | 
			
		||||
  console.log('Stopping server...');
 | 
			
		||||
  
 | 
			
		||||
  if (!serverProcess) {
 | 
			
		||||
    console.log('No server process to stop');
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    // 检查进程是否还存在
 | 
			
		||||
    if (serverProcess.killed || serverProcess.exitCode !== null) {
 | 
			
		||||
      console.log('✓ Server process already terminated');
 | 
			
		||||
      serverProcess = null;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 发送 SIGTERM 信号
 | 
			
		||||
    const killed = serverProcess.kill('SIGTERM');
 | 
			
		||||
    if (!killed) {
 | 
			
		||||
      console.warn('Failed to send SIGTERM to server process');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 等待进程优雅退出
 | 
			
		||||
    const exitPromise = new Promise<void>((resolve) => {
 | 
			
		||||
      if (serverProcess) {
 | 
			
		||||
        serverProcess.on('exit', () => {
 | 
			
		||||
          console.log('✓ Server stopped gracefully');
 | 
			
		||||
          resolve();
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        resolve();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 设置超时,如果 5 秒内没有退出则强制终止
 | 
			
		||||
    const timeoutPromise = new Promise<void>((resolve) => {
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        if (serverProcess && !serverProcess.killed && serverProcess.exitCode === null) {
 | 
			
		||||
          console.log('Force killing server process...');
 | 
			
		||||
          serverProcess.kill('SIGKILL');
 | 
			
		||||
        }
 | 
			
		||||
        resolve();
 | 
			
		||||
      }, 5000);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await Promise.race([exitPromise, timeoutPromise]);
 | 
			
		||||
    
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.warn('Warning: Could not stop server process:', error);
 | 
			
		||||
  } finally {
 | 
			
		||||
    serverProcess = null;
 | 
			
		||||
    
 | 
			
		||||
    // 额外清理:确保没有遗留的 dotnet 进程
 | 
			
		||||
    try {
 | 
			
		||||
      if (process.platform !== 'win32') {
 | 
			
		||||
        // 只清理与我们项目相关的进程
 | 
			
		||||
        await execAsync('pkill -f "dotnet.*run.*--property:Configuration=Release"').catch(() => {
 | 
			
		||||
          // 忽略错误,可能没有匹配的进程
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (cleanupError) {
 | 
			
		||||
      // 忽略清理错误
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function stopWeb(): Promise<void> {
 | 
			
		||||
  console.log('Stopping web server...');
 | 
			
		||||
  
 | 
			
		||||
  if (!webProcess) {
 | 
			
		||||
    console.log('No web process to stop');
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    // 检查进程是否还存在
 | 
			
		||||
    if (webProcess.killed || webProcess.exitCode !== null) {
 | 
			
		||||
      console.log('✓ Web process already terminated');
 | 
			
		||||
      webProcess = null;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 发送 SIGTERM 信号
 | 
			
		||||
    const killed = webProcess.kill('SIGTERM');
 | 
			
		||||
    if (!killed) {
 | 
			
		||||
      console.warn('Failed to send SIGTERM to web process');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 等待进程优雅退出
 | 
			
		||||
    const exitPromise = new Promise<void>((resolve) => {
 | 
			
		||||
      if (webProcess) {
 | 
			
		||||
        webProcess.on('exit', () => {
 | 
			
		||||
          console.log('✓ Web server stopped gracefully');
 | 
			
		||||
          resolve();
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        resolve();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 设置超时,如果 5 秒内没有退出则强制终止
 | 
			
		||||
    const timeoutPromise = new Promise<void>((resolve) => {
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        if (webProcess && !webProcess.killed && webProcess.exitCode === null) {
 | 
			
		||||
          console.log('Force killing web process...');
 | 
			
		||||
          webProcess.kill('SIGKILL');
 | 
			
		||||
        }
 | 
			
		||||
        resolve();
 | 
			
		||||
      }, 5000);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await Promise.race([exitPromise, timeoutPromise]);
 | 
			
		||||
    
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.warn('Warning: Could not stop web process:', error);
 | 
			
		||||
  } finally {
 | 
			
		||||
    webProcess = null;
 | 
			
		||||
    
 | 
			
		||||
    // 额外清理:确保没有遗留的 npm/node 进程
 | 
			
		||||
    try {
 | 
			
		||||
      if (process.platform !== 'win32') {
 | 
			
		||||
        // 清理可能的 vite 进程
 | 
			
		||||
        await execAsync('pkill -f "vite"').catch(() => {
 | 
			
		||||
          // 忽略错误,可能没有匹配的进程
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (cleanupError) {
 | 
			
		||||
      // 忽略清理错误
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function generateApiClient(): Promise<void> {
 | 
			
		||||
  console.log('Generating API client...');
 | 
			
		||||
  try {
 | 
			
		||||
    await execAsync('npx nswag openapi2tsclient /input:http://localhost:5000/swagger/v1/swagger.json /output:src/APIClient.ts');
 | 
			
		||||
    console.log('✓ API client generated successfully');
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    throw new Error(`Failed to generate API client: ${error}`);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function main(): Promise<void> {
 | 
			
		||||
  try {
 | 
			
		||||
    // Start web frontend first
 | 
			
		||||
    await startWeb();
 | 
			
		||||
    console.log('✓ Frontend started');
 | 
			
		||||
    
 | 
			
		||||
    // Wait a bit for frontend to fully initialize
 | 
			
		||||
    await new Promise(resolve => setTimeout(resolve, 3000));
 | 
			
		||||
    
 | 
			
		||||
    // Start server
 | 
			
		||||
    await startServer();
 | 
			
		||||
    console.log('✓ Backend started');
 | 
			
		||||
    
 | 
			
		||||
    // Wait for server to be ready (给服务器额外时间完全启动)
 | 
			
		||||
    await new Promise(resolve => setTimeout(resolve, 2000));
 | 
			
		||||
    
 | 
			
		||||
    // Check if swagger endpoint is available
 | 
			
		||||
    const serverReady = await waitForServer('http://localhost:5000/swagger/v1/swagger.json');
 | 
			
		||||
    
 | 
			
		||||
    if (!serverReady) {
 | 
			
		||||
      throw new Error('Server failed to start within the expected time');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Generate API client
 | 
			
		||||
    await generateApiClient();
 | 
			
		||||
    
 | 
			
		||||
    console.log('✓ API generation completed successfully');
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('❌ Error:', error);
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
  } finally {
 | 
			
		||||
    // Always try to stop processes in order: server first, then web
 | 
			
		||||
    await stopServer();
 | 
			
		||||
    await stopWeb();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 改进的进程终止处理
 | 
			
		||||
const cleanup = async (signal: string) => {
 | 
			
		||||
  console.log(`\nReceived ${signal}, cleaning up...`);
 | 
			
		||||
  await stopServer();
 | 
			
		||||
  await stopWeb();
 | 
			
		||||
  process.exit(0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
process.on('SIGINT', () => cleanup('SIGINT'));
 | 
			
		||||
process.on('SIGTERM', () => cleanup('SIGTERM'));
 | 
			
		||||
 | 
			
		||||
// 处理未捕获的异常
 | 
			
		||||
process.on('uncaughtException', async (error) => {
 | 
			
		||||
  console.error('❌ Uncaught exception:', error);
 | 
			
		||||
  await stopServer();
 | 
			
		||||
  await stopWeb();
 | 
			
		||||
  process.exit(1);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
process.on('unhandledRejection', async (reason, promise) => {
 | 
			
		||||
  console.error('❌ Unhandled rejection at:', promise, 'reason:', reason);
 | 
			
		||||
  await stopServer();
 | 
			
		||||
  await stopWeb();
 | 
			
		||||
  process.exit(1);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
main().catch(async (error) => {
 | 
			
		||||
  console.error('❌ Unhandled error:', error);
 | 
			
		||||
  await stopServer();
 | 
			
		||||
  await stopWeb();
 | 
			
		||||
  process.exit(1);
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										177
									
								
								src/APIClient.ts
									
									
									
									
									
								
							
							
						
						
									
										177
									
								
								src/APIClient.ts
									
									
									
									
									
								
							@@ -327,7 +327,7 @@ export class BsdlParserClient {
 | 
			
		||||
     * [TODO:description]
 | 
			
		||||
     * @return [TODO:return]
 | 
			
		||||
     */
 | 
			
		||||
    getBoundaryLogicalPorts(): Promise<FileResponse> {
 | 
			
		||||
    getBoundaryLogicalPorts(): Promise<FileResponse | null> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/BsdlParser/GetBoundaryLogicalPorts";
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
@@ -343,7 +343,7 @@ export class BsdlParserClient {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected processGetBoundaryLogicalPorts(response: Response): Promise<FileResponse> {
 | 
			
		||||
    protected processGetBoundaryLogicalPorts(response: Response): Promise<FileResponse | null> {
 | 
			
		||||
        const status = response.status;
 | 
			
		||||
        let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
 | 
			
		||||
        if (status === 200 || status === 206) {
 | 
			
		||||
@@ -362,7 +362,7 @@ export class BsdlParserClient {
 | 
			
		||||
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<FileResponse>(null as any);
 | 
			
		||||
        return Promise.resolve<FileResponse | null>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -377,11 +377,21 @@ export class DataClient {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建数据库表
 | 
			
		||||
     * @return 插入的记录数
 | 
			
		||||
     * [TODO:description]
 | 
			
		||||
     * @param name (optional) [TODO:parameter]
 | 
			
		||||
     * @param password (optional) [TODO:parameter]
 | 
			
		||||
     * @return [TODO:return]
 | 
			
		||||
     */
 | 
			
		||||
    createTables(): Promise<FileResponse> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Data/CreateTable";
 | 
			
		||||
    login(name: string | undefined, password: string | undefined): Promise<FileResponse | null> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Data/login?";
 | 
			
		||||
        if (name === null)
 | 
			
		||||
            throw new Error("The parameter 'name' cannot be null.");
 | 
			
		||||
        else if (name !== undefined)
 | 
			
		||||
            url_ += "name=" + encodeURIComponent("" + name) + "&";
 | 
			
		||||
        if (password === null)
 | 
			
		||||
            throw new Error("The parameter 'password' cannot be null.");
 | 
			
		||||
        else if (password !== undefined)
 | 
			
		||||
            url_ += "password=" + encodeURIComponent("" + password) + "&";
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
        let options_: RequestInit = {
 | 
			
		||||
@@ -392,11 +402,11 @@ export class DataClient {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return this.http.fetch(url_, options_).then((_response: Response) => {
 | 
			
		||||
            return this.processCreateTables(_response);
 | 
			
		||||
            return this.processLogin(_response);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected processCreateTables(response: Response): Promise<FileResponse> {
 | 
			
		||||
    protected processLogin(response: Response): Promise<FileResponse | null> {
 | 
			
		||||
        const status = response.status;
 | 
			
		||||
        let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
 | 
			
		||||
        if (status === 200 || status === 206) {
 | 
			
		||||
@@ -415,57 +425,15 @@ export class DataClient {
 | 
			
		||||
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<FileResponse>(null as any);
 | 
			
		||||
        return Promise.resolve<FileResponse | null>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除数据库表
 | 
			
		||||
     * @return 插入的记录数
 | 
			
		||||
     * [TODO:description]
 | 
			
		||||
     * @return [TODO:return]
 | 
			
		||||
     */
 | 
			
		||||
    dropTables(): Promise<FileResponse> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Data/DropTables";
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
        let options_: RequestInit = {
 | 
			
		||||
            method: "DELETE",
 | 
			
		||||
            headers: {
 | 
			
		||||
                "Accept": "application/octet-stream"
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return this.http.fetch(url_, options_).then((_response: Response) => {
 | 
			
		||||
            return this.processDropTables(_response);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected processDropTables(response: Response): Promise<FileResponse> {
 | 
			
		||||
        const status = response.status;
 | 
			
		||||
        let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
 | 
			
		||||
        if (status === 200 || status === 206) {
 | 
			
		||||
            const contentDisposition = response.headers ? response.headers.get("content-disposition") : undefined;
 | 
			
		||||
            let fileNameMatch = contentDisposition ? /filename\*=(?:(\\?['"])(.*?)\1|(?:[^\s]+'.*?')?([^;\n]*))/g.exec(contentDisposition) : undefined;
 | 
			
		||||
            let fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[3] || fileNameMatch[2] : undefined;
 | 
			
		||||
            if (fileName) {
 | 
			
		||||
                fileName = decodeURIComponent(fileName);
 | 
			
		||||
            } else {
 | 
			
		||||
                fileNameMatch = contentDisposition ? /filename="?([^"]*?)"?(;|$)/g.exec(contentDisposition) : undefined;
 | 
			
		||||
                fileName = fileNameMatch && fileNameMatch.length > 1 ? fileNameMatch[1] : undefined;
 | 
			
		||||
            }
 | 
			
		||||
            return response.blob().then(blob => { return { fileName: fileName, data: blob, status: status, headers: _headers }; });
 | 
			
		||||
        } else if (status !== 200 && status !== 204) {
 | 
			
		||||
            return response.text().then((_responseText) => {
 | 
			
		||||
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<FileResponse>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取所有用户
 | 
			
		||||
     * @return 用户列表
 | 
			
		||||
     */
 | 
			
		||||
    allUsers(): Promise<FileResponse> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Data/AllUsers";
 | 
			
		||||
    testAuth(): Promise<FileResponse | null> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Data/TestAuth";
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
        let options_: RequestInit = {
 | 
			
		||||
@@ -476,11 +444,11 @@ export class DataClient {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return this.http.fetch(url_, options_).then((_response: Response) => {
 | 
			
		||||
            return this.processAllUsers(_response);
 | 
			
		||||
            return this.processTestAuth(_response);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected processAllUsers(response: Response): Promise<FileResponse> {
 | 
			
		||||
    protected processTestAuth(response: Response): Promise<FileResponse | null> {
 | 
			
		||||
        const status = response.status;
 | 
			
		||||
        let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
 | 
			
		||||
        if (status === 200 || status === 206) {
 | 
			
		||||
@@ -499,20 +467,30 @@ export class DataClient {
 | 
			
		||||
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<FileResponse>(null as any);
 | 
			
		||||
        return Promise.resolve<FileResponse | null>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 注册新用户
 | 
			
		||||
     * @param name (optional) 用户名
 | 
			
		||||
     * @param email (optional) [TODO:parameter]
 | 
			
		||||
     * @param password (optional) [TODO:parameter]
 | 
			
		||||
     * @return 操作结果
 | 
			
		||||
     */
 | 
			
		||||
    signUpUser(name: string | undefined): Promise<FileResponse> {
 | 
			
		||||
    signUpUser(name: string | undefined, email: string | undefined, password: string | undefined): Promise<FileResponse | null> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Data/SignUpUser?";
 | 
			
		||||
        if (name === null)
 | 
			
		||||
            throw new Error("The parameter 'name' cannot be null.");
 | 
			
		||||
        else if (name !== undefined)
 | 
			
		||||
            url_ += "name=" + encodeURIComponent("" + name) + "&";
 | 
			
		||||
        if (email === null)
 | 
			
		||||
            throw new Error("The parameter 'email' cannot be null.");
 | 
			
		||||
        else if (email !== undefined)
 | 
			
		||||
            url_ += "email=" + encodeURIComponent("" + email) + "&";
 | 
			
		||||
        if (password === null)
 | 
			
		||||
            throw new Error("The parameter 'password' cannot be null.");
 | 
			
		||||
        else if (password !== undefined)
 | 
			
		||||
            url_ += "password=" + encodeURIComponent("" + password) + "&";
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
        let options_: RequestInit = {
 | 
			
		||||
@@ -527,7 +505,7 @@ export class DataClient {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected processSignUpUser(response: Response): Promise<FileResponse> {
 | 
			
		||||
    protected processSignUpUser(response: Response): Promise<FileResponse | null> {
 | 
			
		||||
        const status = response.status;
 | 
			
		||||
        let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
 | 
			
		||||
        if (status === 200 || status === 206) {
 | 
			
		||||
@@ -546,7 +524,7 @@ export class DataClient {
 | 
			
		||||
            return throwException("An unexpected server error occurred.", status, _responseText, _headers);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        return Promise.resolve<FileResponse>(null as any);
 | 
			
		||||
        return Promise.resolve<FileResponse | null>(null as any);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -943,9 +921,9 @@ export class JtagClient {
 | 
			
		||||
    /**
 | 
			
		||||
     * 上传比特流文件
 | 
			
		||||
     * @param address (optional) 设备地址
 | 
			
		||||
     * @param file (optional) 
 | 
			
		||||
     * @param file (optional) 比特流文件
 | 
			
		||||
     */
 | 
			
		||||
    uploadBitstream(address: string | undefined, file: FileParameter | null | undefined): Promise<boolean> {
 | 
			
		||||
    uploadBitstream(address: string | undefined, file: FileParameter | undefined): Promise<boolean> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/Jtag/UploadBitstream?";
 | 
			
		||||
        if (address === null)
 | 
			
		||||
            throw new Error("The parameter 'address' cannot be null.");
 | 
			
		||||
@@ -954,7 +932,9 @@ export class JtagClient {
 | 
			
		||||
        url_ = url_.replace(/[?&]$/, "");
 | 
			
		||||
 | 
			
		||||
        const content_ = new FormData();
 | 
			
		||||
        if (file !== null && file !== undefined)
 | 
			
		||||
        if (file === null || file === undefined)
 | 
			
		||||
            throw new Error("The parameter 'file' cannot be null.");
 | 
			
		||||
        else
 | 
			
		||||
            content_.append("file", file.data, file.fileName ? file.fileName : "file");
 | 
			
		||||
 | 
			
		||||
        let options_: RequestInit = {
 | 
			
		||||
@@ -1519,10 +1499,10 @@ export class RemoteUpdateClient {
 | 
			
		||||
    /**
 | 
			
		||||
     * 上传远程更新比特流文件
 | 
			
		||||
     * @param address (optional) 设备地址
 | 
			
		||||
     * @param goldenBitream (optional) 
 | 
			
		||||
     * @param bitstream1 (optional) 
 | 
			
		||||
     * @param bitstream2 (optional) 
 | 
			
		||||
     * @param bitstream3 (optional) 
 | 
			
		||||
     * @param goldenBitream (optional) 黄金比特流文件
 | 
			
		||||
     * @param bitstream1 (optional) 比特流文件1
 | 
			
		||||
     * @param bitstream2 (optional) 比特流文件2
 | 
			
		||||
     * @param bitstream3 (optional) 比特流文件3
 | 
			
		||||
     * @return 上传结果
 | 
			
		||||
     */
 | 
			
		||||
    uploadBitstreams(address: string | undefined, goldenBitream: FileParameter | null | undefined, bitstream1: FileParameter | null | undefined, bitstream2: FileParameter | null | undefined, bitstream3: FileParameter | null | undefined): Promise<boolean> {
 | 
			
		||||
@@ -2156,7 +2136,7 @@ export class UDPClient {
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取指定IP地址接收的数据列表
 | 
			
		||||
     * @param address (optional) IP地址
 | 
			
		||||
     * @param taskID (optional) 
 | 
			
		||||
     * @param taskID (optional) 任务ID
 | 
			
		||||
     */
 | 
			
		||||
    getRecvDataArray(address: string | undefined, taskID: number | undefined): Promise<UDPData[]> {
 | 
			
		||||
        let url_ = this.baseUrl + "/api/UDP/GetRecvDataArray?";
 | 
			
		||||
@@ -2213,7 +2193,7 @@ export class UDPClient {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Exception implements IException {
 | 
			
		||||
    message?: string;
 | 
			
		||||
    message!: string;
 | 
			
		||||
    innerException?: Exception | undefined;
 | 
			
		||||
    source?: string | undefined;
 | 
			
		||||
    stackTrace?: string | undefined;
 | 
			
		||||
@@ -2254,7 +2234,7 @@ export class Exception implements IException {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IException {
 | 
			
		||||
    message?: string;
 | 
			
		||||
    message: string;
 | 
			
		||||
    innerException?: Exception | undefined;
 | 
			
		||||
    source?: string | undefined;
 | 
			
		||||
    stackTrace?: string | undefined;
 | 
			
		||||
@@ -2262,7 +2242,9 @@ export interface IException {
 | 
			
		||||
 | 
			
		||||
/** 摄像头配置请求模型 */
 | 
			
		||||
export class CameraConfigRequest implements ICameraConfigRequest {
 | 
			
		||||
    /** 摄像头地址 */
 | 
			
		||||
    address!: string;
 | 
			
		||||
    /** 摄像头端口 */
 | 
			
		||||
    port!: number;
 | 
			
		||||
 | 
			
		||||
    constructor(data?: ICameraConfigRequest) {
 | 
			
		||||
@@ -2298,7 +2280,9 @@ export class CameraConfigRequest implements ICameraConfigRequest {
 | 
			
		||||
 | 
			
		||||
/** 摄像头配置请求模型 */
 | 
			
		||||
export interface ICameraConfigRequest {
 | 
			
		||||
    /** 摄像头地址 */
 | 
			
		||||
    address: string;
 | 
			
		||||
    /** 摄像头端口 */
 | 
			
		||||
    port: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -2330,6 +2314,7 @@ export interface ISystemException extends IException {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ArgumentException extends SystemException implements IArgumentException {
 | 
			
		||||
    declare message: string;
 | 
			
		||||
    paramName?: string | undefined;
 | 
			
		||||
 | 
			
		||||
    constructor(data?: IArgumentException) {
 | 
			
		||||
@@ -2361,22 +2346,22 @@ export class ArgumentException extends SystemException implements IArgumentExcep
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IArgumentException extends ISystemException {
 | 
			
		||||
    message?: string;
 | 
			
		||||
    message: string;
 | 
			
		||||
    paramName?: string | undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Package options which to send address to read or write */
 | 
			
		||||
export class SendAddrPackOptions implements ISendAddrPackOptions {
 | 
			
		||||
    /** 突发类型 */
 | 
			
		||||
    burstType?: BurstType;
 | 
			
		||||
    burstType!: BurstType;
 | 
			
		||||
    /** 任务ID */
 | 
			
		||||
    commandID?: number;
 | 
			
		||||
    commandID!: number;
 | 
			
		||||
    /** 标识写入还是读取 */
 | 
			
		||||
    isWrite?: boolean;
 | 
			
		||||
    isWrite!: boolean;
 | 
			
		||||
    /** 突发长度:0是32bits,255是32bits x 256 */
 | 
			
		||||
    burstLength?: number;
 | 
			
		||||
    burstLength!: number;
 | 
			
		||||
    /** 目标地址 */
 | 
			
		||||
    address?: number;
 | 
			
		||||
    address!: number;
 | 
			
		||||
 | 
			
		||||
    constructor(data?: ISendAddrPackOptions) {
 | 
			
		||||
        if (data) {
 | 
			
		||||
@@ -2418,15 +2403,15 @@ export class SendAddrPackOptions implements ISendAddrPackOptions {
 | 
			
		||||
/** Package options which to send address to read or write */
 | 
			
		||||
export interface ISendAddrPackOptions {
 | 
			
		||||
    /** 突发类型 */
 | 
			
		||||
    burstType?: BurstType;
 | 
			
		||||
    burstType: BurstType;
 | 
			
		||||
    /** 任务ID */
 | 
			
		||||
    commandID?: number;
 | 
			
		||||
    commandID: number;
 | 
			
		||||
    /** 标识写入还是读取 */
 | 
			
		||||
    isWrite?: boolean;
 | 
			
		||||
    isWrite: boolean;
 | 
			
		||||
    /** 突发长度:0是32bits,255是32bits x 256 */
 | 
			
		||||
    burstLength?: number;
 | 
			
		||||
    burstLength: number;
 | 
			
		||||
    /** 目标地址 */
 | 
			
		||||
    address?: number;
 | 
			
		||||
    address: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Package Burst Type */
 | 
			
		||||
@@ -2438,17 +2423,17 @@ export enum BurstType {
 | 
			
		||||
/** UDP接受数据包格式 */
 | 
			
		||||
export class UDPData implements IUDPData {
 | 
			
		||||
    /** 接受到的时间 */
 | 
			
		||||
    dateTime?: Date;
 | 
			
		||||
    dateTime!: Date;
 | 
			
		||||
    /** 发送来源的IP地址 */
 | 
			
		||||
    address?: string;
 | 
			
		||||
    address!: string;
 | 
			
		||||
    /** 发送来源的端口号 */
 | 
			
		||||
    port?: number;
 | 
			
		||||
    port!: number;
 | 
			
		||||
    /** 任务ID */
 | 
			
		||||
    taskID?: number;
 | 
			
		||||
    taskID!: number;
 | 
			
		||||
    /** 接受到的数据 */
 | 
			
		||||
    data?: string;
 | 
			
		||||
    data!: string;
 | 
			
		||||
    /** 是否被读取过 */
 | 
			
		||||
    hasRead?: boolean;
 | 
			
		||||
    hasRead!: boolean;
 | 
			
		||||
 | 
			
		||||
    constructor(data?: IUDPData) {
 | 
			
		||||
        if (data) {
 | 
			
		||||
@@ -2492,17 +2477,17 @@ export class UDPData implements IUDPData {
 | 
			
		||||
/** UDP接受数据包格式 */
 | 
			
		||||
export interface IUDPData {
 | 
			
		||||
    /** 接受到的时间 */
 | 
			
		||||
    dateTime?: Date;
 | 
			
		||||
    dateTime: Date;
 | 
			
		||||
    /** 发送来源的IP地址 */
 | 
			
		||||
    address?: string;
 | 
			
		||||
    address: string;
 | 
			
		||||
    /** 发送来源的端口号 */
 | 
			
		||||
    port?: number;
 | 
			
		||||
    port: number;
 | 
			
		||||
    /** 任务ID */
 | 
			
		||||
    taskID?: number;
 | 
			
		||||
    taskID: number;
 | 
			
		||||
    /** 接受到的数据 */
 | 
			
		||||
    data?: string;
 | 
			
		||||
    data: string;
 | 
			
		||||
    /** 是否被读取过 */
 | 
			
		||||
    hasRead?: boolean;
 | 
			
		||||
    hasRead: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FileParameter {
 | 
			
		||||
@@ -2546,4 +2531,4 @@ function throwException(message: string, status: number, response: string, heade
 | 
			
		||||
        throw result;
 | 
			
		||||
    else
 | 
			
		||||
        throw new ApiException(message, status, response, headers, null);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user