From d9800f341f1927182179434137defeff44bedc69 Mon Sep 17 00:00:00 2001 From: tikkhun Date: Thu, 27 Nov 2025 15:32:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E5=AE=9E=E4=BD=93):=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E4=BA=A7=E5=93=81=E7=9B=B8=E5=85=B3=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E5=8F=8A=E5=AD=97=E5=85=B8=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将分类、口味、规格实体重构为字典系统 - 新增dict和dict_item实体实现通用字典管理 - 修改product实体字段从categoryId改为brandId - 修复order_coupon和order_refund_item实体文件名拼写错误 - 更新typeorm配置和种子数据初始化逻辑 - 调整相关DTO和控制器接口适配新字典系统 - 更新package.json依赖版本和脚本 --- package-lock.json | 1118 ++++++++++++++++- package.json | 17 +- pnpm-lock.yaml | 365 ++++++ src/config/config.default.ts | 14 +- src/controller/product.controller.ts | 86 +- src/db/datasource.ts | 87 ++ src/db/seed/dict.ts | 65 - src/db/seed/index.ts | 44 - src/db/seeds/dict.seeder.ts | 113 ++ src/dto/product.dto.ts | 97 +- src/dto/reponse.dto.ts | 48 +- src/entity/category.entity.ts | 53 - src/entity/dict.entity.ts | 39 + src/entity/dict_item.entity.ts | 43 + src/entity/flavors.entity.ts | 43 - ...copon.entity.ts => order_coupon.entity.ts} | 2 +- ....entity.ts => order_refund_item.entity.ts} | 0 src/entity/product.entity.ts | 4 +- src/entity/site.entity.ts | 18 +- src/entity/strength.entity.ts | 43 - src/service/order.service.ts | 4 +- src/service/product.service.ts | 452 +++++-- 22 files changed, 2224 insertions(+), 531 deletions(-) create mode 100644 src/db/datasource.ts delete mode 100644 src/db/seed/dict.ts delete mode 100644 src/db/seed/index.ts create mode 100644 src/db/seeds/dict.seeder.ts delete mode 100644 src/entity/category.entity.ts create mode 100644 src/entity/dict.entity.ts create mode 100644 src/entity/dict_item.entity.ts delete mode 100644 src/entity/flavors.entity.ts rename src/entity/{order_copon.entity.ts => order_coupon.entity.ts} (99%) rename src/entity/{order_retund_item.entity.ts => order_refund_item.entity.ts} (100%) delete mode 100644 src/entity/strength.entity.ts diff --git a/package-lock.json b/package-lock.json index 0ede98f..d9e1020 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,20 +21,25 @@ "@midwayjs/swagger": "^3.20.2", "@midwayjs/typeorm": "^3.20.0", "@midwayjs/validate": "^3.20.2", - "axios": "^1.7.9", + "@woocommerce/woocommerce-rest-api": "^1.0.2", + "axios": "^1.13.2", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", "dayjs": "^1.11.13", "mysql2": "^3.11.5", "nodemailer": "^7.0.5", + "npm-check-updates": "^19.1.2", "swagger-ui-dist": "^5.18.2", - "typeorm": "^0.3.20", + "typeorm": "^0.3.27", + "typeorm-extension": "^3.7.2", + "xlsx": "^0.18.5", "xml2js": "^0.6.2" }, "devDependencies": { "@midwayjs/mock": "^3.20.11", "cross-env": "^10.1.0", "mwtsc": "^1.15.2", + "tsx": "^4.20.6", "typescript": "^5.9.3" }, "engines": { @@ -59,6 +64,465 @@ "dev": true, "license": "MIT" }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@faker-js/faker": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.1.0.tgz", + "integrity": "sha512-C3mrr3b5dRVlKPJdfrAXS8+dq+rq8Qm5SNRazca0JKgw1HQERFmrVb0towvMmw5uu8hHKNiQasMaR/tydf3Zsg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" + } + }, "node_modules/@hapi/bourne": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/@hapi/bourne/-/bourne-3.0.0.tgz", @@ -377,7 +841,6 @@ "version": "2.1.5", "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -391,7 +854,6 @@ "version": "2.0.5", "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -401,7 +863,6 @@ "version": "1.2.8", "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -675,6 +1136,21 @@ "@types/superagent": "*" } }, + "node_modules/@woocommerce/woocommerce-rest-api": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@woocommerce/woocommerce-rest-api/-/woocommerce-rest-api-1.0.2.tgz", + "integrity": "sha512-G+0VwM0MINF83KnT7Rg/htm9EEYADWvDPT/UWEJdZ0de1vXvsPrr4M1ksKaxgKHO8qIJViRrIHCtrui2JoVA+Q==", + "license": "MIT", + "dependencies": { + "axios": "^1.6.8", + "create-hmac": "^1.1.7", + "oauth-1.0a": "^2.2.6", + "url-parse": "^1.4.7" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", @@ -688,6 +1164,15 @@ "node": ">= 0.6" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -799,9 +1284,9 @@ } }, "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmmirror.com/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -867,7 +1352,6 @@ "version": "3.0.3", "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -982,6 +1466,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", @@ -1017,6 +1514,20 @@ "node": ">=18" } }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmmirror.com/class-transformer/-/class-transformer-0.5.1.tgz", @@ -1197,6 +1708,15 @@ "node": ">=8.0.0" } }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", @@ -1254,6 +1774,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1301,6 +1830,51 @@ "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==", "license": "MIT" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/cron": { "version": "3.5.0", "resolved": "https://registry.npmmirror.com/cron/-/cron-3.5.0.tgz", @@ -1436,6 +2010,12 @@ "node": ">= 0.8" } }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", @@ -1502,6 +2082,12 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/ebec": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ebec/-/ebec-2.3.0.tgz", + "integrity": "sha512-bt+0tSL7223VU3PSVi0vtNLZ8pO1AfWolcPPMk2a/a5H+o/ZU9ky0n3A0zhrR4qzJTN61uPsGIO4ShhOukdzxA==", + "license": "MIT" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -1532,6 +2118,18 @@ "node": ">= 0.8" } }, + "node_modules/envix": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/envix/-/envix-1.5.0.tgz", + "integrity": "sha512-IOxTKT+tffjxgvX2O5nq6enbkv6kBQ/QdMy18bZWo0P0rKPvsRp2/EypIPwTvJfnmk3VdOlq/KcRSZCswefM/w==", + "license": "MIT", + "dependencies": { + "std-env": "^3.7.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", @@ -1577,6 +2175,48 @@ "node": ">= 0.4" } }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", @@ -1596,7 +2236,6 @@ "version": "3.3.3", "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1620,7 +2259,6 @@ "version": "1.19.1", "resolved": "https://registry.npmmirror.com/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -1630,7 +2268,6 @@ "version": "7.1.1", "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -1639,6 +2276,15 @@ "node": ">=8" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -1722,6 +2368,15 @@ "url": "https://ko-fi.com/tunnckoCore/commissions" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", @@ -1773,6 +2428,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -1847,7 +2514,6 @@ "version": "5.1.2", "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -1928,6 +2594,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", @@ -2093,7 +2774,6 @@ "version": "2.1.1", "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2130,7 +2810,6 @@ "version": "4.0.3", "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -2143,7 +2822,6 @@ "version": "7.0.0", "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -2215,6 +2893,15 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/joi": { "version": "17.13.3", "resolved": "https://registry.npmmirror.com/joi/-/joi-17.13.3.tgz", @@ -2397,6 +3084,23 @@ "node": ">= 0.6" } }, + "node_modules/locter": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/locter/-/locter-2.2.1.tgz", + "integrity": "sha512-Cc7mowptFl7ug5he6Iuos7aGRd9xbwTfnx1ng4AX/7F4iqemPaXAIJDi13IBwQZrKgli9OPEYXm6uCKr7ynxUQ==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "ebec": "^2.3.0", + "fast-glob": "^3.3.3", + "flat": "^5.0.2", + "jiti": "^2.6.1", + "yaml": "^2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmmirror.com/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -2445,6 +3149,15 @@ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", @@ -2487,6 +3200,17 @@ "node": ">= 0.4" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", @@ -2500,7 +3224,6 @@ "version": "1.4.1", "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2519,7 +3242,6 @@ "version": "4.0.8", "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -2699,6 +3421,16 @@ "node": ">= 0.6" } }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/nodemailer": { "version": "7.0.6", "resolved": "https://registry.npmmirror.com/nodemailer/-/nodemailer-7.0.6.tgz", @@ -2718,6 +3450,26 @@ "node": ">=0.10.0" } }, + "node_modules/npm-check-updates": { + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-19.1.2.tgz", + "integrity": "sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g==", + "license": "Apache-2.0", + "bin": { + "ncu": "build/cli.js", + "npm-check-updates": "build/cli.js" + }, + "engines": { + "node": ">=20.0.0", + "npm": ">=8.12.1" + } + }, + "node_modules/oauth-1.0a": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/oauth-1.0a/-/oauth-1.0a-2.2.6.tgz", + "integrity": "sha512-6bkxv3N4Gu5lty4viIcIAnq5GbxECviMBeKR3WX/q87SPQ8E8aursPZUtsXDnxCs787af09WPRBLqYrf/lwoYQ==", + "license": "MIT" + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", @@ -2772,6 +3524,16 @@ "node": ">= 0.8" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", @@ -2853,6 +3615,12 @@ "node": ">= 0.4" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -2874,6 +3642,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, "node_modules/queue-lit": { "version": "1.5.2", "resolved": "https://registry.npmmirror.com/queue-lit/-/queue-lit-1.5.2.tgz", @@ -2888,7 +3662,6 @@ "version": "1.2.3", "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -2905,6 +3678,25 @@ ], "license": "MIT" }, + "node_modules/rapiq": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/rapiq/-/rapiq-0.9.0.tgz", + "integrity": "sha512-k4oT4RarFBrlLMJ49xUTeQpa/us0uU4I70D/UEnK3FWQ4GENzei01rEQAmvPKAIzACo4NMW+YcYJ7EVfSa7EFg==", + "license": "MIT", + "dependencies": { + "ebec": "^1.1.0", + "smob": "^1.4.0" + } + }, + "node_modules/rapiq/node_modules/ebec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ebec/-/ebec-1.1.1.tgz", + "integrity": "sha512-JZ1vcvPQtR+8LGbZmbjG21IxLQq/v47iheJqn2F6yB2CgnGfn8ZVg3myHrf3buIZS8UCwQK0jOSIb3oHX7aH8g==", + "license": "MIT", + "dependencies": { + "smob": "^1.4.0" + } + }, "node_modules/raw-body": { "version": "2.5.2", "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.2.tgz", @@ -2932,6 +3724,33 @@ "node": ">=0.10.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", @@ -2960,6 +3779,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -2974,18 +3799,29 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -3250,6 +4086,12 @@ "node": ">=8" } }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "license": "MIT" + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", @@ -3296,6 +4138,18 @@ "node": ">= 0.6" } }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", @@ -3305,6 +4159,27 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", @@ -3467,9 +4342,9 @@ } }, "node_modules/to-buffer": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/to-buffer/-/to-buffer-1.2.1.tgz", - "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", "license": "MIT", "dependencies": { "isarray": "^2.0.5", @@ -3484,7 +4359,6 @@ "version": "5.0.1", "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -3539,6 +4413,26 @@ "node": ">=0.6.x" } }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "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/type-is": { "version": "1.6.18", "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", @@ -3668,6 +4562,113 @@ } } }, + "node_modules/typeorm-extension": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/typeorm-extension/-/typeorm-extension-3.7.2.tgz", + "integrity": "sha512-OGxx9RYqxohyfZnfr8JEGEcO3KCNDmh+fSbgxrNH2/pBN7Deprv5M+BmKIFjbNRi0mUHW4d0yx7ALoDUxU87Pg==", + "license": "MIT", + "dependencies": { + "consola": "^3.4.0", + "envix": "^1.5.0", + "locter": "^2.2.1", + "pascal-case": "^3.1.2", + "rapiq": "^0.9.0", + "reflect-metadata": "^0.2.2", + "smob": "^1.5.0", + "yargs": "^18.0.0" + }, + "bin": { + "typeorm-extension": "bin/cli.cjs", + "typeorm-extension-esm": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0" + }, + "peerDependencies": { + "@faker-js/faker": ">=8.4.1", + "typeorm": "~0.3.0" + } + }, + "node_modules/typeorm-extension/node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/typeorm-extension/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/typeorm-extension/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typeorm-extension/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/typeorm-extension/node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/typeorm-extension/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -3697,6 +4698,22 @@ "node": ">= 0.8" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, "node_modules/uuid": { "version": "11.1.0", "resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz", @@ -3755,6 +4772,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -3853,6 +4888,27 @@ "dev": true, "license": "ISC" }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmmirror.com/xml2js/-/xml2js-0.6.2.tgz", @@ -3894,6 +4950,18 @@ "node": ">=18" } }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index d8b9c90..c675c7e 100644 --- a/package.json +++ b/package.json @@ -17,14 +17,17 @@ "@midwayjs/typeorm": "^3.20.0", "@midwayjs/validate": "^3.20.2", "@woocommerce/woocommerce-rest-api": "^1.0.2", - "axios": "^1.7.9", + "axios": "^1.13.2", "bcryptjs": "^2.4.3", "class-transformer": "^0.5.1", "dayjs": "^1.11.13", "mysql2": "^3.11.5", "nodemailer": "^7.0.5", + "npm-check-updates": "^19.1.2", "swagger-ui-dist": "^5.18.2", - "typeorm": "^0.3.20", + "typeorm": "^0.3.27", + "typeorm-extension": "^3.7.2", + "xlsx": "^0.18.5", "xml2js": "^0.6.2" }, "engines": { @@ -36,10 +39,13 @@ "dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js", "test": "cross-env NODE_ENV=unittest jest", "cov": "jest --coverage", - "lint": "mwts check", - "lint:fix": "mwts fix", + "lint": "mwtsc check", + "lint:fix": "mwtsc fix", "ci": "npm run cov", - "build": "mwtsc --cleanOutDir" + "build": "mwtsc --cleanOutDir", + "seed": "ts-node src/db/seed/index.ts", + "seed:run": "ts-node ./node_modules/typeorm-extension/bin/cli.cjs seed:run -d src/db/datasource.ts", + "typeorm": "ts-node ./node_modules/typeorm/cli.js" }, "repository": { "type": "git", @@ -51,6 +57,7 @@ "@midwayjs/mock": "^3.20.11", "cross-env": "^10.1.0", "mwtsc": "^1.15.2", + "tsx": "^4.20.6", "typescript": "^5.9.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7fd255..ff03e1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,12 +65,18 @@ importers: nodemailer: specifier: ^7.0.5 version: 7.0.10 + npm-check-updates: + specifier: ^19.1.2 + version: 19.1.2 swagger-ui-dist: specifier: ^5.18.2 version: 5.30.2 typeorm: specifier: ^0.3.20 version: 0.3.27(mysql2@3.15.3)(reflect-metadata@0.2.2) + xlsx: + specifier: ^0.18.5 + version: 0.18.5 xml2js: specifier: ^0.6.2 version: 0.6.2 @@ -84,6 +90,9 @@ importers: mwtsc: specifier: ^1.15.2 version: 1.15.2 + tsx: + specifier: ^4.20.6 + version: 4.20.6 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -97,6 +106,162 @@ packages: '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@hapi/bourne@3.0.0': resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} @@ -314,6 +479,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -415,6 +584,10 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -446,6 +619,10 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -488,6 +665,11 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + create-hash@1.2.0: resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} @@ -606,6 +788,11 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -651,6 +838,10 @@ packages: formidable@2.1.5: resolution: {integrity: sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==} + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -961,6 +1152,11 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + npm-check-updates@19.1.2: + resolution: {integrity: sha512-FNeFCVgPOj0fz89hOpGtxP2rnnRHR7hD2E8qNU8SMWfkyDZXA/xpgjsL3UMLSo3F/K13QvJDnbxPngulNDDo/g==} + engines: {node: '>=20.0.0', npm: '>=8.12.1'} + hasBin: true + oauth-1.0a@2.2.6: resolution: {integrity: sha512-6bkxv3N4Gu5lty4viIcIAnq5GbxECviMBeKR3WX/q87SPQ8E8aursPZUtsXDnxCs787af09WPRBLqYrf/lwoYQ==} @@ -1160,6 +1356,10 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + statuses@1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -1228,6 +1428,11 @@ packages: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} engines: {node: '>=0.6.x'} + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -1327,6 +1532,14 @@ packages: engines: {node: '>= 8'} hasBin: true + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -1338,6 +1551,11 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + xml2js@0.6.2: resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} engines: {node: '>=4.0.0'} @@ -1373,6 +1591,84 @@ snapshots: '@epic-web/invariant@1.0.0': {} + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + '@hapi/bourne@3.0.0': {} '@hapi/hoek@9.3.0': {} @@ -1645,6 +1941,8 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + adler-32@1.3.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -1735,6 +2033,11 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -1779,6 +2082,8 @@ snapshots: co@4.6.0: {} + codepage@1.15.0: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -1812,6 +2117,8 @@ snapshots: core-util-is@1.0.3: {} + crc-32@1.2.2: {} + create-hash@1.2.0: dependencies: cipher-base: 1.0.7 @@ -1919,6 +2226,35 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -1967,6 +2303,8 @@ snapshots: once: 1.4.0 qs: 6.14.0 + frac@1.1.2: {} + fresh@0.5.2: {} fsevents@2.3.3: @@ -2313,6 +2651,8 @@ snapshots: normalize-path@3.0.0: {} + npm-check-updates@19.1.2: {} + oauth-1.0a@2.2.6: {} object-inspect@1.13.4: {} @@ -2494,6 +2834,10 @@ snapshots: sqlstring@2.3.3: {} + ssf@0.11.2: + dependencies: + frac: 1.1.2 + statuses@1.5.0: {} statuses@2.0.1: {} @@ -2582,6 +2926,13 @@ snapshots: tsscmp@1.0.6: {} + tsx@4.20.6: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -2647,6 +2998,10 @@ snapshots: dependencies: isexe: 2.0.0 + wmf@1.0.2: {} + + word@0.3.0: {} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -2661,6 +3016,16 @@ snapshots: wrappy@1.0.2: {} + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 + xml2js@0.6.2: dependencies: sax: 1.4.3 diff --git a/src/config/config.default.ts b/src/config/config.default.ts index fd99d08..b384d91 100644 --- a/src/config/config.default.ts +++ b/src/config/config.default.ts @@ -1,6 +1,5 @@ import { MidwayConfig } from '@midwayjs/core'; import { Product } from '../entity/product.entity'; -import { Category } from '../entity/category.entity'; import { WpProduct } from '../entity/wp_product.entity'; import { Variation } from '../entity/variation.entity'; import { User } from '../entity/user.entity'; @@ -11,10 +10,10 @@ import { StockPoint } from '../entity/stock_point.entity'; import { StockRecord } from '../entity/stock_record.entity'; import { Order } from '../entity/order.entity'; import { OrderItem } from '../entity/order_item.entity'; -import { OrderCoupon } from '../entity/order_copon.entity'; +import { OrderCoupon } from '../entity/order_coupon.entity'; import { OrderFee } from '../entity/order_fee.entity'; import { OrderRefund } from '../entity/order_refund.entity'; -import { OrderRefundItem } from '../entity/order_retund_item.entity'; +import { OrderRefundItem } from '../entity/order_refund_item.entity'; import { OrderSale } from '../entity/order_sale.entity'; import { OrderSaleOriginal } from '../entity/order_item_original.entity'; import { OrderShipping } from '../entity/order_shipping.entity'; @@ -26,14 +25,14 @@ import { Shipment } from '../entity/shipment.entity'; import { ShipmentItem } from '../entity/shipment_item.entity'; import { Transfer } from '../entity/transfer.entity'; import { TransferItem } from '../entity/transfer_item.entity'; -import { Strength } from '../entity/strength.entity'; -import { Flavors } from '../entity/flavors.entity'; import { CustomerTag } from '../entity/customer_tag.entity'; import { Customer } from '../entity/customer.entity'; import { DeviceWhitelist } from '../entity/device_whitelist'; import { AuthCode } from '../entity/auth_code'; import { Subscription } from '../entity/subscription.entity'; import { Site } from '../entity/site.entity'; +import { Dict } from '../entity/dict.entity'; +import { DictItem } from '../entity/dict_item.entity'; export default { // use for cookie sign key, should change to your own and keep security @@ -42,9 +41,6 @@ export default { default: { entities: [ Product, - Category, - Strength, - Flavors, WpProduct, Variation, User, @@ -76,6 +72,8 @@ export default { AuthCode, Subscription, Site, + Dict, + DictItem, ], synchronize: true, logging: false, diff --git a/src/controller/product.controller.ts b/src/controller/product.controller.ts index cfdedb6..4d7f7fd 100644 --- a/src/controller/product.controller.ts +++ b/src/controller/product.controller.ts @@ -13,15 +13,15 @@ import { ProductService } from '../service/product.service'; import { errorResponse, successResponse } from '../utils/response.util'; import { BatchSetSkuDTO, - CreateCategoryDTO, + CreateBrandDTO, CreateFlavorsDTO, CreateProductDTO, CreateStrengthDTO, - QueryCategoryDTO, + QueryBrandDTO, QueryFlavorsDTO, QueryProductDTO, QueryStrengthDTO, - UpdateCategoryDTO, + UpdateBrandDTO, UpdateFlavorsDTO, UpdateProductDTO, UpdateStrengthDTO, @@ -29,8 +29,8 @@ import { import { ApiOkResponse } from '@midwayjs/swagger'; import { BooleanRes, - ProductCatListRes, - ProductCatRes, + ProductBrandListRes, + ProductBrandRes, ProductListRes, ProductRes, ProductsRes, @@ -79,12 +79,12 @@ export class ProductController { async getProductList( @Query() query: QueryProductDTO ): Promise { - const { current = 1, pageSize = 10, name, categoryId } = query; + const { current = 1, pageSize = 10, name, brandId } = query; try { const data = await this.productService.getProductList( { current, pageSize }, name, - categoryId + brandId ); return successResponse(data); } catch (error) { @@ -138,8 +138,6 @@ export class ProductController { } } - - @ApiOkResponse({ type: BooleanRes, }) @@ -154,13 +152,13 @@ export class ProductController { } @ApiOkResponse({ - type: ProductCatListRes, + type: ProductBrandListRes, }) - @Get('/categories') - async getCategories(@Query() query: QueryCategoryDTO) { + @Get('/brands') + async getBrands(@Query() query: QueryBrandDTO) { const { current = 1, pageSize = 10, name } = query; try { - let data = await this.productService.getCategoryList( + let data = await this.productService.getBrandList( { current, pageSize }, name ); @@ -171,10 +169,10 @@ export class ProductController { } @ApiOkResponse() - @Get('/categorieAll') - async getCategorieAll() { + @Get('/brandAll') + async getBrandAll() { try { - let data = await this.productService.getCategoryAll(); + let data = await this.productService.getBrandAll(); return successResponse(data); } catch (error) { return errorResponse(error?.message || error); @@ -182,18 +180,18 @@ export class ProductController { } @ApiOkResponse({ - type: ProductCatRes, + type: ProductBrandRes, }) - @Post('/category') - async createCategory(@Body() categoryData: CreateCategoryDTO) { + @Post('/brand') + async createBrand(@Body() brandData: CreateBrandDTO) { try { - const hasCategory = await this.productService.hasCategory( - categoryData.name + const hasBrand = await this.productService.hasBrand( + brandData.name ); - if (hasCategory) { - return errorResponse('分类已存在'); + if (hasBrand) { + return errorResponse('品牌已存在'); } - let data = await this.productService.createCategory(categoryData); + let data = await this.productService.createBrand(brandData); return successResponse(data); } catch (error) { return errorResponse(error?.message || error); @@ -201,21 +199,21 @@ export class ProductController { } @ApiOkResponse({ - type: ProductCatRes, + type: ProductBrandRes, }) - @Put('/category/:id') - async updateCategory( + @Put('/brand/:id') + async updateBrand( @Param('id') id: number, - @Body() categoryData: UpdateCategoryDTO + @Body() brandData: UpdateBrandDTO ) { try { - const hasCategory = await this.productService.hasCategory( - categoryData.name + const hasBrand = await this.productService.hasBrand( + brandData.name ); - if (hasCategory) { - return errorResponse('分类已存在'); + if (hasBrand) { + return errorResponse('品牌已存在'); } - const data = this.productService.updateCategory(id, categoryData); + const data = this.productService.updateBrand(id, brandData); return successResponse(data); } catch (error) { return errorResponse(error?.message || error); @@ -225,12 +223,12 @@ export class ProductController { @ApiOkResponse({ type: BooleanRes, }) - @Del('/category/:id') - async deleteCategory(@Param('id') id: number) { + @Del('/brand/:id') + async deleteBrand(@Param('id') id: number) { try { - const hasProducts = await this.productService.hasProductsInCategory(id); - if (hasProducts) throw new Error('该分类下有商品,无法删除'); - const data = await this.productService.deleteCategory(id); + const hasProducts = await this.productService.hasProductsInBrand(id); + if (hasProducts) throw new Error('该品牌下有商品,无法删除'); + const data = await this.productService.deleteBrand(id); return successResponse(data); } catch (error) { return errorResponse(error?.message || error); @@ -283,7 +281,7 @@ export class ProductController { try { const hasFlavors = await this.productService.hasFlavors(flavorsData.name); if (hasFlavors) { - return errorResponse('分类已存在'); + return errorResponse('口味已存在'); } let data = await this.productService.createFlavors(flavorsData); return successResponse(data); @@ -301,7 +299,7 @@ export class ProductController { try { const hasFlavors = await this.productService.hasFlavors(flavorsData.name); if (hasFlavors) { - return errorResponse('分类已存在'); + return errorResponse('口味已存在'); } const data = this.productService.updateFlavors(id, flavorsData); return successResponse(data); @@ -317,7 +315,7 @@ export class ProductController { async deleteFlavors(@Param('id') id: number) { try { const hasProducts = await this.productService.hasProductsInFlavors(id); - if (hasProducts) throw new Error('该分类下有商品,无法删除'); + if (hasProducts) throw new Error('该口味下有商品,无法删除'); const data = await this.productService.deleteFlavors(id); return successResponse(data); } catch (error) { @@ -359,7 +357,7 @@ export class ProductController { strengthData.name ); if (hasStrength) { - return errorResponse('分类已存在'); + return errorResponse('规格已存在'); } let data = await this.productService.createStrength(strengthData); return successResponse(data); @@ -379,7 +377,7 @@ export class ProductController { strengthData.name ); if (hasStrength) { - return errorResponse('分类已存在'); + return errorResponse('规格已存在'); } const data = this.productService.updateStrength(id, strengthData); return successResponse(data); @@ -395,7 +393,7 @@ export class ProductController { async deleteStrength(@Param('id') id: number) { try { const hasProducts = await this.productService.hasProductsInStrength(id); - if (hasProducts) throw new Error('该分类下有商品,无法删除'); + if (hasProducts) throw new Error('该规格下有商品,无法删除'); const data = await this.productService.deleteStrength(id); return successResponse(data); } catch (error) { diff --git a/src/db/datasource.ts b/src/db/datasource.ts new file mode 100644 index 0000000..1f3b84f --- /dev/null +++ b/src/db/datasource.ts @@ -0,0 +1,87 @@ +import { DataSource, DataSourceOptions } from 'typeorm'; +import { SeederOptions } from 'typeorm-extension'; +import { Product } from '../entity/product.entity'; +import { WpProduct } from '../entity/wp_product.entity'; +import { Variation } from '../entity/variation.entity'; +import { User } from '../entity/user.entity'; +import { PurchaseOrder } from '../entity/purchase_order.entity'; +import { PurchaseOrderItem } from '../entity/purchase_order_item.entity'; +import { Stock } from '../entity/stock.entity'; +import { StockPoint } from '../entity/stock_point.entity'; +import { StockRecord } from '../entity/stock_record.entity'; +import { Order } from '../entity/order.entity'; +import { OrderItem } from '../entity/order_item.entity'; +import { OrderCoupon } from '../entity/order_coupon.entity'; +import { OrderFee } from '../entity/order_fee.entity'; +import { OrderRefund } from '../entity/order_refund.entity'; +import { OrderRefundItem } from '../entity/order_refund_item.entity'; +import { OrderSale } from '../entity/order_sale.entity'; +import { OrderSaleOriginal } from '../entity/order_item_original.entity'; +import { OrderShipping } from '../entity/order_shipping.entity'; +import { Service } from '../entity/service.entity'; +import { ShippingAddress } from '../entity/shipping_address.entity'; +import { OrderNote } from '../entity/order_note.entity'; +import { OrderShipment } from '../entity/order_shipment.entity'; +import { Shipment } from '../entity/shipment.entity'; +import { ShipmentItem } from '../entity/shipment_item.entity'; +import { Transfer } from '../entity/transfer.entity'; +import { TransferItem } from '../entity/transfer_item.entity'; +import { CustomerTag } from '../entity/customer_tag.entity'; +import { Customer } from '../entity/customer.entity'; +import { DeviceWhitelist } from '../entity/device_whitelist'; +import { AuthCode } from '../entity/auth_code'; +import { Subscription } from '../entity/subscription.entity'; +import { Site } from '../entity/site.entity'; +import { Dict } from '../entity/dict.entity'; +import { DictItem } from '../entity/dict_item.entity'; + +const options: DataSourceOptions & SeederOptions = { + type: 'mysql', + host: 'localhost', + port: 23306, + username: 'root', + password: '12345678', + database: 'inventory', + synchronize: false, + logging: true, + entities: [ + Product, + WpProduct, + Variation, + User, + PurchaseOrder, + PurchaseOrderItem, + Stock, + StockPoint, + StockRecord, + Order, + OrderItem, + OrderCoupon, + OrderFee, + OrderRefund, + OrderRefundItem, + OrderSale, + OrderSaleOriginal, + OrderShipment, + ShipmentItem, + Shipment, + OrderShipping, + Service, + ShippingAddress, + OrderNote, + Transfer, + TransferItem, + CustomerTag, + Customer, + DeviceWhitelist, + AuthCode, + Subscription, + Site, + Dict, + DictItem, + ], + migrations: ['src/migration/*.ts'], + seeds: ['src/db/seeds/**/*.ts'], +}; + +export default new DataSource(options); diff --git a/src/db/seed/dict.ts b/src/db/seed/dict.ts deleted file mode 100644 index 1ba6d7a..0000000 --- a/src/db/seed/dict.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @description 字典数据备份 - * @author ZKS - * @date 2025-11-27 - */ - -// 真实数据 -export const flavorsData: { id: number; title: string; name: string }[] = [ - { id: 1, title: 'Bellini Mini', name: 'Bellini Mini' }, - { id: 2, title: 'Max Polarmint', name: 'Max Polarmint' }, - { id: 3, title: 'Blueberry', name: 'Blueberry' }, - { id: 4, title: 'Citrus', name: 'Citrus' }, - { id: 5, title: 'Wintergreen', name: 'Wintergreen' }, - { id: 6, title: 'COOL MINT', name: 'COOL MINT' }, - { id: 7, title: 'JUICY PEACH', name: 'JUICY PEACH' }, - { id: 8, title: 'ORANGE', name: 'ORANGE' }, - { id: 9, title: 'PEPPERMINT', name: 'PEPPERMINT' }, - { id: 10, title: 'SPEARMINT', name: 'SPEARMINT' }, - { id: 11, title: 'STRAWBERRY', name: 'STRAWBERRY' }, - { id: 12, title: 'WATERMELON', name: 'WATERMELON' }, - { id: 13, title: 'COFFEE', name: 'COFFEE' }, - { id: 14, title: 'LEMONADE', name: 'LEMONADE' }, - { id: 15, title: 'apple mint', name: 'apple mint' }, - { id: 16, title: 'PEACH', name: 'PEACH' }, - { id: 17, title: 'Mango', name: 'Mango' }, - { id: 18, title: 'ICE WINTERGREEN', name: 'ICE WINTERGREEN' }, - { id: 19, title: 'Pink Lemonade', name: 'Pink Lemonade' }, - { id: 20, title: 'Blackcherry', name: 'Blackcherry' }, - { id: 21, title: 'fresh mint', name: 'fresh mint' }, - { id: 22, title: 'Strawberry Lychee', name: 'Strawberry Lychee' }, - { id: 23, title: 'Passion Fruit', name: 'Passion Fruit' }, - { id: 24, title: 'Banana lce', name: 'Banana lce' }, - { id: 25, title: 'Bubblegum', name: 'Bubblegum' }, - { id: 26, title: 'Mango lce', name: 'Mango lce' }, - { id: 27, title: 'Grape lce', name: 'Grape lce' }, - { id: 28, title: 'Peach', name: 'Peach' }, -]; - -export const brandsData: { id: number; title: string; name: string }[] = [ - { id: 1, title: 'Yoone', name: 'YOONE' }, - { id: 2, title: 'White Fox', name: 'WHITE_FOX' }, - { id: 3, title: 'ZYN', name: 'ZYN' }, - { id: 4, title: 'Zonnic', name: 'ZONNIC' }, - { id: 5, title: 'Zolt', name: 'ZOLT' }, - { id: 6, title: 'Velo', name: 'VELO' }, - { id: 7, title: 'Lucy', name: 'LUCY' }, - { id: 8, title: 'EGP', name: 'EGP' }, - { id: 9, title: 'Bridge', name: 'BRIDGE' }, - { id: 10, title: 'ZEX', name: 'ZEX' }, - { id: 11, title: 'Sesh', name: 'Sesh' }, - { id: 12, title: 'Pablo', name: 'Pablo' }, -]; - -export const strengthsData: { id: number; title: string; name: string }[] = [ - { id: 1, title: '3MG', name: '3MG' }, - { id: 2, title: '9MG', name: '9MG' }, - { id: 3, title: '2MG', name: '2MG' }, - { id: 4, title: '4MG', name: '4MG' }, - { id: 5, title: '12MG', name: '12MG' }, - { id: 6, title: '18MG', name: '18MG' }, - { id: 7, title: '6MG', name: '6MG' }, - { id: 8, title: '16.5MG', name: '16.5MG' }, - { id: 9, title: '6.5MG', name: '6.5MG' }, - { id: 10, title: '30MG', name: '30MG' }, -]; \ No newline at end of file diff --git a/src/db/seed/index.ts b/src/db/seed/index.ts deleted file mode 100644 index 2e1ba10..0000000 --- a/src/db/seed/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { createConnection } from 'typeorm'; -import { Dict } from '../../entity/dict.entity'; -import { DictItem } from '../../entity/dict_item.entity'; -import { brandsData, flavorsData, strengthsData } from './dict'; - -async function seed() { - const connection = await createConnection(); - - // 创建字典 - const brandDict = await connection.manager.save(Dict, { name: '品牌', unique_key: 'brand' }); - const flavorDict = await connection.manager.save(Dict, { name: '口味', unique_key: 'flavor' }); - const strengthDict = await connection.manager.save(Dict, { name: '规格', unique_key: 'strength' }); - - // 植入品牌数据 - for (const brand of brandsData) { - await connection.manager.save(DictItem, { - name: brand.name, - unique_key: brand.unique_key, - dict_id: brandDict.id, - }); - } - - // 植入口味数据 - for (const flavor of flavorsData) { - await connection.manager.save(DictItem, { - name: flavor.name, - unique_key: flavor.unique_key, - dict_id: flavorDict.id, - }); - } - - // 植入规格数据 - for (const strength of strengthsData) { - await connection.manager.save(DictItem, { - name: strength.name, - unique_key: strength.unique_key, - dict_id: strengthDict.id, - }); - } - - await connection.close(); -} - -seed().catch(error => console.error(error)); diff --git a/src/db/seeds/dict.seeder.ts b/src/db/seeds/dict.seeder.ts new file mode 100644 index 0000000..2201f54 --- /dev/null +++ b/src/db/seeds/dict.seeder.ts @@ -0,0 +1,113 @@ +import { Seeder, SeederFactoryManager } from 'typeorm-extension'; +import { DataSource } from 'typeorm'; +import { Dict } from '../../entity/dict.entity'; +import { DictItem } from '../../entity/dict_item.entity'; + +export default class DictSeeder implements Seeder { + public async run( + dataSource: DataSource, + factoryManager: SeederFactoryManager + ): Promise { + const dictRepository = dataSource.getRepository(Dict); + const dictItemRepository = dataSource.getRepository(DictItem); + + const flavorsData = [ + { id: 1, title: 'Bellini Mini', name: 'Bellini Mini' }, + { id: 2, title: 'Max Polarmint', name: 'Max Polarmint' }, + { id: 3, title: 'Blueberry', name: 'Blueberry' }, + { id: 4, title: 'Citrus', name: 'Citrus' }, + { id: 5, title: 'Wintergreen', name: 'Wintergreen' }, + { id: 6, title: 'COOL MINT', name: 'COOL MINT' }, + { id: 7, title: 'JUICY PEACH', name: 'JUICY PEACH' }, + { id: 8, title: 'ORANGE', name: 'ORANGE' }, + { id: 9, title: 'PEPPERMINT', name: 'PEPPERMINT' }, + { id: 10, title: 'SPEARMINT', name: 'SPEARMINT' }, + { id: 11, title: 'STRAWBERRY', name: 'STRAWBERRY' }, + { id: 12, title: 'WATERMELON', name: 'WATERMELON' }, + { id: 13, title: 'COFFEE', name: 'COFFEE' }, + { id: 14, title: 'LEMONADE', name: 'LEMONADE' }, + { id: 15, title: 'apple mint', name: 'apple mint' }, + { id: 16, title: 'PEACH', name: 'PEACH' }, + { id: 17, title: 'Mango', name: 'Mango' }, + { id: 18, title: 'ICE WINTERGREEN', name: 'ICE WINTERGREEN' }, + { id: 19, title: 'Pink Lemonade', name: 'Pink Lemonade' }, + { id: 20, title: 'Blackcherry', name: 'Blackcherry' }, + { id: 21, title: 'fresh mint', name: 'fresh mint' }, + { id: 22, title: 'Strawberry Lychee', name: 'Strawberry Lychee' }, + { id: 23, title: 'Passion Fruit', name: 'Passion Fruit' }, + { id: 24, title: 'Banana lce', name: 'Banana lce' }, + { id: 25, title: 'Bubblegum', name: 'Bubblegum' }, + { id: 26, title: 'Mango lce', name: 'Mango lce' }, + { id: 27, title: 'Grape lce', name: 'Grape lce' }, + ]; + + const brandsData = [ + { id: 1, title: 'Yoone', name: 'YOONE' }, + { id: 2, title: 'White Fox', name: 'WHITE_FOX' }, + { id: 3, title: 'ZYN', name: 'ZYN' }, + { id: 4, title: 'Zonnic', name: 'ZONNIC' }, + { id: 5, title: 'Zolt', name: 'ZOLT' }, + { id: 6, title: 'Velo', name: 'VELO' }, + { id: 7, title: 'Lucy', name: 'LUCY' }, + { id: 8, title: 'EGP', name: 'EGP' }, + { id: 9, title: 'Bridge', name: 'BRIDGE' }, + { id: 10, title: 'ZEX', name: 'ZEX' }, + { id: 11, title: 'Sesh', name: 'Sesh' }, + { id: 12, title: 'Pablo', name: 'Pablo' }, + ]; + + const strengthsData = [ + { id: 1, title: '3MG', name: '3MG' }, + { id: 2, title: '9MG', name: '9MG' }, + { id: 3, title: '2MG', name: '2MG' }, + { id: 4, title: '4MG', name: '4MG' }, + { id: 5, title: '12MG', name: '12MG' }, + { id: 6, title: '18MG', name: '18MG' }, + { id: 7, title: '6MG', name: '6MG' }, + { id: 8, title: '16.5MG', name: '16.5MG' }, + { id: 9, title: '6.5MG', name: '6.5MG' }, + { id: 10, title: '30MG', name: '30MG' }, + ]; + + // 在插入新数据前,清空旧数据 + await dictItemRepository.query('DELETE FROM `dict_item`'); + await dictRepository.query('DELETE FROM `dict`'); + // 重置自增 ID + await dictItemRepository.query('ALTER TABLE `dict_item` AUTO_INCREMENT = 1'); + await dictRepository.query('ALTER TABLE `dict` AUTO_INCREMENT = 1'); + + const brandDict = await dictRepository.save({ title: '品牌', name: 'brand' }); + const flavorDict = await dictRepository.save({ title: '口味', name: 'flavor' }); + const strengthDict = await dictRepository.save({ title: '强度', name: 'strength' }); + + // 遍历品牌数据 + for (const brand of brandsData) { + // 保存字典项,并关联到品牌字典 + await dictItemRepository.save({ + title: brand.title, + name: brand.name, + dict: brandDict, + }); + } + + // 遍历口味数据 + for (const flavor of flavorsData) { + // 保存字典项,并关联到口味字典 + await dictItemRepository.save({ + title: flavor.title, + name: flavor.name, + dict: flavorDict, + }); + } + + // 遍历强度数据 + for (const strength of strengthsData) { + // 保存字典项,并关联到强度字典 + await dictItemRepository.save({ + title: strength.title, + name: strength.name, + dict: strengthDict, + }); + } + } +} diff --git a/src/dto/product.dto.ts b/src/dto/product.dto.ts index d952151..6616a82 100644 --- a/src/dto/product.dto.ts +++ b/src/dto/product.dto.ts @@ -1,6 +1,16 @@ import { ApiProperty } from '@midwayjs/swagger'; import { Rule, RuleType } from '@midwayjs/validate'; +class DictItemDTO { + @ApiProperty({ description: '显示名称', required: false }) + @Rule(RuleType.string()) + title?: string; + + @ApiProperty({ description: '唯一标识', required: true }) + @Rule(RuleType.string().required()) + name: string; +} + /** * DTO 用于创建产品 */ @@ -17,17 +27,17 @@ export class CreateProductDTO { @Rule(RuleType.string()) description: string; - @ApiProperty({ example: '1', description: '分类 ID' }) - @Rule(RuleType.number()) - categoryId: number; + @ApiProperty({ description: '品牌', type: DictItemDTO }) + @Rule(RuleType.object().keys({ title: RuleType.string().required(), name: RuleType.string() })) + brand: DictItemDTO; - @ApiProperty() - @Rule(RuleType.number()) - strengthId: number; + @ApiProperty({ description: '规格', type: DictItemDTO }) + @Rule(RuleType.object().keys({ title: RuleType.string().required(), name: RuleType.string() })) + strength: DictItemDTO; - @ApiProperty() - @Rule(RuleType.number()) - flavorsId: number; + @ApiProperty({ description: '口味', type: DictItemDTO }) + @Rule(RuleType.object().keys({ title: RuleType.string().required(), name: RuleType.string() })) + flavor: DictItemDTO; @ApiProperty() @Rule(RuleType.string()) @@ -59,36 +69,41 @@ export class QueryProductDTO { @Rule(RuleType.string()) name: string; - @ApiProperty({ example: '1', description: '分类 ID' }) + @ApiProperty({ example: '1', description: '品牌 ID' }) @Rule(RuleType.string()) - categoryId: number; + brandId: number; } /** - * DTO 用于创建分类 + * DTO 用于创建品牌 */ -export class CreateCategoryDTO { - @ApiProperty({ example: 'ZYN', description: '分类名称', required: true }) - @Rule(RuleType.string().required().empty({ message: '分类名称不能为空' })) - name: string; +export class CreateBrandDTO { + @ApiProperty({ example: 'ZYN', description: '品牌名称', required: true }) + @Rule(RuleType.string().required().empty({ message: '品牌名称不能为空' })) + title: string; + @ApiProperty({ example: 'ZYN', description: '品牌唯一标识', required: true }) @Rule(RuleType.string().required().empty({ message: 'key不能为空' })) - unique_key: string; + name: string; } /** - * DTO 用于更新分类 + * DTO 用于更新品牌 */ -export class UpdateCategoryDTO { - @ApiProperty({ example: 'ZYN', description: '分类名称' }) +export class UpdateBrandDTO { + @ApiProperty({ example: 'ZYN', description: '品牌名称' }) + @Rule(RuleType.string()) + title: string; + + @ApiProperty({ example: 'ZYN', description: '品牌唯一标识' }) @Rule(RuleType.string()) name: string; } /** - * DTO 用于查询分类(支持分页) + * DTO 用于查询品牌(支持分页) */ -export class QueryCategoryDTO { +export class QueryBrandDTO { @ApiProperty({ example: '1', description: '页码' }) @Rule(RuleType.number()) current: number; // 页码 @@ -98,21 +113,30 @@ export class QueryCategoryDTO { pageSize: number; // 每页大小 @ApiProperty({ example: 'ZYN', description: '关键字' }) - @Rule(RuleType.string()) + @Rule(RuleType.string().required()) name: string; // 搜索关键字(支持模糊查询) } export class CreateFlavorsDTO { - @ApiProperty({ example: 'ZYN', description: '分类名称', required: true }) - @Rule(RuleType.string().required().empty({ message: '分类名称不能为空' })) - name: string; + @ApiProperty({ example: 'WINTERGREEN', description: '口味名称', required: true }) + @Rule(RuleType.string().required().empty({ message: '口味名称不能为空' })) + title: string; + @ApiProperty({ + example: 'WINTERGREEN', + description: '口味唯一标识', + required: true, + }) @Rule(RuleType.string().required().empty({ message: 'key不能为空' })) - unique_key: string; + name: string; } export class UpdateFlavorsDTO { - @ApiProperty({ example: 'ZYN', description: '分类名称' }) + @ApiProperty({ example: 'WINTERGREEN', description: '口味名称' }) + @Rule(RuleType.string()) + title: string; + + @ApiProperty({ example: 'WINTERGREEN', description: '口味唯一标识' }) @Rule(RuleType.string()) name: string; } @@ -132,16 +156,21 @@ export class QueryFlavorsDTO { } export class CreateStrengthDTO { - @ApiProperty({ example: 'ZYN', description: '分类名称', required: true }) - @Rule(RuleType.string().required().empty({ message: '分类名称不能为空' })) - name: string; + @ApiProperty({ example: '6MG', description: '规格名称', required: false }) + @Rule(RuleType.string()) + title?: string; + @ApiProperty({ example: '6MG', description: '规格唯一标识', required: true }) @Rule(RuleType.string().required().empty({ message: 'key不能为空' })) - unique_key: string; + name: string; } export class UpdateStrengthDTO { - @ApiProperty({ example: 'ZYN', description: '分类名称' }) + @ApiProperty({ example: '6MG', description: '规格名称' }) + @Rule(RuleType.string()) + title: string; + + @ApiProperty({ example: '6MG', description: '规格唯一标识' }) @Rule(RuleType.string()) name: string; } @@ -155,7 +184,7 @@ export class QueryStrengthDTO { @Rule(RuleType.number()) pageSize: number; // 每页大小 - @ApiProperty({ example: 'ZYN', description: '关键字' }) + @ApiProperty({ example: 'YOONE', description: '关键字' }) @Rule(RuleType.string()) name: string; // 搜索关键字(支持模糊查询) } diff --git a/src/dto/reponse.dto.ts b/src/dto/reponse.dto.ts index f4aae3c..6ee01ee 100644 --- a/src/dto/reponse.dto.ts +++ b/src/dto/reponse.dto.ts @@ -1,5 +1,4 @@ import { ApiProperty } from '@midwayjs/swagger'; -import { Category } from '../entity/category.entity'; import { Order } from '../entity/order.entity'; import { Product } from '../entity/product.entity'; import { StockPoint } from '../entity/stock_point.entity'; @@ -18,12 +17,11 @@ import { Service } from '../entity/service.entity'; import { RateDTO } from './freightcom.dto'; import { ShippingAddress } from '../entity/shipping_address.entity'; import { OrderItem } from '../entity/order_item.entity'; -import { OrderRefundItem } from '../entity/order_retund_item.entity'; +import { OrderRefundItem } from '../entity/order_refund_item.entity'; import { OrderNote } from '../entity/order_note.entity'; import { PaymentMethodDTO } from './logistics.dto'; -import { Flavors } from '../entity/flavors.entity'; -import { Strength } from '../entity/strength.entity'; import { Subscription } from '../entity/subscription.entity'; +import { Dict } from '../entity/dict.entity'; export class BooleanRes extends SuccessWrapper(Boolean) {} //网站配置返回数据 @@ -35,18 +33,38 @@ export class ProductListRes extends SuccessWrapper(ProductPaginatedResponse) {} //产品返回数据 export class ProductRes extends SuccessWrapper(Product) {} export class ProductsRes extends SuccessArrayWrapper(Product) {} -//产品分类返分页数据 -export class CategoryPaginatedResponse extends PaginatedWrapper(Category) {} -export class FlavorsPaginatedResponse extends PaginatedWrapper(Flavors) {} -export class StrengthPaginatedResponse extends PaginatedWrapper(Strength) {} -//产品分类返分页返回数据 -export class ProductCatListRes extends SuccessWrapper( - CategoryPaginatedResponse +//产品品牌返分页数据 +export class BrandPaginatedResponse extends PaginatedWrapper(Dict) {} +//产品品牌返分页返回数据 +export class ProductBrandListRes extends SuccessWrapper( + BrandPaginatedResponse ) {} -//产品分类返所有数据 -export class ProductCatAllRes extends SuccessArrayWrapper(Category) {} -//产品分类返回数据 -export class ProductCatRes extends SuccessWrapper(Category) {} +//产品品牌返所有数据 +export class ProductBrandAllRes extends SuccessArrayWrapper(Dict) {} +//产品品牌返回数据 +export class ProductBrandRes extends SuccessWrapper(Dict) {} + +//产品口味返分页数据 +export class FlavorsPaginatedResponse extends PaginatedWrapper(Dict) {} +//产品口味返分页返回数据 +export class ProductFlavorsListRes extends SuccessWrapper( + FlavorsPaginatedResponse +) {} +//产品口味返所有数据 +export class ProductFlavorsAllRes extends SuccessArrayWrapper(Dict) {} +//产品口味返回数据 +export class ProductFlavorsRes extends SuccessWrapper(Dict) {} + +//产品规格返分页数据 +export class StrengthPaginatedResponse extends PaginatedWrapper(Dict) {} +//产品规格返分页返回数据 +export class ProductStrengthListRes extends SuccessWrapper( + StrengthPaginatedResponse +) {} +//产品规格返所有数据 +export class ProductStrengthAllRes extends SuccessArrayWrapper(Dict) {} +//产品规格返回数据 +export class ProductStrengthRes extends SuccessWrapper(Dict) {} //产品分页数据 export class WpProductPaginatedResponse extends PaginatedWrapper( diff --git a/src/entity/category.entity.ts b/src/entity/category.entity.ts deleted file mode 100644 index 2e52e8a..0000000 --- a/src/entity/category.entity.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - PrimaryGeneratedColumn, - Column, - CreateDateColumn, - UpdateDateColumn, - Entity, -} from 'typeorm'; -import { ApiProperty } from '@midwayjs/swagger'; - -@Entity() -export class Category { - @ApiProperty({ - example: '1', - description: '分类 ID', - type: 'number', - required: true, - }) - @PrimaryGeneratedColumn() - id: number; - - @ApiProperty({ - example: '分类名称', - description: '分类名称', - type: 'string', - required: true, - }) - @Column() - name: string; - - @ApiProperty({ - description: '唯一识别key', - type: 'string', - required: true, - }) - @Column() - unique_key: string; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '创建时间', - required: true, - }) - @CreateDateColumn() - createdAt: Date; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '更新时间', - required: true, - }) - @UpdateDateColumn() - updatedAt: Date; -} diff --git a/src/entity/dict.entity.ts b/src/entity/dict.entity.ts new file mode 100644 index 0000000..3a63ce1 --- /dev/null +++ b/src/entity/dict.entity.ts @@ -0,0 +1,39 @@ +/** + * @description 字典 + * @author ZKS + * @date 2025-11-27 + */ +import { DictItem } from './dict_item.entity'; +import { + Column, + CreateDateColumn, + Entity, + OneToMany, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity() +export class Dict { + // 主键 + @PrimaryGeneratedColumn() + id: number; + + @Column({comment: '字典显示名称'}) + title: string; + // 字典名称 + @Column({ unique: true, comment: '字典名称' }) + name: string; + + // 字典项 + @OneToMany(() => DictItem, item => item.dict) + items: DictItem[]; + + // 创建时间 + @CreateDateColumn() + createdAt: Date; + + // 更新时间 + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/src/entity/dict_item.entity.ts b/src/entity/dict_item.entity.ts new file mode 100644 index 0000000..4a4ac1a --- /dev/null +++ b/src/entity/dict_item.entity.ts @@ -0,0 +1,43 @@ +/** + * @description 字典项 + * @author ZKS + * @date 2025-11-27 + */ +import { Dict } from './dict.entity'; +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity() +export class DictItem { + // 主键 + @PrimaryGeneratedColumn() + id: number; + + // 字典项名称 + @Column({ comment: '字典项显示名称' }) + title: string; + + // 唯一标识 + @Column({ unique: true, comment: '字典唯一标识名称' }) + name: string; + + // 属于哪个字典 + @ManyToOne(() => Dict, dict => dict.items) + @JoinColumn({ name: 'dict_id' }) + dict: Dict; + + // 创建时间 + @CreateDateColumn() + createdAt: Date; + + // 更新时间 + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/src/entity/flavors.entity.ts b/src/entity/flavors.entity.ts deleted file mode 100644 index 9b0cb10..0000000 --- a/src/entity/flavors.entity.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - PrimaryGeneratedColumn, - Column, - CreateDateColumn, - UpdateDateColumn, - Entity, -} from 'typeorm'; -import { ApiProperty } from '@midwayjs/swagger'; - -@Entity() -export class Flavors { - @ApiProperty() - @PrimaryGeneratedColumn() - id: number; - - @ApiProperty() - @Column() - name: string; - - @ApiProperty({ - description: '唯一识别key', - type: 'string', - required: true, - }) - @Column() - unique_key: string; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '创建时间', - required: true, - }) - @CreateDateColumn() - createdAt: Date; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '更新时间', - required: true, - }) - @UpdateDateColumn() - updatedAt: Date; -} diff --git a/src/entity/order_copon.entity.ts b/src/entity/order_coupon.entity.ts similarity index 99% rename from src/entity/order_copon.entity.ts rename to src/entity/order_coupon.entity.ts index c1a16bd..f045620 100644 --- a/src/entity/order_copon.entity.ts +++ b/src/entity/order_coupon.entity.ts @@ -22,7 +22,7 @@ export class OrderCoupon { orderId: number; // 订单 ID @ApiProperty() - @Column() + @Column( ) @Expose() siteId: string; // 来源站点唯一标识 diff --git a/src/entity/order_retund_item.entity.ts b/src/entity/order_refund_item.entity.ts similarity index 100% rename from src/entity/order_retund_item.entity.ts rename to src/entity/order_refund_item.entity.ts diff --git a/src/entity/product.entity.ts b/src/entity/product.entity.ts index 67fa486..dc72c9e 100644 --- a/src/entity/product.entity.ts +++ b/src/entity/product.entity.ts @@ -35,9 +35,9 @@ export class Product { @Column({ nullable: true }) description?: string; - @ApiProperty({ example: '1', description: '分类 ID', type: 'number' }) + @ApiProperty({ example: '1', description: '品牌 ID', type: 'number' }) @Column() - categoryId: number; + brandId: number; @ApiProperty({ description: '口味ID' }) @Column() diff --git a/src/entity/site.entity.ts b/src/entity/site.entity.ts index d4e3215..a4c58e4 100644 --- a/src/entity/site.entity.ts +++ b/src/entity/site.entity.ts @@ -2,27 +2,27 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; @Entity('site') export class Site { - @PrimaryGeneratedColumn({ type: 'int' }) + @PrimaryGeneratedColumn() id: number; - @Column({ type: 'varchar', length: 255, nullable: true }) + @Column({ length: 255, nullable: true }) apiUrl: string; - @Column({ type: 'varchar', length: 255, nullable: true }) + @Column({ length: 255, nullable: true }) consumerKey: string; - @Column({ type: 'varchar', length: 255, nullable: true }) + @Column({ length: 255, nullable: true }) consumerSecret: string; - @Column({ type: 'varchar', length: 255, unique: true }) + @Column({ length: 255, unique: true }) siteName: string; - @Column({ type: 'varchar', length: 32, default: 'woocommerce' }) + @Column({ length: 32, default: 'woocommerce' }) type: string; // 平台类型:woocommerce | shopyy - @Column({ type: 'varchar', length: 64, nullable: true }) + @Column({ length: 64, nullable: true }) skuPrefix: string; - @Column({ type: 'tinyint', default: 0 }) - isDisabled: number; + @Column({ default: false }) + isDisabled: boolean; } \ No newline at end of file diff --git a/src/entity/strength.entity.ts b/src/entity/strength.entity.ts deleted file mode 100644 index 9ffc916..0000000 --- a/src/entity/strength.entity.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - PrimaryGeneratedColumn, - Column, - CreateDateColumn, - UpdateDateColumn, - Entity, -} from 'typeorm'; -import { ApiProperty } from '@midwayjs/swagger'; - -@Entity() -export class Strength { - @ApiProperty() - @PrimaryGeneratedColumn() - id: number; - - @ApiProperty() - @Column() - name: string; - - @ApiProperty({ - description: '唯一识别key', - type: 'string', - required: true, - }) - @Column() - unique_key: string; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '创建时间', - required: true, - }) - @CreateDateColumn() - createdAt: Date; - - @ApiProperty({ - example: '2022-12-12 11:11:11', - description: '更新时间', - required: true, - }) - @UpdateDateColumn() - updatedAt: Date; -} diff --git a/src/service/order.service.ts b/src/service/order.service.ts index d62baf9..d0872ed 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -12,8 +12,8 @@ import { WpProduct } from '../entity/wp_product.entity'; import { Product } from '../entity/product.entity'; import { OrderFee } from '../entity/order_fee.entity'; import { OrderRefund } from '../entity/order_refund.entity'; -import { OrderRefundItem } from '../entity/order_retund_item.entity'; -import { OrderCoupon } from '../entity/order_copon.entity'; +import { OrderRefundItem } from '../entity/order_refund_item.entity'; +import { OrderCoupon } from '../entity/order_coupon.entity'; import { OrderShipping } from '../entity/order_shipping.entity'; import { Shipment } from '../entity/shipment.entity'; import { Customer } from '../entity/customer.entity'; diff --git a/src/service/product.service.ts b/src/service/product.service.ts index 22973d5..5baf29e 100644 --- a/src/service/product.service.ts +++ b/src/service/product.service.ts @@ -1,21 +1,20 @@ -import { Provide } from '@midwayjs/core'; +import { Inject, Provide } from '@midwayjs/core'; import { In, Like, Not, Repository } from 'typeorm'; import { Product } from '../entity/product.entity'; -import { Category } from '../entity/category.entity'; import { paginate } from '../utils/paginate.util'; import { PaginationParams } from '../interface'; import { - CreateCategoryDTO, + CreateBrandDTO, CreateFlavorsDTO, CreateProductDTO, CreateStrengthDTO, - UpdateCategoryDTO, + UpdateBrandDTO, UpdateFlavorsDTO, UpdateProductDTO, UpdateStrengthDTO, } from '../dto/product.dto'; import { - CategoryPaginatedResponse, + BrandPaginatedResponse, FlavorsPaginatedResponse, ProductPaginatedResponse, StrengthPaginatedResponse, @@ -23,22 +22,23 @@ import { import { InjectEntityModel } from '@midwayjs/typeorm'; import { WpProduct } from '../entity/wp_product.entity'; import { Variation } from '../entity/variation.entity'; -import { Strength } from '../entity/strength.entity'; -import { Flavors } from '../entity/flavors.entity'; +import { Dict } from '../entity/dict.entity'; +import { DictItem } from '../entity/dict_item.entity'; +import { Context } from '@midwayjs/koa'; @Provide() export class ProductService { + @Inject() + ctx: Context; + @InjectEntityModel(Product) productModel: Repository; - @InjectEntityModel(Category) - categoryModel: Repository; + @InjectEntityModel(Dict) + dictModel: Repository; - @InjectEntityModel(Strength) - strengthModel: Repository; - - @InjectEntityModel(Flavors) - flavorsModel: Repository; + @InjectEntityModel(DictItem) + dictItemModel: Repository; @InjectEntityModel(WpProduct) wpProductModel: Repository; @@ -111,15 +111,42 @@ export class ProductService { async getProductList( pagination: PaginationParams, name?: string, - categoryId?: number + brandId?: number ): Promise { const nameFilter = name ? name.split(' ').filter(Boolean) : []; + // 查询品牌、口味、规格字典 + const brandDict = await this.dictModel.findOne({ + where: { name: 'brand' }, + }); + const flavorDict = await this.dictModel.findOne({ + where: { name: 'flavor' }, + }); + const strengthDict = await this.dictModel.findOne({ + where: { name: 'strength' }, + }); + + // 构建查询 const qb = this.productModel .createQueryBuilder('product') - .leftJoin(Category, 'category', 'category.id = product.categoryId') - .leftJoin(Strength, 'strength', 'strength.id = product.strengthId') - .leftJoin(Flavors, 'flavors', 'flavors.id = product.flavorsId') + .leftJoin( + DictItem, + 'brand', + 'brand.id = product.brandId AND brand.dict_id = :brandDictId', + { brandDictId: brandDict?.id } + ) + .leftJoin( + DictItem, + 'flavor', + 'flavor.id = product.flavorsId AND flavor.dict_id = :flavorDictId', + { flavorDictId: flavorDict?.id } + ) + .leftJoin( + DictItem, + 'strength', + 'strength.id = product.strengthId AND strength.dict_id = :strengthDictId', + { strengthDictId: strengthDict?.id } + ) .select([ 'product.id as id', 'product.name as name', @@ -129,9 +156,9 @@ export class ProductService { 'product.sku as sku', 'product.createdAt as createdAt', 'product.updatedAt as updatedAt', - 'category.name AS categoryName', - 'strength.name AS strengthName', - 'flavors.name AS flavorsName', + 'brand.title AS brandName', + 'flavor.title AS flavorsName', + 'strength.title AS strengthName', ]); // 模糊搜索 name,支持多个关键词 @@ -141,9 +168,9 @@ export class ProductService { }); }); - // 分类过滤 - if (categoryId) { - qb.andWhere('product.categoryId = :categoryId', { categoryId }); + // 品牌过滤 + if (brandId) { + qb.andWhere('product.brandId = :brandId', { brandId }); } // 分页 @@ -162,35 +189,79 @@ export class ProductService { }; } + async getOrCreateDictItem( + dictName: string, + itemTitle: string, + itemName?: string + ): Promise { + // 查找字典 + const dict = await this.dictModel.findOne({ where: { name: dictName } }); + if (!dict) { + throw new Error(`字典 '${dictName}' 不存在`); + } + + // 查找字典项 + let item = await this.dictItemModel.findOne({ + where: { title: itemTitle, dict_id: dict.id }, + }); + + // 如果字典项不存在,则创建 + if (!item) { + item = new DictItem(); + item.title = itemTitle; + item.name = itemName || itemTitle; // 如果没有提供 name,则使用 title + item.dict_id = dict.id; + await this.dictItemModel.save(item); + } + + return item; + } + async createProduct(createProductDTO: CreateProductDTO): Promise { - const { name, description, categoryId, strengthId, flavorsId, humidity } = + const { name, description, brand, flavor, strength, humidity } = createProductDTO; + + // 获取或创建品牌、口味、规格 + const brandItem = await this.getOrCreateDictItem( + 'brand', + brand.title, + brand.name + ); + const flavorItem = await this.getOrCreateDictItem( + 'flavor', + flavor.title, + flavor.name + ); + const strengthItem = await this.getOrCreateDictItem( + 'strength', + strength.title, + strength.name + ); + + // 检查产品是否已存在 const isExit = await this.productModel.findOne({ where: { - categoryId, - strengthId, - flavorsId, + brandId: brandItem.id, + flavorsId: flavorItem.id, + strengthId: strengthItem.id, humidity, }, }); if (isExit) throw new Error('产品已存在'); + + // 创建新产品实例 const product = new Product(); product.name = name; product.description = description; - product.categoryId = categoryId; - product.strengthId = strengthId; - product.flavorsId = flavorsId; + product.brandId = brandItem.id; + product.flavorsId = flavorItem.id; + product.strengthId = strengthItem.id; product.humidity = humidity; - const categoryKey = ( - await this.categoryModel.findOne({ where: { id: categoryId } }) - ).unique_key; - const strengthKey = ( - await this.strengthModel.findOne({ where: { id: strengthId } }) - ).unique_key; - const flavorsKey = ( - await this.flavorsModel.findOne({ where: { id: flavorsId } }) - ).unique_key; - product.sku = `${categoryKey}-${flavorsKey}-${strengthKey}-${humidity}`; + + // 生成 SKU + product.sku = `${brandItem.name}-${flavorItem.name}-${strengthItem.name}-${humidity}`; + + // 保存产品 return await this.productModel.save(product); } @@ -257,67 +328,126 @@ export class ProductService { return result.affected > 0; // `affected` 表示删除的行数 } - async hasProductsInCategory(categoryId: number): Promise { + async hasProductsInBrand(brandId: number): Promise { + // 检查是否有产品属于该品牌 const count = await this.productModel.count({ - where: { categoryId }, + where: { brandId }, }); return count > 0; } - async hasCategory(name: string, id?: string): Promise { - const where: any = { name }; + async hasBrand(title: string, id?: number): Promise { + // 查找 'brand' 字典 + const brandDict = await this.dictModel.findOne({ + where: { name: 'brand' }, + }); + + // 如果字典不存在,则品牌不存在 + if (!brandDict) { + return false; + } + + // 设置查询条件 + const where: any = { title, dict_id: brandDict.id }; if (id) where.id = Not(id); - const count = await this.categoryModel.count({ + + // 统计数量 + const count = await this.dictItemModel.count({ where, }); + return count > 0; } - async getCategoryList( + async getBrandList( pagination: PaginationParams, - name?: string - ): Promise { - const where: any = {}; - if (name) { - where.name = Like(`%${name}%`); + title?: string + ): Promise { + // 查找 'brand' 字典 + const brandDict = await this.dictModel.findOne({ + where: { name: 'brand' }, + }); + + // 如果字典不存在,则返回空 + if (!brandDict) { + return { + items: [], + total: 0, + ...pagination, + }; } - return await paginate(this.categoryModel, { pagination, where }); - } - async getCategoryAll(): Promise { - return await this.categoryModel.find(); - } - - async createCategory( - createCategoryDTO: CreateCategoryDTO - ): Promise { - const { name, unique_key } = createCategoryDTO; - const category = new Category(); - category.name = name; - category.unique_key = unique_key; - return await this.categoryModel.save(category); - } - - async updateCategory(id: number, updateCategory: UpdateCategoryDTO) { - // 确认产品是否存在 - const category = await this.categoryModel.findOneBy({ id }); - if (!category) { - throw new Error(`产品分类 ID ${id} 不存在`); + // 设置查询条件 + const where: any = { dict_id: brandDict.id }; + if (title) { + where.title = Like(`%${title}%`); } - // 更新产品 - await this.categoryModel.update(id, updateCategory); - // 返回更新后的产品 - return await this.categoryModel.findOneBy({ id }); + + // 分页查询 + return await paginate(this.dictItemModel, { pagination, where }); } - async deleteCategory(id: number): Promise { - // 检查产品是否存在 - const category = await this.categoryModel.findOneBy({ id }); - if (!category) { - throw new Error(`产品分类 ID ${id} 不存在`); + async getBrandAll(): Promise { + // 查找 'brand' 字典 + const brandDict = await this.dictModel.findOne({ + where: { name: 'brand' }, + }); + + // 如果字典不存在,则返回空数组 + if (!brandDict) { + return []; } - // 删除产品 - const result = await this.categoryModel.delete(id); + + // 返回所有品牌 + return this.dictItemModel.find({ where: { dict_id: brandDict.id } }); + } + + async createBrand(createBrandDTO: CreateBrandDTO): Promise { + const { title, name } = createBrandDTO; + + // 查找 'brand' 字典 + const brandDict = await this.dictModel.findOne({ + where: { name: 'brand' }, + }); + + // 如果字典不存在,则抛出错误 + if (!brandDict) { + throw new Error('品牌字典不存在'); + } + + // 创建新的品牌实例 + const brand = new DictItem(); + brand.title = title; + brand.name = name; + brand.dict_id = brandDict.id; + + // 保存到数据库 + return await this.dictItemModel.save(brand); + } + + async updateBrand(id: number, updateBrand: UpdateBrandDTO) { + // 确认品牌是否存在 + const brand = await this.dictItemModel.findOneBy({ id }); + if (!brand) { + throw new Error(`品牌 ID ${id} 不存在`); + } + + // 更新品牌 + await this.dictItemModel.update(id, updateBrand); + + // 返回更新后的品牌 + return await this.dictItemModel.findOneBy({ id }); + } + + async deleteBrand(id: number): Promise { + // 检查品牌是否存在 + const brand = await this.dictItemModel.findOneBy({ id }); + if (!brand) { + throw new Error(`品牌 ID ${id} 不存在`); + } + + // 删除品牌 + const result = await this.dictItemModel.delete(id); return result.affected > 0; // `affected` 表示删除的行数 } @@ -328,58 +458,82 @@ export class ProductService { return count > 0; } - async hasFlavors(name: string, id?: string): Promise { - const where: any = { name }; + async hasFlavors(title: string, id?: string): Promise { + const flavorsDict = await this.dictModel.findOne({ + where: { name: 'flavor' }, + }); + if (!flavorsDict) { + return false; + } + const where: any = { title, dict_id: flavorsDict.id }; if (id) where.id = Not(id); - const count = await this.flavorsModel.count({ + const count = await this.dictItemModel.count({ where, }); return count > 0; } async getFlavorsList( pagination: PaginationParams, - name?: string + title?: string ): Promise { - const where: any = {}; - if (name) { - where.name = Like(`%${name}%`); + const flavorsDict = await this.dictModel.findOne({ + where: { name: 'flavor' }, + }); + if (!flavorsDict) { + return { + items: [], + total: 0, + ...pagination, + }; } - return await paginate(this.flavorsModel, { pagination, where }); + const where: any = { dict_id: flavorsDict.id }; + if (title) { + where.title = Like(`%${title}%`); + } + return await paginate(this.dictItemModel, { pagination, where }); } async getFlavorsAll(): Promise { - return await this.flavorsModel.find(); + const flavorsDict = await this.dictModel.findOne({ + where: { name: 'flavor' }, + }); + if (!flavorsDict) { + return []; + } + return this.dictItemModel.find({ where: { dict_id: flavorsDict.id } }); } - async createFlavors(createFlavorsDTO: CreateFlavorsDTO): Promise { - const { name, unique_key } = createFlavorsDTO; - const flavors = new Flavors(); + async createFlavors(createFlavorsDTO: CreateFlavorsDTO): Promise { + const { title, name } = createFlavorsDTO; + const flavorsDict = await this.dictModel.findOne({ + where: { name: 'flavor' }, + }); + if (!flavorsDict) { + throw new Error('口味字典不存在'); + } + const flavors = new DictItem(); + flavors.title = title; flavors.name = name; - flavors.unique_key = unique_key; - return await this.flavorsModel.save(flavors); + flavors.dict_id = flavorsDict.id; + return await this.dictItemModel.save(flavors); } async updateFlavors(id: number, updateFlavors: UpdateFlavorsDTO) { - // 确认产品是否存在 - const flavors = await this.flavorsModel.findOneBy({ id }); + const flavors = await this.dictItemModel.findOneBy({ id }); if (!flavors) { throw new Error(`口味 ID ${id} 不存在`); } - // 更新产品 - await this.flavorsModel.update(id, updateFlavors); - // 返回更新后的产品 - return await this.flavorsModel.findOneBy({ id }); + await this.dictItemModel.update(id, updateFlavors); + return await this.dictItemModel.findOneBy({ id }); } async deleteFlavors(id: number): Promise { - // 检查产品是否存在 - const flavors = await this.flavorsModel.findOneBy({ id }); + const flavors = await this.dictItemModel.findOneBy({ id }); if (!flavors) { throw new Error(`口味 ID ${id} 不存在`); } - // 删除产品 - const result = await this.flavorsModel.delete(id); - return result.affected > 0; // `affected` 表示删除的行数 + const result = await this.dictItemModel.delete(id); + return result.affected > 0; } async hasProductsInStrength(strengthId: number): Promise { const count = await this.productModel.count({ @@ -388,60 +542,82 @@ export class ProductService { return count > 0; } - async hasStrength(name: string, id?: string): Promise { - const where: any = { name }; + async hasStrength(title: string, id?: string): Promise { + const strengthDict = await this.dictModel.findOne({ + where: { name: 'strength' }, + }); + if (!strengthDict) { + return false; + } + const where: any = { title, dict_id: strengthDict.id }; if (id) where.id = Not(id); - const count = await this.strengthModel.count({ + const count = await this.dictItemModel.count({ where, }); return count > 0; } async getStrengthList( pagination: PaginationParams, - name?: string + title?: string ): Promise { - const where: any = {}; - if (name) { - where.name = Like(`%${name}%`); + const strengthDict = await this.dictModel.findOne({ + where: { name: 'strength' }, + }); + if (!strengthDict) { + return { + items: [], + total: 0, + ...pagination, + }; } - return await paginate(this.strengthModel, { pagination, where }); + const where: any = { dict_id: strengthDict.id }; + if (title) { + where.title = Like(`%${title}%`); + } + return await paginate(this.dictItemModel, { pagination, where }); } async getStrengthAll(): Promise { - return await this.strengthModel.find(); + const strengthDict = await this.dictModel.findOne({ + where: { name: 'strength' }, + }); + if (!strengthDict) { + return []; + } + return this.dictItemModel.find({ where: { dict_id: strengthDict.id } }); } - async createStrength( - createStrengthDTO: CreateStrengthDTO - ): Promise { - const { name, unique_key } = createStrengthDTO; - const strength = new Strength(); + async createStrength(createStrengthDTO: CreateStrengthDTO): Promise { + const { title, name } = createStrengthDTO; + const strengthDict = await this.dictModel.findOne({ + where: { name: 'strength' }, + }); + if (!strengthDict) { + throw new Error('规格字典不存在'); + } + const strength = new DictItem(); + strength.title = title; strength.name = name; - strength.unique_key = unique_key; - return await this.strengthModel.save(strength); + strength.dict_id = strengthDict.id; + return await this.dictItemModel.save(strength); } async updateStrength(id: number, updateStrength: UpdateStrengthDTO) { - // 确认产品是否存在 - const strength = await this.strengthModel.findOneBy({ id }); + const strength = await this.dictItemModel.findOneBy({ id }); if (!strength) { - throw new Error(`口味 ID ${id} 不存在`); + throw new Error(`规格 ID ${id} 不存在`); } - // 更新产品 - await this.strengthModel.update(id, updateStrength); - // 返回更新后的产品 - return await this.strengthModel.findOneBy({ id }); + await this.dictItemModel.update(id, updateStrength); + return await this.dictItemModel.findOneBy({ id }); } async deleteStrength(id: number): Promise { - // 检查产品是否存在 - const strength = await this.strengthModel.findOneBy({ id }); + const strength = await this.dictItemModel.findOneBy({ id }); if (!strength) { - throw new Error(`口味 ID ${id} 不存在`); + throw new Error(`规格 ID ${id} 不存在`); } - // 删除产品 - const result = await this.flavorsModel.delete(id); - return result.affected > 0; // `affected` 表示删除的行数 + const result = await this.dictItemModel.delete(id); + return result.affected > 0; } async batchSetSku(skus: { productId: number; sku: string }[]) {