diff --git a/bun.lock b/bun.lock
index 28ed1f0..0330b71 100644
--- a/bun.lock
+++ b/bun.lock
@@ -18,18 +18,20 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"decimal.js": "^10.6.0",
+ "docxtemplater": "^3.68.5",
"exceljs": "^4.4.0",
+ "file-saver": "^2.0.5",
"localforage": "^1.10.0",
"lucide-vue-next": "^0.563.0",
"motion-v": "^2.0.0",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
+ "pizzip": "^3.2.0",
"reka-ui": "^2.8.0",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"vue": "^3.5.25",
"vue-i18n": "^11.3.0",
- "vue-router": "^4.6.4",
"vuedraggable": "^4.1.0",
},
"devDependencies": {
@@ -45,548 +47,554 @@
},
},
"packages": {
- "@ag-grid-community/locale": ["@ag-grid-community/locale@35.1.0", "https://registry.npmmirror.com/@ag-grid-community/locale/-/locale-35.1.0.tgz", {}, "sha512-Tez1imtqfipMT3O1Ay+dyDcFJIj6H6gXBp45s44pwkzWQzxO20IBpZUrmAPTNRMYVZNXqCVbNsozWrPaVFAgeQ=="],
+ "@ag-grid-community/locale": ["@ag-grid-community/locale@35.1.0", "", {}, "sha512-Tez1imtqfipMT3O1Ay+dyDcFJIj6H6gXBp45s44pwkzWQzxO20IBpZUrmAPTNRMYVZNXqCVbNsozWrPaVFAgeQ=="],
- "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
+ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
- "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
+ "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
- "@babel/parser": ["@babel/parser@7.29.0", "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.0.tgz", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
+ "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="],
- "@babel/types": ["@babel/types@7.29.0", "https://registry.npmmirror.com/@babel/types/-/types-7.29.0.tgz", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
+ "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
- "@emnapi/core": ["@emnapi/core@1.8.1", "https://registry.npmmirror.com/@emnapi/core/-/core-1.8.1.tgz", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
+ "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
- "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.8.1.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
+ "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
- "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
+ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
- "@fast-csv/format": ["@fast-csv/format@4.3.5", "https://registry.npmmirror.com/@fast-csv/format/-/format-4.3.5.tgz", { "dependencies": { "@types/node": "^14.0.1", "lodash.escaperegexp": "^4.1.2", "lodash.isboolean": "^3.0.3", "lodash.isequal": "^4.5.0", "lodash.isfunction": "^3.0.9", "lodash.isnil": "^4.0.0" } }, "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A=="],
+ "@fast-csv/format": ["@fast-csv/format@4.3.5", "", { "dependencies": { "@types/node": "^14.0.1", "lodash.escaperegexp": "^4.1.2", "lodash.isboolean": "^3.0.3", "lodash.isequal": "^4.5.0", "lodash.isfunction": "^3.0.9", "lodash.isnil": "^4.0.0" } }, "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A=="],
- "@fast-csv/parse": ["@fast-csv/parse@4.3.6", "https://registry.npmmirror.com/@fast-csv/parse/-/parse-4.3.6.tgz", { "dependencies": { "@types/node": "^14.0.1", "lodash.escaperegexp": "^4.1.2", "lodash.groupby": "^4.6.0", "lodash.isfunction": "^3.0.9", "lodash.isnil": "^4.0.0", "lodash.isundefined": "^3.0.1", "lodash.uniq": "^4.5.0" } }, "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA=="],
+ "@fast-csv/parse": ["@fast-csv/parse@4.3.6", "", { "dependencies": { "@types/node": "^14.0.1", "lodash.escaperegexp": "^4.1.2", "lodash.groupby": "^4.6.0", "lodash.isfunction": "^3.0.9", "lodash.isnil": "^4.0.0", "lodash.isundefined": "^3.0.1", "lodash.uniq": "^4.5.0" } }, "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA=="],
- "@floating-ui/core": ["@floating-ui/core@1.7.4", "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.4.tgz", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg=="],
+ "@floating-ui/core": ["@floating-ui/core@1.7.4", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg=="],
- "@floating-ui/dom": ["@floating-ui/dom@1.7.5", "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.5.tgz", { "dependencies": { "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg=="],
+ "@floating-ui/dom": ["@floating-ui/dom@1.7.5", "", { "dependencies": { "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg=="],
- "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="],
+ "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="],
- "@floating-ui/vue": ["@floating-ui/vue@1.1.10", "https://registry.npmmirror.com/@floating-ui/vue/-/vue-1.1.10.tgz", { "dependencies": { "@floating-ui/dom": "^1.7.5", "@floating-ui/utils": "^0.2.10", "vue-demi": ">=0.13.0" } }, "sha512-vdf8f6rHnFPPLRsmL4p12wYl+Ux4mOJOkjzKEMYVnwdf7UFdvBtHlLvQyx8iKG5vhPRbDRgZxdtpmyigDPjzYg=="],
+ "@floating-ui/vue": ["@floating-ui/vue@1.1.10", "", { "dependencies": { "@floating-ui/dom": "^1.7.5", "@floating-ui/utils": "^0.2.10", "vue-demi": ">=0.13.0" } }, "sha512-vdf8f6rHnFPPLRsmL4p12wYl+Ux4mOJOkjzKEMYVnwdf7UFdvBtHlLvQyx8iKG5vhPRbDRgZxdtpmyigDPjzYg=="],
- "@iconify/types": ["@iconify/types@2.0.0", "https://registry.npmmirror.com/@iconify/types/-/types-2.0.0.tgz", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
+ "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
- "@iconify/vue": ["@iconify/vue@5.0.0", "https://registry.npmmirror.com/@iconify/vue/-/vue-5.0.0.tgz", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "vue": ">=3" } }, "sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg=="],
+ "@iconify/vue": ["@iconify/vue@5.0.0", "", { "dependencies": { "@iconify/types": "^2.0.0" }, "peerDependencies": { "vue": ">=3" } }, "sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg=="],
- "@internationalized/date": ["@internationalized/date@3.12.0", "https://registry.npmmirror.com/@internationalized/date/-/date-3.12.0.tgz", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ=="],
+ "@internationalized/date": ["@internationalized/date@3.12.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ=="],
- "@internationalized/number": ["@internationalized/number@3.6.5", "https://registry.npmmirror.com/@internationalized/number/-/number-3.6.5.tgz", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g=="],
+ "@internationalized/number": ["@internationalized/number@3.6.5", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g=="],
- "@intlify/core-base": ["@intlify/core-base@11.3.1", "https://registry.npmmirror.com/@intlify/core-base/-/core-base-11.3.1.tgz", { "dependencies": { "@intlify/devtools-types": "11.3.1", "@intlify/message-compiler": "11.3.1", "@intlify/shared": "11.3.1" } }, "sha512-9nG3ItSD5ApZHmTbv2UFqvJSy3m+u6C/orMohukNKoT/Yuwiz8tPtlNw6ylLuPqSP2kP7ZF4Cdqwp6V1m3BQgw=="],
+ "@intlify/core-base": ["@intlify/core-base@11.4.6", "", { "dependencies": { "@intlify/devtools-types": "11.4.6", "@intlify/message-compiler": "11.4.6", "@intlify/shared": "11.4.6" } }, "sha512-EOeHO95XESK9IFHgHeZXunsM/WBAoCA0DlaWODvx14vKmetAuS97t+l6Xe9hTUqntPpF93vtVSjjUDafw3wXMw=="],
- "@intlify/devtools-types": ["@intlify/devtools-types@11.3.1", "https://registry.npmmirror.com/@intlify/devtools-types/-/devtools-types-11.3.1.tgz", { "dependencies": { "@intlify/core-base": "11.3.1", "@intlify/shared": "11.3.1" } }, "sha512-qrOknIx294W4YYVYBgldDOeOnv2NlpabW+aYGjMuXMSrY36f7GCAPlEBE2G+qTC5x0oAWDBSY5BmvLlPUx1exg=="],
+ "@intlify/devtools-types": ["@intlify/devtools-types@11.4.6", "", { "dependencies": { "@intlify/core-base": "11.4.6", "@intlify/shared": "11.4.6" } }, "sha512-wowQPpNem56b2d43IJmqbrzG2FeBKe5f/kUGlpNuBmXs6OSqncF8m1+1lxHuW8ISZJF0ma2RkW3iLkw0g0G4VA=="],
- "@intlify/message-compiler": ["@intlify/message-compiler@11.3.1", "https://registry.npmmirror.com/@intlify/message-compiler/-/message-compiler-11.3.1.tgz", { "dependencies": { "@intlify/shared": "11.3.1", "source-map-js": "^1.0.2" } }, "sha512-uIa4YurbphU+4Cl5CoL6nq/c7uQhVNRowEelgboNmXNs+UEcyFLQBESwaUjMvdtYxzA2qh+vGim080KZ84ruDA=="],
+ "@intlify/message-compiler": ["@intlify/message-compiler@11.4.6", "", { "dependencies": { "@intlify/shared": "11.4.6", "source-map-js": "^1.0.2" } }, "sha512-5nj3jULqeTAC1WovwMs1LQWgatTa2pM/rXN9T3XW8rdOtXW9ZF6/GLSNFTKDQmPLwclhPdgUWLJ/4w3fMeeC/Q=="],
- "@intlify/shared": ["@intlify/shared@11.3.1", "https://registry.npmmirror.com/@intlify/shared/-/shared-11.3.1.tgz", {}, "sha512-9GWc5PKuRdeWkT7FJN43c/+rD6xpSB3WtizewkfFCK/0XzYqCk4gQBWWcTdfKo8ylEcHwqYsR2Z3HRE3XhEHrQ=="],
+ "@intlify/shared": ["@intlify/shared@11.4.6", "", {}, "sha512-m1p1HHAMLhqSpTRH7VnXdrN0CQ4y+9vunFkpLkbD8soIuBsnQdawZXqMCgvwI2UVF9Ww7sVaw7g9tV2VO7shoA=="],
- "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
+ "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
- "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
+ "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
- "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
- "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
+ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
- "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
- "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
+ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
- "@noble/ciphers": ["@noble/ciphers@2.1.1", "https://registry.npmmirror.com/@noble/ciphers/-/ciphers-2.1.1.tgz", {}, "sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw=="],
+ "@noble/ciphers": ["@noble/ciphers@2.2.0", "", {}, "sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA=="],
- "@noble/hashes": ["@noble/hashes@2.0.1", "https://registry.npmmirror.com/@noble/hashes/-/hashes-2.0.1.tgz", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
+ "@noble/hashes": ["@noble/hashes@2.2.0", "", {}, "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="],
- "@oxc-project/runtime": ["@oxc-project/runtime@0.114.0", "https://registry.npmmirror.com/@oxc-project/runtime/-/runtime-0.114.0.tgz", {}, "sha512-mVGQvr/uFJGQ3hsvgQ1sJfh79t5owyZZZtw+VaH+WhtvsmtgjT6imznB9sz2Q67Q0/4obM9mOOtQscU4aJteSg=="],
+ "@oxc-project/runtime": ["@oxc-project/runtime@0.114.0", "", {}, "sha512-mVGQvr/uFJGQ3hsvgQ1sJfh79t5owyZZZtw+VaH+WhtvsmtgjT6imznB9sz2Q67Q0/4obM9mOOtQscU4aJteSg=="],
- "@oxc-project/types": ["@oxc-project/types@0.114.0", "https://registry.npmmirror.com/@oxc-project/types/-/types-0.114.0.tgz", {}, "sha512-//nBfbzHQHvJs8oFIjv6coZ6uxQ4alLfiPe6D5vit6c4pmxATHHlVwgB1k+Hv4yoAMyncdxgRBF5K4BYWUCzvA=="],
+ "@oxc-project/types": ["@oxc-project/types@0.114.0", "", {}, "sha512-//nBfbzHQHvJs8oFIjv6coZ6uxQ4alLfiPe6D5vit6c4pmxATHHlVwgB1k+Hv4yoAMyncdxgRBF5K4BYWUCzvA=="],
- "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.5.tgz", { "os": "android", "cpu": "arm64" }, "sha512-zCEmUrt1bggwgBgeKLxNj217J1OrChrp3jJt24VK9jAharSTeVaHODNL+LpcQVhRz+FktYWfT9cjo5oZ99ZLpg=="],
+ "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.5", "", { "os": "android", "cpu": "arm64" }, "sha512-zCEmUrt1bggwgBgeKLxNj217J1OrChrp3jJt24VK9jAharSTeVaHODNL+LpcQVhRz+FktYWfT9cjo5oZ99ZLpg=="],
- "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.5.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-ZP9xb9lPAex36pvkNWCjSEJW/Gfdm9I3ssiqOFLmpZ/vosPXgpoGxCmh+dX1Qs+/bWQE6toNFXWWL8vYoKoK9Q=="],
+ "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ZP9xb9lPAex36pvkNWCjSEJW/Gfdm9I3ssiqOFLmpZ/vosPXgpoGxCmh+dX1Qs+/bWQE6toNFXWWL8vYoKoK9Q=="],
- "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.5.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-7IdrPunf6dp9mywMgTOKMMGDnMHQ6+h5gRl6LW8rhD8WK2kXX0IwzcM5Zc0B5J7xQs8QWOlKjv8BJsU/1CD3pg=="],
+ "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-7IdrPunf6dp9mywMgTOKMMGDnMHQ6+h5gRl6LW8rhD8WK2kXX0IwzcM5Zc0B5J7xQs8QWOlKjv8BJsU/1CD3pg=="],
- "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.5.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-o/JCk+dL0IN68EBhZ4DqfsfvxPfMeoM6cJtxORC1YYoxGHZyth2Kb2maXDb4oddw2wu8iIbnYXYPEzBtAF5CAg=="],
+ "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-o/JCk+dL0IN68EBhZ4DqfsfvxPfMeoM6cJtxORC1YYoxGHZyth2Kb2maXDb4oddw2wu8iIbnYXYPEzBtAF5CAg=="],
- "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.5.tgz", { "os": "linux", "cpu": "arm" }, "sha512-IIBwTtA6VwxQLcEgq2mfrUgam7VvPZjhd/jxmeS1npM+edWsrrpRLHUdze+sk4rhb8/xpP3flemgcZXXUW6ukw=="],
+ "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.5", "", { "os": "linux", "cpu": "arm" }, "sha512-IIBwTtA6VwxQLcEgq2mfrUgam7VvPZjhd/jxmeS1npM+edWsrrpRLHUdze+sk4rhb8/xpP3flemgcZXXUW6ukw=="],
- "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.5.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-KSol1De1spMZL+Xg7K5IBWXIvRWv7+pveaxFWXpezezAG7CS6ojzRjtCGCiLxQricutTAi/LkNWKMsd2wNhMKQ=="],
+ "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-KSol1De1spMZL+Xg7K5IBWXIvRWv7+pveaxFWXpezezAG7CS6ojzRjtCGCiLxQricutTAi/LkNWKMsd2wNhMKQ=="],
- "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.5.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-WFljyDkxtXRlWxMjxeegf7xMYXxUr8u7JdXlOEWKYgDqEgxUnSEsVDxBiNWQ1D5kQKwf8Wo4sVKEYPRhCdsjwA=="],
+ "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-WFljyDkxtXRlWxMjxeegf7xMYXxUr8u7JdXlOEWKYgDqEgxUnSEsVDxBiNWQ1D5kQKwf8Wo4sVKEYPRhCdsjwA=="],
- "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.5.tgz", { "os": "linux", "cpu": "x64" }, "sha512-CUlplTujmbDWp2gamvrqVKi2Or8lmngXT1WxsizJfts7JrvfGhZObciaY/+CbdbS9qNnskvwMZNEhTPrn7b+WA=="],
+ "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.5", "", { "os": "linux", "cpu": "x64" }, "sha512-CUlplTujmbDWp2gamvrqVKi2Or8lmngXT1WxsizJfts7JrvfGhZObciaY/+CbdbS9qNnskvwMZNEhTPrn7b+WA=="],
- "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.5.tgz", { "os": "linux", "cpu": "x64" }, "sha512-wdf7g9NbVZCeAo2iGhsjJb7I8ZFfs6X8bumfrWg82VK+8P6AlLXwk48a1ASiJQDTS7Svq2xVzZg3sGO2aXpHRA=="],
+ "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.5", "", { "os": "linux", "cpu": "x64" }, "sha512-wdf7g9NbVZCeAo2iGhsjJb7I8ZFfs6X8bumfrWg82VK+8P6AlLXwk48a1ASiJQDTS7Svq2xVzZg3sGO2aXpHRA=="],
- "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.5.tgz", { "os": "none", "cpu": "arm64" }, "sha512-0CWY7ubu12nhzz+tkpHjoG3IRSTlWYe0wrfJRf4qqjqQSGtAYgoL9kwzdvlhaFdZ5ffVeyYw9qLsChcjUMEloQ=="],
+ "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.5", "", { "os": "none", "cpu": "arm64" }, "sha512-0CWY7ubu12nhzz+tkpHjoG3IRSTlWYe0wrfJRf4qqjqQSGtAYgoL9kwzdvlhaFdZ5ffVeyYw9qLsChcjUMEloQ=="],
- "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.5.tgz", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-LztXnGzv6t2u830mnZrFLRVqT/DPJ9DL4ZTz/y93rqUVkeHjMMYIYaFj+BUthiYxbVH9dH0SZYufETspKY/NhA=="],
+ "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.5", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-LztXnGzv6t2u830mnZrFLRVqT/DPJ9DL4ZTz/y93rqUVkeHjMMYIYaFj+BUthiYxbVH9dH0SZYufETspKY/NhA=="],
- "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.5.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-jUct1XVeGtyjqJXEAfvdFa8xoigYZ2rge7nYEm70ppQxpfH9ze2fbIrpHmP2tNM2vL/F6Dd0CpXhpjPbC6bSxQ=="],
+ "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-jUct1XVeGtyjqJXEAfvdFa8xoigYZ2rge7nYEm70ppQxpfH9ze2fbIrpHmP2tNM2vL/F6Dd0CpXhpjPbC6bSxQ=="],
- "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.5.tgz", { "os": "win32", "cpu": "x64" }, "sha512-VQ8F9ld5gw29epjnVGdrx8ugiLTe8BMqmhDYy7nGbdeDo4HAt4bgdZvLbViEhg7DZyHLpiEUlO5/jPSUrIuxRQ=="],
+ "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.5", "", { "os": "win32", "cpu": "x64" }, "sha512-VQ8F9ld5gw29epjnVGdrx8ugiLTe8BMqmhDYy7nGbdeDo4HAt4bgdZvLbViEhg7DZyHLpiEUlO5/jPSUrIuxRQ=="],
- "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.2", "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", {}, "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw=="],
+ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.2", "", {}, "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw=="],
- "@swc/helpers": ["@swc/helpers@0.5.18", "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.18.tgz", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ=="],
+ "@swc/helpers": ["@swc/helpers@0.5.18", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ=="],
- "@tailwindcss/node": ["@tailwindcss/node@4.2.0", "https://registry.npmmirror.com/@tailwindcss/node/-/node-4.2.0.tgz", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.0" } }, "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q=="],
+ "@tailwindcss/node": ["@tailwindcss/node@4.2.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.31.1", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.0" } }, "sha512-Yv+fn/o2OmL5fh/Ir62VXItdShnUxfpkMA4Y7jdeC8O81WPB8Kf6TT6GSHvnqgSwDzlB5iT7kDpeXxLsUS0T6Q=="],
- "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide/-/oxide-4.2.0.tgz", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.0", "@tailwindcss/oxide-darwin-arm64": "4.2.0", "@tailwindcss/oxide-darwin-x64": "4.2.0", "@tailwindcss/oxide-freebsd-x64": "4.2.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.0", "@tailwindcss/oxide-linux-arm64-musl": "4.2.0", "@tailwindcss/oxide-linux-x64-gnu": "4.2.0", "@tailwindcss/oxide-linux-x64-musl": "4.2.0", "@tailwindcss/oxide-wasm32-wasi": "4.2.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.0", "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" } }, "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ=="],
+ "@tailwindcss/oxide": ["@tailwindcss/oxide@4.2.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.2.0", "@tailwindcss/oxide-darwin-arm64": "4.2.0", "@tailwindcss/oxide-darwin-x64": "4.2.0", "@tailwindcss/oxide-freebsd-x64": "4.2.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.2.0", "@tailwindcss/oxide-linux-arm64-musl": "4.2.0", "@tailwindcss/oxide-linux-x64-gnu": "4.2.0", "@tailwindcss/oxide-linux-x64-musl": "4.2.0", "@tailwindcss/oxide-wasm32-wasi": "4.2.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.2.0", "@tailwindcss/oxide-win32-x64-msvc": "4.2.0" } }, "sha512-AZqQzADaj742oqn2xjl5JbIOzZB/DGCYF/7bpvhA8KvjUj9HJkag6bBuwZvH1ps6dfgxNHyuJVlzSr2VpMgdTQ=="],
- "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.0.tgz", { "os": "android", "cpu": "arm64" }, "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw=="],
+ "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.2.0", "", { "os": "android", "cpu": "arm64" }, "sha512-F0QkHAVaW/JNBWl4CEKWdZ9PMb0khw5DCELAOnu+RtjAfx5Zgw+gqCHFvqg3AirU1IAd181fwOtJQ5I8Yx5wtw=="],
- "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.0.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA=="],
+ "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.2.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-I0QylkXsBsJMZ4nkUNSR04p6+UptjcwhcVo3Zu828ikiEqHjVmQL9RuQ6uT/cVIiKpvtVA25msu/eRV97JeNSA=="],
- "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.0.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg=="],
+ "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.2.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-6TmQIn4p09PBrmnkvbYQ0wbZhLtbaksCDx7Y7R3FYYx0yxNA7xg5KP7dowmQ3d2JVdabIHvs3Hx4K3d5uCf8xg=="],
- "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.0.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw=="],
+ "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.2.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-qBudxDvAa2QwGlq9y7VIzhTvp2mLJ6nD/G8/tI70DCDoneaUeLWBJaPcbfzqRIWraj+o969aDQKvKW9dvkUizw=="],
- "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.0.tgz", { "os": "linux", "cpu": "arm" }, "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg=="],
+ "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.2.0", "", { "os": "linux", "cpu": "arm" }, "sha512-7XKkitpy5NIjFZNUQPeUyNJNJn1CJeV7rmMR+exHfTuOsg8rxIO9eNV5TSEnqRcaOK77zQpsyUkBWmPy8FgdSg=="],
- "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.0.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA=="],
+ "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Mff5a5Q3WoQR01pGU1gr29hHM1N93xYrKkGXfPw/aRtK4bOc331Ho4Tgfsm5WDGvpevqMpdlkCojT3qlCQbCpA=="],
- "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.0.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A=="],
+ "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.2.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-XKcSStleEVnbH6W/9DHzZv1YhjE4eSS6zOu2eRtYAIh7aV4o3vIBs+t/B15xlqoxt6ef/0uiqJVB6hkHjWD/0A=="],
- "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.0.tgz", { "os": "linux", "cpu": "x64" }, "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA=="],
+ "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-/hlXCBqn9K6fi7eAM0RsobHwJYa5V/xzWspVTzxnX+Ft9v6n+30Pz8+RxCn7sQL/vRHHLS30iQPrHQunu6/vJA=="],
- "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.0.tgz", { "os": "linux", "cpu": "x64" }, "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw=="],
+ "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.2.0", "", { "os": "linux", "cpu": "x64" }, "sha512-lKUaygq4G7sWkhQbfdRRBkaq4LY39IriqBQ+Gk6l5nKq6Ay2M2ZZb1tlIyRNgZKS8cbErTwuYSor0IIULC0SHw=="],
- "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.0.tgz", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw=="],
+ "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.2.0", "", { "dependencies": { "@emnapi/core": "^1.8.1", "@emnapi/runtime": "^1.8.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.1", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-xuDjhAsFdUuFP5W9Ze4k/o4AskUtI8bcAGU4puTYprr89QaYFmhYOPfP+d1pH+k9ets6RoE23BXZM1X1jJqoyw=="],
- "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.0.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA=="],
+ "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.2.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-2UU/15y1sWDEDNJXxEIrfWKC2Yb4YgIW5Xz2fKFqGzFWfoMHWFlfa1EJlGO2Xzjkq/tvSarh9ZTjvbxqWvLLXA=="],
- "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.0", "https://registry.npmmirror.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.0.tgz", { "os": "win32", "cpu": "x64" }, "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ=="],
+ "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.2.0", "", { "os": "win32", "cpu": "x64" }, "sha512-CrFadmFoc+z76EV6LPG1jx6XceDsaCG3lFhyLNo/bV9ByPrE+FnBPckXQVP4XRkN76h3Fjt/a+5Er/oA/nCBvQ=="],
- "@tailwindcss/vite": ["@tailwindcss/vite@4.2.0", "https://registry.npmmirror.com/@tailwindcss/vite/-/vite-4.2.0.tgz", { "dependencies": { "@tailwindcss/node": "4.2.0", "@tailwindcss/oxide": "4.2.0", "tailwindcss": "4.2.0" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA=="],
+ "@tailwindcss/vite": ["@tailwindcss/vite@4.2.0", "", { "dependencies": { "@tailwindcss/node": "4.2.0", "@tailwindcss/oxide": "4.2.0", "tailwindcss": "4.2.0" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-da9mFCaHpoOgtQiWtDGIikTrSpUFBtIZCG3jy/u2BGV+l/X1/pbxzmIUxNt6JWm19N3WtGi4KlJdSH/Si83WOA=="],
- "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.18", "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.13.18.tgz", {}, "sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg=="],
+ "@tanstack/virtual-core": ["@tanstack/virtual-core@3.13.18", "", {}, "sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg=="],
- "@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.18", "https://registry.npmmirror.com/@tanstack/vue-virtual/-/vue-virtual-3.13.18.tgz", { "dependencies": { "@tanstack/virtual-core": "3.13.18" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-6pT8HdHtTU5Z+t906cGdCroUNA5wHjFXsNss9gwk7QAr1VNZtz9IQCs2Nhx0gABK48c+OocHl2As+TMg8+Hy4A=="],
+ "@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.18", "", { "dependencies": { "@tanstack/virtual-core": "3.13.18" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-6pT8HdHtTU5Z+t906cGdCroUNA5wHjFXsNss9gwk7QAr1VNZtz9IQCs2Nhx0gABK48c+OocHl2As+TMg8+Hy4A=="],
- "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
+ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
- "@types/bun": ["@types/bun@1.3.9", "https://registry.npmmirror.com/@types/bun/-/bun-1.3.9.tgz", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
+ "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
- "@types/node": ["@types/node@24.10.13", "https://registry.npmmirror.com/@types/node/-/node-24.10.13.tgz", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg=="],
+ "@types/node": ["@types/node@24.10.13", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg=="],
- "@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="],
+ "@types/web-bluetooth": ["@types/web-bluetooth@0.0.21", "", {}, "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA=="],
- "@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.4", "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.4.tgz", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.2" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "vue": "^3.2.25" } }, "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ=="],
+ "@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.4", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.2" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "vue": "^3.2.25" } }, "sha512-uM5iXipgYIn13UUQCZNdWkYk+sysBeA97d5mHsAoAt1u/wpN3+zxOmsVJWosuzX+IMGRzeYUNytztrYznboIkQ=="],
- "@volar/language-core": ["@volar/language-core@2.4.28", "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.28.tgz", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
+ "@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
- "@volar/source-map": ["@volar/source-map@2.4.28", "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.28.tgz", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="],
+ "@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="],
- "@volar/typescript": ["@volar/typescript@2.4.28", "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.28.tgz", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="],
+ "@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="],
- "@vue/compiler-core": ["@vue/compiler-core@3.5.28", "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.28.tgz", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.28", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ=="],
+ "@vue/compiler-core": ["@vue/compiler-core@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.28", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ=="],
- "@vue/compiler-dom": ["@vue/compiler-dom@3.5.28", "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz", { "dependencies": { "@vue/compiler-core": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA=="],
+ "@vue/compiler-dom": ["@vue/compiler-dom@3.5.28", "", { "dependencies": { "@vue/compiler-core": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA=="],
- "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.28", "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.5.28", "@vue/compiler-dom": "3.5.28", "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g=="],
+ "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.28", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/compiler-core": "3.5.28", "@vue/compiler-dom": "3.5.28", "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g=="],
- "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.28", "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g=="],
+ "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.28", "", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g=="],
- "@vue/devtools-api": ["@vue/devtools-api@7.7.9", "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-7.7.9.tgz", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="],
+ "@vue/devtools-api": ["@vue/devtools-api@7.7.9", "", { "dependencies": { "@vue/devtools-kit": "^7.7.9" } }, "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g=="],
- "@vue/devtools-kit": ["@vue/devtools-kit@7.7.9", "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", { "dependencies": { "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA=="],
+ "@vue/devtools-kit": ["@vue/devtools-kit@7.7.9", "", { "dependencies": { "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.2" } }, "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA=="],
- "@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="],
+ "@vue/devtools-shared": ["@vue/devtools-shared@7.7.9", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA=="],
- "@vue/language-core": ["@vue/language-core@3.2.5", "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.2.5.tgz", { "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" } }, "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g=="],
+ "@vue/language-core": ["@vue/language-core@3.2.5", "", { "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" } }, "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g=="],
- "@vue/reactivity": ["@vue/reactivity@3.5.28", "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.28.tgz", { "dependencies": { "@vue/shared": "3.5.28" } }, "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw=="],
+ "@vue/reactivity": ["@vue/reactivity@3.5.28", "", { "dependencies": { "@vue/shared": "3.5.28" } }, "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw=="],
- "@vue/runtime-core": ["@vue/runtime-core@3.5.28", "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.28.tgz", { "dependencies": { "@vue/reactivity": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ=="],
+ "@vue/runtime-core": ["@vue/runtime-core@3.5.28", "", { "dependencies": { "@vue/reactivity": "3.5.28", "@vue/shared": "3.5.28" } }, "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ=="],
- "@vue/runtime-dom": ["@vue/runtime-dom@3.5.28", "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz", { "dependencies": { "@vue/reactivity": "3.5.28", "@vue/runtime-core": "3.5.28", "@vue/shared": "3.5.28", "csstype": "^3.2.3" } }, "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA=="],
+ "@vue/runtime-dom": ["@vue/runtime-dom@3.5.28", "", { "dependencies": { "@vue/reactivity": "3.5.28", "@vue/runtime-core": "3.5.28", "@vue/shared": "3.5.28", "csstype": "^3.2.3" } }, "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA=="],
- "@vue/server-renderer": ["@vue/server-renderer@3.5.28", "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.28.tgz", { "dependencies": { "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "vue": "3.5.28" } }, "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg=="],
+ "@vue/server-renderer": ["@vue/server-renderer@3.5.28", "", { "dependencies": { "@vue/compiler-ssr": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "vue": "3.5.28" } }, "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg=="],
- "@vue/shared": ["@vue/shared@3.5.28", "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.28.tgz", {}, "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ=="],
+ "@vue/shared": ["@vue/shared@3.5.28", "", {}, "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ=="],
- "@vue/tsconfig": ["@vue/tsconfig@0.8.1", "https://registry.npmmirror.com/@vue/tsconfig/-/tsconfig-0.8.1.tgz", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g=="],
+ "@vue/tsconfig": ["@vue/tsconfig@0.8.1", "", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g=="],
- "@vueuse/core": ["@vueuse/core@14.2.1", "https://registry.npmmirror.com/@vueuse/core/-/core-14.2.1.tgz", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.2.1", "@vueuse/shared": "14.2.1" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ=="],
+ "@vueuse/core": ["@vueuse/core@14.2.1", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "14.2.1", "@vueuse/shared": "14.2.1" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ=="],
- "@vueuse/metadata": ["@vueuse/metadata@14.2.1", "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-14.2.1.tgz", {}, "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw=="],
+ "@vueuse/metadata": ["@vueuse/metadata@14.2.1", "", {}, "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw=="],
- "@vueuse/shared": ["@vueuse/shared@14.2.1", "https://registry.npmmirror.com/@vueuse/shared/-/shared-14.2.1.tgz", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw=="],
+ "@vueuse/shared": ["@vueuse/shared@14.2.1", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw=="],
- "ag-charts-community": ["ag-charts-community@13.1.0", "https://registry.npmmirror.com/ag-charts-community/-/ag-charts-community-13.1.0.tgz", { "dependencies": { "ag-charts-core": "13.1.0", "ag-charts-locale": "13.1.0", "ag-charts-types": "13.1.0" } }, "sha512-w+uFTjxlAoTq1+8tgUORtB/zr9jm38ibXzbbWnkBP9Dep9yahi5a1jZL7yExAX35uq3g9QtjTh0Oj/QPDBQ9Ew=="],
+ "@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="],
- "ag-charts-core": ["ag-charts-core@13.1.0", "https://registry.npmmirror.com/ag-charts-core/-/ag-charts-core-13.1.0.tgz", { "dependencies": { "ag-charts-types": "13.1.0" } }, "sha512-mLHJZ8oU5CPeLRURescdISCtMsiiA/m4d1iBr6aQBEgiTVogRMGpFpsYNtQiYtoW2sRh+62I9sN8fhC3JQjX/g=="],
+ "ag-charts-community": ["ag-charts-community@13.1.0", "", { "dependencies": { "ag-charts-core": "13.1.0", "ag-charts-locale": "13.1.0", "ag-charts-types": "13.1.0" } }, "sha512-w+uFTjxlAoTq1+8tgUORtB/zr9jm38ibXzbbWnkBP9Dep9yahi5a1jZL7yExAX35uq3g9QtjTh0Oj/QPDBQ9Ew=="],
- "ag-charts-enterprise": ["ag-charts-enterprise@13.1.0", "https://registry.npmmirror.com/ag-charts-enterprise/-/ag-charts-enterprise-13.1.0.tgz", { "dependencies": { "ag-charts-community": "13.1.0", "ag-charts-core": "13.1.0" } }, "sha512-WyKIqvkOdtdvEJxq76hjTacXTCpIR2lq1JDMYc5MtoHYtiVt1KHApsxS0nbutp/CxGKRgdOqJtxUF+3r33pgPw=="],
+ "ag-charts-core": ["ag-charts-core@13.1.0", "", { "dependencies": { "ag-charts-types": "13.1.0" } }, "sha512-mLHJZ8oU5CPeLRURescdISCtMsiiA/m4d1iBr6aQBEgiTVogRMGpFpsYNtQiYtoW2sRh+62I9sN8fhC3JQjX/g=="],
- "ag-charts-locale": ["ag-charts-locale@13.1.0", "https://registry.npmmirror.com/ag-charts-locale/-/ag-charts-locale-13.1.0.tgz", {}, "sha512-mPgJnVsOI4Cf17CAlRh8BvLz19e165sdQJeUXNaB7M+DPB+pxODOcfx4oqZlR4Wc8Zu++TGb/2ueHa/aeV2qeQ=="],
+ "ag-charts-enterprise": ["ag-charts-enterprise@13.1.0", "", { "dependencies": { "ag-charts-community": "13.1.0", "ag-charts-core": "13.1.0" } }, "sha512-WyKIqvkOdtdvEJxq76hjTacXTCpIR2lq1JDMYc5MtoHYtiVt1KHApsxS0nbutp/CxGKRgdOqJtxUF+3r33pgPw=="],
- "ag-charts-types": ["ag-charts-types@13.1.0", "https://registry.npmmirror.com/ag-charts-types/-/ag-charts-types-13.1.0.tgz", {}, "sha512-DytRM3CXli+Y013SC1Mr8lQBrhVTACK+11ilDHOhwUM0sRpmGuR51XFGcBKOliW1Vas1AycP31Cm3Pp0jx3hqw=="],
+ "ag-charts-locale": ["ag-charts-locale@13.1.0", "", {}, "sha512-mPgJnVsOI4Cf17CAlRh8BvLz19e165sdQJeUXNaB7M+DPB+pxODOcfx4oqZlR4Wc8Zu++TGb/2ueHa/aeV2qeQ=="],
- "ag-grid-community": ["ag-grid-community@35.1.0", "https://registry.npmmirror.com/ag-grid-community/-/ag-grid-community-35.1.0.tgz", { "dependencies": { "ag-charts-types": "13.1.0" } }, "sha512-yWFQfRNjv3KUBkHHzFdDOYGjPcDMU0B8Up4qG651diFlGRUGEGVs94SK73niWvk1FDZdpV9oWrwq3f30/qAoVg=="],
+ "ag-charts-types": ["ag-charts-types@13.1.0", "", {}, "sha512-DytRM3CXli+Y013SC1Mr8lQBrhVTACK+11ilDHOhwUM0sRpmGuR51XFGcBKOliW1Vas1AycP31Cm3Pp0jx3hqw=="],
- "ag-grid-enterprise": ["ag-grid-enterprise@35.1.0", "https://registry.npmmirror.com/ag-grid-enterprise/-/ag-grid-enterprise-35.1.0.tgz", { "dependencies": { "ag-grid-community": "35.1.0" }, "optionalDependencies": { "ag-charts-community": "13.1.0", "ag-charts-enterprise": "13.1.0" } }, "sha512-Zhod3fpgWa9KE0JNFkkkb8/3Qv66UR9KF3wFyCz++wQUtQm5wdExul4UA8wm1ukvBmD6QyBLQ5Cs9zDnIEb0uQ=="],
+ "ag-grid-community": ["ag-grid-community@35.1.0", "", { "dependencies": { "ag-charts-types": "13.1.0" } }, "sha512-yWFQfRNjv3KUBkHHzFdDOYGjPcDMU0B8Up4qG651diFlGRUGEGVs94SK73niWvk1FDZdpV9oWrwq3f30/qAoVg=="],
- "ag-grid-vue3": ["ag-grid-vue3@35.1.0", "https://registry.npmmirror.com/ag-grid-vue3/-/ag-grid-vue3-35.1.0.tgz", { "dependencies": { "ag-grid-community": "35.1.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-BvM7yrFxRB/r5hZ4xSyE6T2lU2Rj+Ls6RH5tTu/n8DmhCTmLj4QCEkoU7EuaE0/Az3uEHOubYMaCX4jcDf181A=="],
+ "ag-grid-enterprise": ["ag-grid-enterprise@35.1.0", "", { "dependencies": { "ag-grid-community": "35.1.0" }, "optionalDependencies": { "ag-charts-community": "13.1.0", "ag-charts-enterprise": "13.1.0" } }, "sha512-Zhod3fpgWa9KE0JNFkkkb8/3Qv66UR9KF3wFyCz++wQUtQm5wdExul4UA8wm1ukvBmD6QyBLQ5Cs9zDnIEb0uQ=="],
- "alien-signals": ["alien-signals@3.1.2", "https://registry.npmmirror.com/alien-signals/-/alien-signals-3.1.2.tgz", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="],
+ "ag-grid-vue3": ["ag-grid-vue3@35.1.0", "", { "dependencies": { "ag-grid-community": "35.1.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-BvM7yrFxRB/r5hZ4xSyE6T2lU2Rj+Ls6RH5tTu/n8DmhCTmLj4QCEkoU7EuaE0/Az3uEHOubYMaCX4jcDf181A=="],
- "archiver": ["archiver@5.3.2", "https://registry.npmmirror.com/archiver/-/archiver-5.3.2.tgz", { "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.1.2", "tar-stream": "^2.2.0", "zip-stream": "^4.1.0" } }, "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw=="],
+ "alien-signals": ["alien-signals@3.1.2", "", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="],
- "archiver-utils": ["archiver-utils@2.1.0", "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-2.1.0.tgz", { "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^2.0.0" } }, "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw=="],
+ "archiver": ["archiver@5.3.2", "", { "dependencies": { "archiver-utils": "^2.1.0", "async": "^3.2.4", "buffer-crc32": "^0.2.1", "readable-stream": "^3.6.0", "readdir-glob": "^1.1.2", "tar-stream": "^2.2.0", "zip-stream": "^4.1.0" } }, "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw=="],
- "aria-hidden": ["aria-hidden@1.2.6", "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
+ "archiver-utils": ["archiver-utils@2.1.0", "", { "dependencies": { "glob": "^7.1.4", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^2.0.0" } }, "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw=="],
- "async": ["async@3.2.6", "https://registry.npmmirror.com/async/-/async-3.2.6.tgz", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
+ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
- "balanced-match": ["balanced-match@1.0.2", "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
+ "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
- "base64-js": ["base64-js@1.5.1", "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
+ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
- "big-integer": ["big-integer@1.6.52", "https://registry.npmmirror.com/big-integer/-/big-integer-1.6.52.tgz", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="],
+ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
- "binary": ["binary@0.3.0", "https://registry.npmmirror.com/binary/-/binary-0.3.0.tgz", { "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" } }, "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg=="],
+ "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="],
- "birpc": ["birpc@2.9.0", "https://registry.npmmirror.com/birpc/-/birpc-2.9.0.tgz", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="],
+ "binary": ["binary@0.3.0", "", { "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" } }, "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg=="],
- "bl": ["bl@4.1.0", "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
+ "birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="],
- "bluebird": ["bluebird@3.4.7", "https://registry.npmmirror.com/bluebird/-/bluebird-3.4.7.tgz", {}, "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="],
+ "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
- "brace-expansion": ["brace-expansion@2.0.2", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
+ "bluebird": ["bluebird@3.4.7", "", {}, "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="],
- "buffer": ["buffer@5.7.1", "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
+ "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
- "buffer-crc32": ["buffer-crc32@0.2.13", "https://registry.npmmirror.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
+ "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="],
- "buffer-indexof-polyfill": ["buffer-indexof-polyfill@1.0.2", "https://registry.npmmirror.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", {}, "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A=="],
+ "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
- "buffers": ["buffers@0.1.1", "https://registry.npmmirror.com/buffers/-/buffers-0.1.1.tgz", {}, "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="],
+ "buffer-indexof-polyfill": ["buffer-indexof-polyfill@1.0.2", "", {}, "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A=="],
- "bun-types": ["bun-types@1.3.9", "https://registry.npmmirror.com/bun-types/-/bun-types-1.3.9.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
+ "buffers": ["buffers@0.1.1", "", {}, "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="],
- "chainsaw": ["chainsaw@0.1.0", "https://registry.npmmirror.com/chainsaw/-/chainsaw-0.1.0.tgz", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="],
+ "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
- "class-variance-authority": ["class-variance-authority@0.7.1", "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
+ "chainsaw": ["chainsaw@0.1.0", "", { "dependencies": { "traverse": ">=0.3.0 <0.4" } }, "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ=="],
- "clsx": ["clsx@2.1.1", "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
+ "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
- "compress-commons": ["compress-commons@4.1.2", "https://registry.npmmirror.com/compress-commons/-/compress-commons-4.1.2.tgz", { "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg=="],
+ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
- "concat-map": ["concat-map@0.0.1", "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
+ "compress-commons": ["compress-commons@4.1.2", "", { "dependencies": { "buffer-crc32": "^0.2.13", "crc32-stream": "^4.0.2", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg=="],
- "copy-anything": ["copy-anything@4.0.5", "https://registry.npmmirror.com/copy-anything/-/copy-anything-4.0.5.tgz", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
+ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
- "core-util-is": ["core-util-is@1.0.3", "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
+ "copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
- "crc-32": ["crc-32@1.2.2", "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="],
+ "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
- "crc32-stream": ["crc32-stream@4.0.3", "https://registry.npmmirror.com/crc32-stream/-/crc32-stream-4.0.3.tgz", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" } }, "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw=="],
+ "crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="],
- "csstype": ["csstype@3.2.3", "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
+ "crc32-stream": ["crc32-stream@4.0.3", "", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" } }, "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw=="],
- "dayjs": ["dayjs@1.11.19", "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="],
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
- "decimal.js": ["decimal.js@10.6.0", "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.6.0.tgz", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
+ "dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="],
- "defu": ["defu@6.1.4", "https://registry.npmmirror.com/defu/-/defu-6.1.4.tgz", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
+ "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
- "detect-libc": ["detect-libc@2.1.2", "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
- "duplexer2": ["duplexer2@0.1.4", "https://registry.npmmirror.com/duplexer2/-/duplexer2-0.1.4.tgz", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="],
+ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
- "end-of-stream": ["end-of-stream@1.4.5", "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
+ "docxtemplater": ["docxtemplater@3.69.0", "", { "dependencies": { "@xmldom/xmldom": "^0.9.10" } }, "sha512-l1zDGXj4CHdBCkGPvmVOsEzc4DDpMxLXgnNd1zllEck9gxCGkkV5vv1tOD5JhudaM73nTIgymy4wil2u9O/uhQ=="],
- "enhanced-resolve": ["enhanced-resolve@5.19.0", "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="],
+ "duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="],
- "entities": ["entities@7.0.1", "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
+ "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
- "estree-walker": ["estree-walker@2.0.2", "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
+ "enhanced-resolve": ["enhanced-resolve@5.19.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.0" } }, "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg=="],
- "exceljs": ["exceljs@4.4.0", "https://registry.npmmirror.com/exceljs/-/exceljs-4.4.0.tgz", { "dependencies": { "archiver": "^5.0.0", "dayjs": "^1.8.34", "fast-csv": "^4.3.1", "jszip": "^3.10.1", "readable-stream": "^3.6.0", "saxes": "^5.0.1", "tmp": "^0.2.0", "unzipper": "^0.10.11", "uuid": "^8.3.0" } }, "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg=="],
+ "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
- "fast-csv": ["fast-csv@4.3.6", "https://registry.npmmirror.com/fast-csv/-/fast-csv-4.3.6.tgz", { "dependencies": { "@fast-csv/format": "4.3.5", "@fast-csv/parse": "4.3.6" } }, "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw=="],
+ "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
- "fdir": ["fdir@6.5.0", "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
+ "exceljs": ["exceljs@4.4.0", "", { "dependencies": { "archiver": "^5.0.0", "dayjs": "^1.8.34", "fast-csv": "^4.3.1", "jszip": "^3.10.1", "readable-stream": "^3.6.0", "saxes": "^5.0.1", "tmp": "^0.2.0", "unzipper": "^0.10.11", "uuid": "^8.3.0" } }, "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg=="],
- "framer-motion": ["framer-motion@12.34.3", "https://registry.npmmirror.com/framer-motion/-/framer-motion-12.34.3.tgz", { "dependencies": { "motion-dom": "^12.34.3", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-v81ecyZKYO/DfpTwHivqkxSUBzvceOpoI+wLfgCgoUIKxlFKEXdg0oR9imxwXumT4SFy8vRk9xzJ5l3/Du/55Q=="],
+ "fast-csv": ["fast-csv@4.3.6", "", { "dependencies": { "@fast-csv/format": "4.3.5", "@fast-csv/parse": "4.3.6" } }, "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw=="],
- "fs-constants": ["fs-constants@1.0.0", "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
+ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
- "fs.realpath": ["fs.realpath@1.0.0", "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
+ "file-saver": ["file-saver@2.0.5", "", {}, "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="],
- "fsevents": ["fsevents@2.3.3", "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
+ "framer-motion": ["framer-motion@12.34.3", "", { "dependencies": { "motion-dom": "^12.34.3", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-v81ecyZKYO/DfpTwHivqkxSUBzvceOpoI+wLfgCgoUIKxlFKEXdg0oR9imxwXumT4SFy8vRk9xzJ5l3/Du/55Q=="],
- "fstream": ["fstream@1.0.12", "https://registry.npmmirror.com/fstream/-/fstream-1.0.12.tgz", { "dependencies": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", "mkdirp": ">=0.5 0", "rimraf": "2" } }, "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg=="],
+ "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
- "glob": ["glob@7.2.3", "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
+ "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
- "graceful-fs": ["graceful-fs@4.2.11", "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
+ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
- "hey-listen": ["hey-listen@1.0.8", "https://registry.npmmirror.com/hey-listen/-/hey-listen-1.0.8.tgz", {}, "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="],
+ "fstream": ["fstream@1.0.12", "", { "dependencies": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", "mkdirp": ">=0.5 0", "rimraf": "2" } }, "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg=="],
- "hookable": ["hookable@5.5.3", "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
+ "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
- "ieee754": ["ieee754@1.2.1", "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
- "immediate": ["immediate@3.0.6", "https://registry.npmmirror.com/immediate/-/immediate-3.0.6.tgz", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
+ "hey-listen": ["hey-listen@1.0.8", "", {}, "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="],
- "inflight": ["inflight@1.0.6", "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
+ "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
- "inherits": ["inherits@2.0.4", "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
+ "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
- "is-what": ["is-what@5.5.0", "https://registry.npmmirror.com/is-what/-/is-what-5.5.0.tgz", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="],
+ "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
- "isarray": ["isarray@1.0.0", "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
+ "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
- "jiti": ["jiti@2.6.1", "https://registry.npmmirror.com/jiti/-/jiti-2.6.1.tgz", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
+ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
- "jszip": ["jszip@3.10.1", "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],
+ "is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="],
- "lazystream": ["lazystream@1.0.1", "https://registry.npmmirror.com/lazystream/-/lazystream-1.0.1.tgz", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="],
+ "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
- "lie": ["lie@3.1.1", "https://registry.npmmirror.com/lie/-/lie-3.1.1.tgz", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw=="],
+ "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
- "lightningcss": ["lightningcss@1.31.1", "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.31.1.tgz", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
+ "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="],
- "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
+ "lazystream": ["lazystream@1.0.1", "", { "dependencies": { "readable-stream": "^2.0.5" } }, "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw=="],
- "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
+ "lie": ["lie@3.1.1", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw=="],
- "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
+ "lightningcss": ["lightningcss@1.31.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.31.1", "lightningcss-darwin-arm64": "1.31.1", "lightningcss-darwin-x64": "1.31.1", "lightningcss-freebsd-x64": "1.31.1", "lightningcss-linux-arm-gnueabihf": "1.31.1", "lightningcss-linux-arm64-gnu": "1.31.1", "lightningcss-linux-arm64-musl": "1.31.1", "lightningcss-linux-x64-gnu": "1.31.1", "lightningcss-linux-x64-musl": "1.31.1", "lightningcss-win32-arm64-msvc": "1.31.1", "lightningcss-win32-x64-msvc": "1.31.1" } }, "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ=="],
- "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
+ "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
- "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
+ "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.31.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg=="],
- "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
+ "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.31.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA=="],
- "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
+ "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.31.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A=="],
- "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
+ "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.31.1", "", { "os": "linux", "cpu": "arm" }, "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g=="],
- "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
+ "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg=="],
- "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
+ "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.31.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg=="],
- "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
+ "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA=="],
- "listenercount": ["listenercount@1.0.1", "https://registry.npmmirror.com/listenercount/-/listenercount-1.0.1.tgz", {}, "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ=="],
+ "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.31.1", "", { "os": "linux", "cpu": "x64" }, "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA=="],
- "localforage": ["localforage@1.10.0", "https://registry.npmmirror.com/localforage/-/localforage-1.10.0.tgz", { "dependencies": { "lie": "3.1.1" } }, "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg=="],
+ "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.31.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w=="],
- "lodash.defaults": ["lodash.defaults@4.2.0", "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="],
+ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
- "lodash.difference": ["lodash.difference@4.5.0", "https://registry.npmmirror.com/lodash.difference/-/lodash.difference-4.5.0.tgz", {}, "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA=="],
+ "listenercount": ["listenercount@1.0.1", "", {}, "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ=="],
- "lodash.escaperegexp": ["lodash.escaperegexp@4.1.2", "https://registry.npmmirror.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", {}, "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="],
+ "localforage": ["localforage@1.10.0", "", { "dependencies": { "lie": "3.1.1" } }, "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg=="],
- "lodash.flatten": ["lodash.flatten@4.4.0", "https://registry.npmmirror.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz", {}, "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="],
+ "lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="],
- "lodash.groupby": ["lodash.groupby@4.6.0", "https://registry.npmmirror.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz", {}, "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="],
+ "lodash.difference": ["lodash.difference@4.5.0", "", {}, "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA=="],
- "lodash.isboolean": ["lodash.isboolean@3.0.3", "https://registry.npmmirror.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
+ "lodash.escaperegexp": ["lodash.escaperegexp@4.1.2", "", {}, "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw=="],
- "lodash.isequal": ["lodash.isequal@4.5.0", "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="],
+ "lodash.flatten": ["lodash.flatten@4.4.0", "", {}, "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="],
- "lodash.isfunction": ["lodash.isfunction@3.0.9", "https://registry.npmmirror.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", {}, "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="],
+ "lodash.groupby": ["lodash.groupby@4.6.0", "", {}, "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw=="],
- "lodash.isnil": ["lodash.isnil@4.0.0", "https://registry.npmmirror.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz", {}, "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="],
+ "lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
- "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
+ "lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="],
- "lodash.isundefined": ["lodash.isundefined@3.0.1", "https://registry.npmmirror.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", {}, "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA=="],
+ "lodash.isfunction": ["lodash.isfunction@3.0.9", "", {}, "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="],
- "lodash.union": ["lodash.union@4.6.0", "https://registry.npmmirror.com/lodash.union/-/lodash.union-4.6.0.tgz", {}, "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw=="],
+ "lodash.isnil": ["lodash.isnil@4.0.0", "", {}, "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng=="],
- "lodash.uniq": ["lodash.uniq@4.5.0", "https://registry.npmmirror.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz", {}, "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="],
+ "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
- "lucide-vue-next": ["lucide-vue-next@0.563.0", "https://registry.npmmirror.com/lucide-vue-next/-/lucide-vue-next-0.563.0.tgz", { "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA=="],
+ "lodash.isundefined": ["lodash.isundefined@3.0.1", "", {}, "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA=="],
- "magic-string": ["magic-string@0.30.21", "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
+ "lodash.union": ["lodash.union@4.6.0", "", {}, "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw=="],
- "minimatch": ["minimatch@5.1.9", "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.9.tgz", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="],
+ "lodash.uniq": ["lodash.uniq@4.5.0", "", {}, "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="],
- "mitt": ["mitt@3.0.1", "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
+ "lucide-vue-next": ["lucide-vue-next@0.563.0", "", { "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA=="],
- "mkdirp": ["mkdirp@3.0.1", "https://registry.npmmirror.com/mkdirp/-/mkdirp-3.0.1.tgz", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
+ "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
- "motion-dom": ["motion-dom@12.34.3", "https://registry.npmmirror.com/motion-dom/-/motion-dom-12.34.3.tgz", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ=="],
+ "minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="],
- "motion-utils": ["motion-utils@12.29.2", "https://registry.npmmirror.com/motion-utils/-/motion-utils-12.29.2.tgz", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="],
+ "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
- "motion-v": ["motion-v@2.0.0", "https://registry.npmmirror.com/motion-v/-/motion-v-2.0.0.tgz", { "dependencies": { "framer-motion": "^12.29.2", "hey-listen": "^1.0.8", "motion-dom": "^12.29.2", "motion-utils": "^12.29.2" }, "peerDependencies": { "@vueuse/core": ">=10.0.0", "vue": ">=3.0.0" } }, "sha512-oQuQMrPhti+Zps6OosOaW3b/eqzaGAuwI54XHJKq/dIWtQWcNzfyhTo4VB5xmp7yLN+3BE9FKF6skLsynfgbHQ=="],
+ "mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
- "muggle-string": ["muggle-string@0.4.1", "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
+ "motion-dom": ["motion-dom@12.34.3", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-sYgFe+pR9aIM7o4fhs2aXtOI+oqlUd33N9Yoxcgo1Fv7M20sRkHtCmzE/VRNIcq7uNJ+qio+Xubt1FXH3pQ+eQ=="],
- "nanoid": ["nanoid@3.3.11", "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
+ "motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="],
- "normalize-path": ["normalize-path@3.0.0", "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
+ "motion-v": ["motion-v@2.0.0", "", { "dependencies": { "framer-motion": "^12.29.2", "hey-listen": "^1.0.8", "motion-dom": "^12.29.2", "motion-utils": "^12.29.2" }, "peerDependencies": { "@vueuse/core": ">=10.0.0", "vue": ">=3.0.0" } }, "sha512-oQuQMrPhti+Zps6OosOaW3b/eqzaGAuwI54XHJKq/dIWtQWcNzfyhTo4VB5xmp7yLN+3BE9FKF6skLsynfgbHQ=="],
- "ohash": ["ohash@2.0.11", "https://registry.npmmirror.com/ohash/-/ohash-2.0.11.tgz", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
+ "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
- "once": ["once@1.4.0", "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
+ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
- "pako": ["pako@1.0.11", "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
+ "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
- "path-browserify": ["path-browserify@1.0.1", "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
+ "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
- "path-is-absolute": ["path-is-absolute@1.0.1", "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
+ "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
- "perfect-debounce": ["perfect-debounce@1.0.0", "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
+ "pako": ["pako@2.2.0", "", {}, "sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w=="],
- "picocolors": ["picocolors@1.1.1", "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
+ "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
- "picomatch": ["picomatch@4.0.3", "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
+ "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
- "pinia": ["pinia@3.0.4", "https://registry.npmmirror.com/pinia/-/pinia-3.0.4.tgz", { "dependencies": { "@vue/devtools-api": "^7.7.7" }, "peerDependencies": { "typescript": ">=4.5.0", "vue": "^3.5.11" }, "optionalPeers": ["typescript"] }, "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw=="],
+ "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="],
- "pinia-plugin-persistedstate": ["pinia-plugin-persistedstate@4.7.1", "https://registry.npmmirror.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-4.7.1.tgz", { "dependencies": { "defu": "^6.1.4" }, "peerDependencies": { "@nuxt/kit": ">=3.0.0", "@pinia/nuxt": ">=0.10.0", "pinia": ">=3.0.0" }, "optionalPeers": ["@nuxt/kit", "@pinia/nuxt", "pinia"] }, "sha512-WHOqh2esDlR3eAaknPbqXrkkj0D24h8shrDPqysgCFR6ghqP/fpFfJmMPJp0gETHsvrh9YNNg6dQfo2OEtDnIQ=="],
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
- "postcss": ["postcss@8.5.6", "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
+ "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
- "process-nextick-args": ["process-nextick-args@2.0.1", "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
+ "pinia": ["pinia@3.0.4", "", { "dependencies": { "@vue/devtools-api": "^7.7.7" }, "peerDependencies": { "typescript": ">=4.5.0", "vue": "^3.5.11" }, "optionalPeers": ["typescript"] }, "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw=="],
- "readable-stream": ["readable-stream@3.6.2", "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
+ "pinia-plugin-persistedstate": ["pinia-plugin-persistedstate@4.7.1", "", { "dependencies": { "defu": "^6.1.4" }, "peerDependencies": { "@nuxt/kit": ">=3.0.0", "@pinia/nuxt": ">=0.10.0", "pinia": ">=3.0.0" }, "optionalPeers": ["@nuxt/kit", "@pinia/nuxt", "pinia"] }, "sha512-WHOqh2esDlR3eAaknPbqXrkkj0D24h8shrDPqysgCFR6ghqP/fpFfJmMPJp0gETHsvrh9YNNg6dQfo2OEtDnIQ=="],
- "readdir-glob": ["readdir-glob@1.1.3", "https://registry.npmmirror.com/readdir-glob/-/readdir-glob-1.1.3.tgz", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="],
+ "pizzip": ["pizzip@3.2.0", "", { "dependencies": { "pako": "^2.1.0" } }, "sha512-X4NPNICxCfIK8VYhF6wbksn81vTiziyLbvKuORVAmolvnUzl1A1xmz9DAWKxPRq9lZg84pJOOAMq3OE61bD8IQ=="],
- "reka-ui": ["reka-ui@2.8.2", "https://registry.npmmirror.com/reka-ui/-/reka-ui-2.8.2.tgz", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.2.0" } }, "sha512-8lTKcJhmG+D3UyJxhBnNnW/720sLzm0pbA9AC1MWazmJ5YchJAyTSl+O00xP/kxBmEN0fw5JqWVHguiFmsGjzA=="],
+ "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
- "rfdc": ["rfdc@1.4.1", "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
+ "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
- "rimraf": ["rimraf@2.7.1", "https://registry.npmmirror.com/rimraf/-/rimraf-2.7.1.tgz", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="],
+ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
- "rolldown": ["rolldown@1.0.0-rc.5", "https://registry.npmmirror.com/rolldown/-/rolldown-1.0.0-rc.5.tgz", { "dependencies": { "@oxc-project/types": "=0.114.0", "@rolldown/pluginutils": "1.0.0-rc.5" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.5", "@rolldown/binding-darwin-arm64": "1.0.0-rc.5", "@rolldown/binding-darwin-x64": "1.0.0-rc.5", "@rolldown/binding-freebsd-x64": "1.0.0-rc.5", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.5", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.5", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.5", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.5", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.5", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.5", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.5", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.5", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.5" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-0AdalTs6hNTioaCYIkAa7+xsmHBfU5hCNclZnM/lp7lGGDuUOb6N4BVNtwiomybbencDjq/waKjTImqiGCs5sw=="],
+ "readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="],
- "safe-buffer": ["safe-buffer@5.1.2", "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
+ "reka-ui": ["reka-ui@2.8.2", "", { "dependencies": { "@floating-ui/dom": "^1.6.13", "@floating-ui/vue": "^1.1.6", "@internationalized/date": "^3.5.0", "@internationalized/number": "^3.5.0", "@tanstack/vue-virtual": "^3.12.0", "@vueuse/core": "^14.1.0", "@vueuse/shared": "^14.1.0", "aria-hidden": "^1.2.4", "defu": "^6.1.4", "ohash": "^2.0.11" }, "peerDependencies": { "vue": ">= 3.2.0" } }, "sha512-8lTKcJhmG+D3UyJxhBnNnW/720sLzm0pbA9AC1MWazmJ5YchJAyTSl+O00xP/kxBmEN0fw5JqWVHguiFmsGjzA=="],
- "saxes": ["saxes@5.0.1", "https://registry.npmmirror.com/saxes/-/saxes-5.0.1.tgz", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw=="],
+ "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
- "setimmediate": ["setimmediate@1.0.5", "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="],
+ "rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="],
- "sortablejs": ["sortablejs@1.14.0", "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.14.0.tgz", {}, "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="],
+ "rolldown": ["rolldown@1.0.0-rc.5", "", { "dependencies": { "@oxc-project/types": "=0.114.0", "@rolldown/pluginutils": "1.0.0-rc.5" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.5", "@rolldown/binding-darwin-arm64": "1.0.0-rc.5", "@rolldown/binding-darwin-x64": "1.0.0-rc.5", "@rolldown/binding-freebsd-x64": "1.0.0-rc.5", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.5", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.5", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.5", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.5", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.5", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.5", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.5", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.5", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.5" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-0AdalTs6hNTioaCYIkAa7+xsmHBfU5hCNclZnM/lp7lGGDuUOb6N4BVNtwiomybbencDjq/waKjTImqiGCs5sw=="],
- "source-map-js": ["source-map-js@1.2.1", "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
+ "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
- "speakingurl": ["speakingurl@14.0.1", "https://registry.npmmirror.com/speakingurl/-/speakingurl-14.0.1.tgz", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="],
+ "saxes": ["saxes@5.0.1", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw=="],
- "string_decoder": ["string_decoder@1.3.0", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
+ "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="],
- "superjson": ["superjson@2.2.6", "https://registry.npmmirror.com/superjson/-/superjson-2.2.6.tgz", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="],
+ "sortablejs": ["sortablejs@1.14.0", "", {}, "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="],
- "tailwind-merge": ["tailwind-merge@3.5.0", "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.5.0.tgz", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
+ "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
- "tailwindcss": ["tailwindcss@4.2.0", "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.2.0.tgz", {}, "sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q=="],
+ "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="],
- "tapable": ["tapable@2.3.0", "https://registry.npmmirror.com/tapable/-/tapable-2.3.0.tgz", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
+ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
- "tar-stream": ["tar-stream@2.2.0", "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
+ "superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="],
- "tinyglobby": ["tinyglobby@0.2.15", "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+ "tailwind-merge": ["tailwind-merge@3.5.0", "", {}, "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A=="],
- "tmp": ["tmp@0.2.5", "https://registry.npmmirror.com/tmp/-/tmp-0.2.5.tgz", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="],
+ "tailwindcss": ["tailwindcss@4.2.0", "", {}, "sha512-yYzTZ4++b7fNYxFfpnberEEKu43w44aqDMNM9MHMmcKuCH7lL8jJ4yJ7LGHv7rSwiqM0nkiobF9I6cLlpS2P7Q=="],
- "traverse": ["traverse@0.3.9", "https://registry.npmmirror.com/traverse/-/traverse-0.3.9.tgz", {}, "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ=="],
+ "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
- "tslib": ["tslib@2.8.1", "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+ "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
- "tw-animate-css": ["tw-animate-css@1.4.0", "https://registry.npmmirror.com/tw-animate-css/-/tw-animate-css-1.4.0.tgz", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
+ "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
- "typescript": ["typescript@5.9.3", "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
+ "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="],
- "undici-types": ["undici-types@7.16.0", "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
+ "traverse": ["traverse@0.3.9", "", {}, "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ=="],
- "unzipper": ["unzipper@0.10.14", "https://registry.npmmirror.com/unzipper/-/unzipper-0.10.14.tgz", { "dependencies": { "big-integer": "^1.6.17", "binary": "~0.3.0", "bluebird": "~3.4.1", "buffer-indexof-polyfill": "~1.0.0", "duplexer2": "~0.1.4", "fstream": "^1.0.12", "graceful-fs": "^4.2.2", "listenercount": "~1.0.1", "readable-stream": "~2.3.6", "setimmediate": "~1.0.4" } }, "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g=="],
+ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
- "util-deprecate": ["util-deprecate@1.0.2", "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
+ "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
- "uuid": ["uuid@8.3.2", "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
+ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
- "vite": ["vite@8.0.0-beta.15", "https://registry.npmmirror.com/vite/-/vite-8.0.0-beta.15.tgz", { "dependencies": { "@oxc-project/runtime": "0.114.0", "lightningcss": "^1.31.1", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rolldown": "1.0.0-rc.5", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.0.0-alpha.31", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-RHX7IvsJlEfjyA1rS7MY0UsmF91etdLAamslHR5lfuO3W/BXRdXm2tRE64ztpSPZbKqB4wAAZ0AwtF6QzfKZLA=="],
+ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
- "vscode-uri": ["vscode-uri@3.1.0", "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
+ "unzipper": ["unzipper@0.10.14", "", { "dependencies": { "big-integer": "^1.6.17", "binary": "~0.3.0", "bluebird": "~3.4.1", "buffer-indexof-polyfill": "~1.0.0", "duplexer2": "~0.1.4", "fstream": "^1.0.12", "graceful-fs": "^4.2.2", "listenercount": "~1.0.1", "readable-stream": "~2.3.6", "setimmediate": "~1.0.4" } }, "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g=="],
- "vue": ["vue@3.5.28", "https://registry.npmmirror.com/vue/-/vue-3.5.28.tgz", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/compiler-sfc": "3.5.28", "@vue/runtime-dom": "3.5.28", "@vue/server-renderer": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg=="],
+ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
- "vue-demi": ["vue-demi@0.14.10", "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
+ "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
- "vue-i18n": ["vue-i18n@11.3.1", "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-11.3.1.tgz", { "dependencies": { "@intlify/core-base": "11.3.1", "@intlify/devtools-types": "11.3.1", "@intlify/shared": "11.3.1", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-azq8fhVnCwJAw0iXW7i44h9P+Bj+snNuevBAaJ9bxn0I3YVsRU3deVFPNnTfZ2uxVJefGp83JUmL68ddCPw5Pw=="],
+ "vite": ["vite@8.0.0-beta.15", "", { "dependencies": { "@oxc-project/runtime": "0.114.0", "lightningcss": "^1.31.1", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rolldown": "1.0.0-rc.5", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.0.0-alpha.31", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-RHX7IvsJlEfjyA1rS7MY0UsmF91etdLAamslHR5lfuO3W/BXRdXm2tRE64ztpSPZbKqB4wAAZ0AwtF6QzfKZLA=="],
- "vue-router": ["vue-router@4.6.4", "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg=="],
+ "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
- "vue-tsc": ["vue-tsc@3.2.5", "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.2.5.tgz", { "dependencies": { "@volar/typescript": "2.4.28", "@vue/language-core": "3.2.5" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "bin/vue-tsc.js" } }, "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA=="],
+ "vue": ["vue@3.5.28", "", { "dependencies": { "@vue/compiler-dom": "3.5.28", "@vue/compiler-sfc": "3.5.28", "@vue/runtime-dom": "3.5.28", "@vue/server-renderer": "3.5.28", "@vue/shared": "3.5.28" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg=="],
- "vuedraggable": ["vuedraggable@4.1.0", "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz", { "dependencies": { "sortablejs": "1.14.0" }, "peerDependencies": { "vue": "^3.0.1" } }, "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww=="],
+ "vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
- "wrappy": ["wrappy@1.0.2", "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
+ "vue-i18n": ["vue-i18n@11.4.6", "", { "dependencies": { "@intlify/core-base": "11.4.6", "@intlify/devtools-types": "11.4.6", "@intlify/shared": "11.4.6", "@vue/devtools-api": "^6.5.0" }, "peerDependencies": { "vue": "^3.0.0" } }, "sha512-l0gE7Rfy0phCa5ChKYkOq543Wgd39BCK6hkktfr1Ed4D99oRkgPK9ffShASZdeC8OJxGfdWmpYoAaAH6iLEuIg=="],
- "xmlchars": ["xmlchars@2.2.0", "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="],
+ "vue-tsc": ["vue-tsc@3.2.5", "", { "dependencies": { "@volar/typescript": "2.4.28", "@vue/language-core": "3.2.5" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "bin/vue-tsc.js" } }, "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA=="],
- "zip-stream": ["zip-stream@4.1.1", "https://registry.npmmirror.com/zip-stream/-/zip-stream-4.1.1.tgz", { "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", "readable-stream": "^3.6.0" } }, "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ=="],
+ "vuedraggable": ["vuedraggable@4.1.0", "", { "dependencies": { "sortablejs": "1.14.0" }, "peerDependencies": { "vue": "^3.0.1" } }, "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww=="],
- "@fast-csv/format/@types/node": ["@types/node@14.18.63", "https://registry.npmmirror.com/@types/node/-/node-14.18.63.tgz", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="],
+ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
- "@fast-csv/parse/@types/node": ["@types/node@14.18.63", "https://registry.npmmirror.com/@types/node/-/node-14.18.63.tgz", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="],
+ "xmlchars": ["xmlchars@2.2.0", "", {}, "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="],
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "https://registry.npmmirror.com/@emnapi/core/-/core-1.8.1.tgz", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
+ "zip-stream": ["zip-stream@4.1.1", "", { "dependencies": { "archiver-utils": "^3.0.4", "compress-commons": "^4.1.2", "readable-stream": "^3.6.0" } }, "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ=="],
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.8.1.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
+ "@fast-csv/format/@types/node": ["@types/node@14.18.63", "", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="],
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "https://registry.npmmirror.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
+ "@fast-csv/parse/@types/node": ["@types/node@14.18.63", "", {}, "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ=="],
- "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "https://registry.npmmirror.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
- "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
- "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
- "archiver-utils/readable-stream": ["readable-stream@2.3.8", "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
- "duplexer2/readable-stream": ["readable-stream@2.3.8", "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+ "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
- "glob/minimatch": ["minimatch@3.1.5", "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
+ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
- "jszip/lie": ["lie@3.3.0", "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
+ "archiver-utils/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
- "jszip/readable-stream": ["readable-stream@2.3.8", "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+ "duplexer2/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
- "lazystream/readable-stream": ["readable-stream@2.3.8", "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+ "glob/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
- "reka-ui/@internationalized/date": ["@internationalized/date@3.11.0", "https://registry.npmmirror.com/@internationalized/date/-/date-3.11.0.tgz", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q=="],
+ "jszip/lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="],
- "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.5", "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.5.tgz", {}, "sha512-RxlLX/DPoarZ9PtxVrQgZhPoor987YtKQqCo5zkjX+0S0yLJ7Vv515Wk6+xtTL67VONKJKxETWZwuZjss2idYw=="],
+ "jszip/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
- "string_decoder/safe-buffer": ["safe-buffer@5.2.1", "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
+ "jszip/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
- "unzipper/readable-stream": ["readable-stream@2.3.8", "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
+ "lazystream/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
- "vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
+ "reka-ui/@internationalized/date": ["@internationalized/date@3.11.0", "", { "dependencies": { "@swc/helpers": "^0.5.0" } }, "sha512-BOx5huLAWhicM9/ZFs84CzP+V3gBW6vlpM02yzsdYC7TGlZJX1OJiEEHcSayF00Z+3jLlm4w79amvSt6RqKN3Q=="],
- "vue-router/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
+ "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.5", "", {}, "sha512-RxlLX/DPoarZ9PtxVrQgZhPoor987YtKQqCo5zkjX+0S0yLJ7Vv515Wk6+xtTL67VONKJKxETWZwuZjss2idYw=="],
- "zip-stream/archiver-utils": ["archiver-utils@3.0.4", "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-3.0.4.tgz", { "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw=="],
+ "string_decoder/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
- "archiver-utils/readable-stream/string_decoder": ["string_decoder@1.1.1", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+ "unzipper/readable-stream": ["readable-stream@2.3.8", "", { "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" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
- "duplexer2/readable-stream/string_decoder": ["string_decoder@1.1.1", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+ "vue-i18n/@vue/devtools-api": ["@vue/devtools-api@6.6.4", "", {}, "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g=="],
- "glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+ "zip-stream/archiver-utils": ["archiver-utils@3.0.4", "", { "dependencies": { "glob": "^7.2.3", "graceful-fs": "^4.2.0", "lazystream": "^1.0.0", "lodash.defaults": "^4.2.0", "lodash.difference": "^4.5.0", "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", "normalize-path": "^3.0.0", "readable-stream": "^3.6.0" } }, "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw=="],
- "jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+ "archiver-utils/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
- "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+ "duplexer2/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
- "unzipper/readable-stream/string_decoder": ["string_decoder@1.1.1", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+ "glob/minimatch/brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
+
+ "jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+
+ "lazystream/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
+
+ "unzipper/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
}
}
diff --git a/data.js b/data.js
deleted file mode 100644
index 8be6eff..0000000
--- a/data.js
+++ /dev/null
@@ -1,117 +0,0 @@
-const DEFAULT_FILE_NAME = 'data'
-const DEFAULT_MIME_TYPE = 'application/octet-stream'
-
-const encoder = new TextEncoder()
-const decoder = new TextDecoder()
-
-const normalizeSuffix = (suffix) => {
- const value = String(suffix || '').trim()
- if (!value) throw new Error('INVALID_SUFFIX')
- return value.startsWith('.') ? value : `.${value}`
-}
-
-const sanitizeFileNamePart = (value) => {
- const cleaned = String(value || '')
- .replace(/[\\/:*?"<>|]/g, '_')
- .replace(/\s+/g, ' ')
- .trim()
-
- return cleaned || DEFAULT_FILE_NAME
-}
-
-const formatTimestamp = (date = new Date()) => {
- const year = date.getFullYear()
- const month = String(date.getMonth() + 1).padStart(2, '0')
- const day = String(date.getDate()).padStart(2, '0')
- const hour = String(date.getHours()).padStart(2, '0')
- const minute = String(date.getMinutes()).padStart(2, '0')
- const second = String(date.getSeconds()).padStart(2, '0')
-
- return `${year}${month}${day}-${hour}${minute}${second}`
-}
-
-const encodeData = (data) => {
- const json = JSON.stringify(data)
- return encoder.encode(json)
-}
-
-const decodeData = (bytes) => {
- const text = decoder.decode(bytes)
- return JSON.parse(text)
-}
-
-const downloadBlob = (blob, fileName) => {
- const url = URL.createObjectURL(blob)
- const link = document.createElement('a')
-
- link.href = url
- link.download = fileName
- document.body.appendChild(link)
- link.click()
- document.body.removeChild(link)
- URL.revokeObjectURL(url)
-}
-
-const pickFile = (accept) => {
- return new Promise((resolve, reject) => {
- const input = document.createElement('input')
- input.type = 'file'
- input.accept = accept
- input.style.display = 'none'
-
- const cleanup = () => {
- input.removeEventListener('change', handleChange)
- input.remove()
- }
-
- const handleChange = () => {
- const file = input.files?.[0] || null
- cleanup()
-
- if (!file) {
- reject(new Error('FILE_NOT_SELECTED'))
- return
- }
-
- resolve(file)
- }
-
- input.addEventListener('change', handleChange, { once: true })
- document.body.appendChild(input)
- input.click()
- })
-}
-
-export const exportData = async (data, suffix, options = {}) => {
- const normalizedSuffix = normalizeSuffix(suffix)
- const bytes = encodeData(data)
- const blob = new Blob([bytes], {
- type: options.mimeType || DEFAULT_MIME_TYPE
- })
- const baseName = sanitizeFileNamePart(options.fileName)
- const fileName = `${baseName}-${formatTimestamp()}${normalizedSuffix}`
- const shouldDownload = options.download !== false
-
- if (shouldDownload) {
- downloadBlob(blob, fileName)
- }
-
- return {
- blob,
- fileName,
- bytes
- }
-}
-
-export const importData = async (suffix) => {
- const normalizedSuffix = normalizeSuffix(suffix)
- const file = await pickFile(normalizedSuffix)
- const fileName = String(file.name || '')
-
- if (!fileName.toLowerCase().endsWith(normalizedSuffix.toLowerCase())) {
- throw new Error('INVALID_FILE_SUFFIX')
- }
-
- const bytes = new Uint8Array(await file.arrayBuffer())
- return decodeData(bytes)
-}
diff --git a/docs/交通工程造价技术中介服务收费项目及标准表》在线计算工具编制说明模板-v2.doc b/docs/交通工程造价技术中介服务收费项目及标准表》在线计算工具编制说明模板-v2.doc
new file mode 100644
index 0000000..d8aaab0
Binary files /dev/null and b/docs/交通工程造价技术中介服务收费项目及标准表》在线计算工具编制说明模板-v2.doc differ
diff --git a/docs/介服务收费项目及标准表》在线计算工具开发.xlsx b/docs/介服务收费项目及标准表》在线计算工具开发.xlsx
new file mode 100644
index 0000000..d04420d
Binary files /dev/null and b/docs/介服务收费项目及标准表》在线计算工具开发.xlsx differ
diff --git a/docs/造价技术中介服务收费项目及标准表》在线计.xlsx b/docs/造价技术中介服务收费项目及标准表》在线计.xlsx
new file mode 100644
index 0000000..7752c61
Binary files /dev/null and b/docs/造价技术中介服务收费项目及标准表》在线计.xlsx differ
diff --git a/index.html b/index.html
index 7864bef..332cdab 100644
--- a/index.html
+++ b/index.html
@@ -4,19 +4,7 @@
-
交通运输工程造价咨询服务预算编制规范
-
-
-
-
-
-
-
-
-
-
-
-
+ 联众咨询
diff --git a/package-lock.json b/package-lock.json
index ccd4869..b9e1b8a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,18 +21,20 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"decimal.js": "^10.6.0",
+ "docxtemplater": "^3.68.5",
"exceljs": "^4.4.0",
+ "file-saver": "^2.0.5",
"localforage": "^1.10.0",
"lucide-vue-next": "^0.563.0",
"motion-v": "^2.0.0",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
+ "pizzip": "^3.2.0",
"reka-ui": "^2.8.0",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"vue": "^3.5.25",
"vue-i18n": "^11.3.0",
- "vue-router": "^4.6.4",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
@@ -657,6 +659,15 @@
"vue": "^3.5.0"
}
},
+ "node_modules/@xmldom/xmldom": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.9.9.tgz",
+ "integrity": "sha512-qycIHAucxy/LXAYIjmLmtQ8q9GPnMbnjG1KXhWm9o5sCr6pOYDATkMPiTNa6/v8eELyqOQ2FsEqeoFYmgv/gJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.6"
+ }
+ },
"node_modules/ag-charts-community": {
"version": "13.1.0",
"license": "MIT",
@@ -1013,6 +1024,18 @@
"node": ">=8"
}
},
+ "node_modules/docxtemplater": {
+ "version": "3.68.5",
+ "resolved": "https://registry.npmmirror.com/docxtemplater/-/docxtemplater-3.68.5.tgz",
+ "integrity": "sha512-2xcHvTXjMA0jdX6PRh1BUTLrcRQ86Re/QJKWCUCX/vv5RKzntjNNkpR/O4AUoJY1TdoqxA+d04L4xgoAUNf/kw==",
+ "license": "MIT",
+ "dependencies": {
+ "@xmldom/xmldom": "^0.9.8"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/duplexer2": {
"version": "0.1.4",
"license": "BSD-3-Clause",
@@ -1117,6 +1140,12 @@
}
}
},
+ "node_modules/file-saver": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz",
+ "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==",
+ "license": "MIT"
+ },
"node_modules/framer-motion": {
"version": "12.34.3",
"license": "MIT",
@@ -1638,6 +1667,21 @@
}
}
},
+ "node_modules/pizzip": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmmirror.com/pizzip/-/pizzip-3.2.0.tgz",
+ "integrity": "sha512-X4NPNICxCfIK8VYhF6wbksn81vTiziyLbvKuORVAmolvnUzl1A1xmz9DAWKxPRq9lZg84pJOOAMq3OE61bD8IQ==",
+ "license": "(MIT OR GPL-3.0)",
+ "dependencies": {
+ "pako": "^2.1.0"
+ }
+ },
+ "node_modules/pizzip/node_modules/pako": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/pako/-/pako-2.1.0.tgz",
+ "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
+ "license": "(MIT AND Zlib)"
+ },
"node_modules/postcss": {
"version": "8.5.6",
"funding": [
@@ -2128,27 +2172,6 @@
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
- "node_modules/vue-router": {
- "version": "4.6.4",
- "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz",
- "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
- "license": "MIT",
- "dependencies": {
- "@vue/devtools-api": "^6.6.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/posva"
- },
- "peerDependencies": {
- "vue": "^3.5.0"
- }
- },
- "node_modules/vue-router/node_modules/@vue/devtools-api": {
- "version": "6.6.4",
- "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
- "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
- "license": "MIT"
- },
"node_modules/vue-tsc": {
"version": "3.2.5",
"dev": true,
diff --git a/package.json b/package.json
index 416e4f1..58353c5 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,13 @@
{
- "name": "ZWJJ2026",
+ "name": "my-vue-app",
"private": true,
- "version": "1.0",
+ "version": "0.0.0",
"type": "module",
"scripts": {
"dev": "bunx --bun vite",
- "build": "bunx vue-tsc -b && bunx --bun vite build",
+ "build": " bunx --bun vite build",
"preview": "bunx --bun vite preview",
- "type-check": "bunx vue-tsc --noEmit",
- "dockerPush": "bun run build && docker build -f Dockerfile.dist -t wintsa/zwzjjstool2026:latest . && docker push wintsa/zwzjjstool2026:latest"
+ "type-check": "bunx vue-tsc --noEmit"
},
"dependencies": {
"@ag-grid-community/locale": "^35.1.0",
@@ -24,18 +23,20 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"decimal.js": "^10.6.0",
+ "docxtemplater": "^3.68.5",
"exceljs": "^4.4.0",
+ "file-saver": "^2.0.5",
"localforage": "^1.10.0",
"lucide-vue-next": "^0.563.0",
"motion-v": "^2.0.0",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
+ "pizzip": "^3.2.0",
"reka-ui": "^2.8.0",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18",
"vue": "^3.5.25",
"vue-i18n": "^11.3.0",
- "vue-router": "^4.6.4",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
diff --git a/public/background.png b/public/background.png
new file mode 100644
index 0000000..849942d
Binary files /dev/null and b/public/background.png differ
diff --git a/public/bg-home.png b/public/bg-home.png
new file mode 100644
index 0000000..7edcc2a
--- /dev/null
+++ b/public/bg-home.png
@@ -0,0 +1 @@
+iVBORw0KGgoAAAANSUhEUgAAAfQAAAH0CAYAAADl8HLGAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4SU
\ No newline at end of file
diff --git a/public/related-files.png b/public/related-files.png
deleted file mode 100644
index e4d5677..0000000
Binary files a/public/related-files.png and /dev/null differ
diff --git a/public/template-doc.doc b/public/template-doc.doc
new file mode 100644
index 0000000..773e5a2
Binary files /dev/null and b/public/template-doc.doc differ
diff --git a/public/template-doc.docx b/public/template-doc.docx
new file mode 100644
index 0000000..9e5eed7
Binary files /dev/null and b/public/template-doc.docx differ
diff --git a/public/template-excel.xlsx b/public/template-excel.xlsx
new file mode 100644
index 0000000..ead6989
Binary files /dev/null and b/public/template-excel.xlsx differ
diff --git a/public/组 4@2x.png b/public/组 4@2x.png
new file mode 100644
index 0000000..78fcb4d
Binary files /dev/null and b/public/组 4@2x.png differ
diff --git a/public/组 5@2x.png b/public/组 5@2x.png
new file mode 100644
index 0000000..e09f59f
Binary files /dev/null and b/public/组 5@2x.png differ
diff --git a/public/组 6@2x.png b/public/组 6@2x.png
new file mode 100644
index 0000000..65cda32
Binary files /dev/null and b/public/组 6@2x.png differ
diff --git a/src/App.vue b/src/App.vue
index 7c2aa3f..b1f618d 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,3 +1,323 @@
+
+
-
+
+
+
+
{{ t('app.projectConflict.title') }}
+
+ {{ t('app.projectConflict.desc', { name: currentProjectName }) }}
+
+
+ {{ t('app.projectConflict.countdown', { seconds: closeCountdown }) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/features/app/components/WorkspaceShell.vue b/src/features/app/components/WorkspaceShell.vue
deleted file mode 100644
index 1da72e2..0000000
--- a/src/features/app/components/WorkspaceShell.vue
+++ /dev/null
@@ -1,318 +0,0 @@
-
-
-
-
-
-
-
{{ t('app.projectConflict.title') }}
-
- {{ t('app.projectConflict.desc', { name: currentProjectName }) }}
-
-
- {{ t('app.projectConflict.countdown', { seconds: closeCountdown }) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/features/disclaimer/components/DisclaimerPage.vue b/src/features/disclaimer/components/DisclaimerPage.vue
deleted file mode 100644
index 88307a2..0000000
--- a/src/features/disclaimer/components/DisclaimerPage.vue
+++ /dev/null
@@ -1,197 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{{ t('disclaimerPage.eyebrow') }}
-
- {{ t('disclaimerPage.pageTitle') }}
-
-
- {{ t('disclaimerPage.lastUpdatedLabel') }}
- {{ t('disclaimerPage.lastUpdatedValue') }}
-
-
- {{ t('disclaimerPage.leadText') }}
-
-
-
-
-
-
-
-
- {{ section.title }}
-
- {{ paragraph }}
-
-
-
-
- {{ t('disclaimerPage.confirm.title') }}
- {{ t('disclaimerPage.confirm.desc1') }}
- {{ t('disclaimerPage.confirm.desc2') }}
-
-
-
-
-
- {{ t('disclaimerPage.confirm.hint') }}
-
-
-
-
-
-
-
-
diff --git a/src/features/ht/components/Ht.vue b/src/features/ht/components/Ht.vue
index 61ed8e5..e5a42ab 100644
--- a/src/features/ht/components/Ht.vue
+++ b/src/features/ht/components/Ht.vue
@@ -74,6 +74,7 @@ import {
ToastTitle,
ToastViewport
} from 'reka-ui'
+import {useDataStore} from '@/pinia/zx'
const STORAGE_KEY = 'ht-card-v1'
const tabStore = useTabStore()
@@ -333,8 +334,18 @@ const loadContractBudgetFee = async (contractId: string) => {
loadHtMainTotalFee(`htExtraFee-${contractId}-additional-work`),
loadHtMainTotalFee(`htExtraFee-${contractId}-reserve`)
])
- const parts = [serviceFee, additionalFee, reserveFee]
- const total = sumNullableNumbers(parts)
+
+ const zxRows = await useDataStore().query([
+ { field: 'type', value: `${contractId}-zxFw`, operator: 'eq' }
+ ])
+ const totalFinalFee = zxRows.reduce((sum, row) => {
+ return sum + (Number(row.finalFee) || 0)
+ }, 0)
+
+ const total = totalFinalFee;
+
+ /*const parts = [serviceFee, additionalFee, reserveFee]
+ const total = sumNullableNumbers(parts)*/
return total == null ? null : roundTo(total, 2)
}
diff --git a/src/features/ht/components/HtContractSummary.vue b/src/features/ht/components/HtContractSummary.vue
index f3db7e6..5f8b8bc 100644
--- a/src/features/ht/components/HtContractSummary.vue
+++ b/src/features/ht/components/HtContractSummary.vue
@@ -1,4 +1,4 @@
-
-
+
diff --git a/src/features/ht/components/zxFw.vue b/src/features/ht/components/zxFw.vue
index 40c07b9..8bd19a7 100644
--- a/src/features/ht/components/zxFw.vue
+++ b/src/features/ht/components/zxFw.vue
@@ -1,5 +1,17 @@
-
@@ -1346,6 +1760,7 @@ onActivated(async () => {
consultCategoryFactorMap.value.get(String(props.serviceId)) ?? null
const getDefaultMajorFactorById = (id: string): number | null => majorFactorMap.value.get(id) ?? null
-const usesInvestScaleSingleTotal = computed(() => {
+const isOnlyCostScaleService = computed(() => {
const service = getServiceDictItemById(props.serviceId) as ServiceLite | undefined
- return isInvestScaleSingleTotalService(service)
+ return service?.onlyCostScale === true
})
const isMutipleService = computed(() => {
const service = getServiceDictItemById(props.serviceId) as ServiceLite | undefined
@@ -197,6 +202,10 @@ const inferProjectCountFromRows = (rows?: Array>) => {
return inferScaleProjectCountFromRows(rows, isMutipleService.value)
}
const totalLabel = computed(() => {
+ if (isOnlyCostScaleService.value) {
+ const service = getServiceDictItemById(props.serviceId) as { code?: string; name?: string } | undefined
+ return `${service?.code || ''} ${service?.name || ''}`.trim()
+ }
const industryName = getIndustryDisplayName(activeIndustryCode.value.trim(), locale.value)
return industryName ? t('pricingScale.totalInvestmentByIndustry', { industryName }) : t('pricingScale.totalInvestment')
})
@@ -251,17 +260,236 @@ const shouldForceDefaultLoad = () => {
const getMethodState = () =>
zxFwPricingStore.getServicePricingMethodState(props.contractId, props.serviceId, 'investScale')
+// 从咨询服务明细中获取数据
+const c0Amount = ref(null)
+
+const loadC0Amount = async () => {
+ try {
+ // 直接从合同段规模信息中获取 C0 建设项目总费用
+ const htScaleState = await kvStore.getItem<{ totalAmount?: number | null }>(HT_DB_KEY.value)
+
+ if (typeof htScaleState?.totalAmount === 'number' && htScaleState.totalAmount > 0) {
+ c0Amount.value = htScaleState.totalAmount
+ return
+ }
+
+ // 回退:尝试从项目规模信息中获取
+ const xmScaleState = await kvStore.getItem<{ totalAmount?: number | null }>('xm-info-v3')
+ c0Amount.value = typeof xmScaleState?.totalAmount === 'number' ? xmScaleState.totalAmount : null
+ } catch (e) {
+ c0Amount.value = null
+ }
+}
+
+const SERVICE_SCALE_RULES: Record = {
+ 'D1': [
+ { limit: 1000, rate: 1.32, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.99, baseAmount: 13200, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.83, baseAmount: 102900, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.66, baseAmount: 930900, base: 'F≧100000' }
+ ],
+ 'D2-1': [
+ { limit: 1000, rate: 0.67, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.50, baseAmount: 6700, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.42, baseAmount: 51700, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.33, baseAmount: 423700, base: 'F≧100000' }
+ ],
+ 'D2-2-1': [
+ { limit: 1000, rate: 0.73, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.55, baseAmount: 7300, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.46, baseAmount: 56800, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.37, baseAmount: 467800, base: 'F≧100000' }
+ ],
+ 'D3-1': [
+ { limit: 1000, rate: 0.13, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.10, baseAmount: 1300, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.08, baseAmount: 10300, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.07, baseAmount: 82300, base: 'F≧100000' }
+ ],
+ 'D3-2': [
+ { limit: 1000, rate: 0.26, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.20, baseAmount: 26000, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.17, baseAmount: 206000, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.13, baseAmount: 1646000, base: 'F≧100000' }
+ ],
+ 'D3-3': [
+ { limit: 1000, rate: 0.40, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.30, baseAmount: 40000, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.25, baseAmount: 310000, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.20, baseAmount: 2480000, base: 'F≧100000' }
+ ],
+ 'D3-4': [
+ { limit: 1000, rate: 0.24, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.18, baseAmount: 24000, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.15, baseAmount: 192000, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.12, baseAmount: 1542000, base: 'F≧100000' }
+ ],
+ 'D3-6-1': [
+ { limit: 1000, rate: 0.40, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.30, baseAmount: 40000, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.25, baseAmount: 310000, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.20, baseAmount: 2480000, base: 'F≧100000' }
+ ],
+ 'D3-7': [
+ { limit: 1000, rate: 1.00, baseAmount: 0, base: 'F<1000' },
+ { limit: 10000, rate: 0.90, baseAmount: 100000, base: '1000≦F<10000' },
+ { limit: 100000, rate: 0.80, baseAmount: 910000, base: '10000≦F<100000' },
+ { limit: 500000, rate: 0.70, baseAmount: 8210000, base: '100000≦F<500000' },
+ { limit: Infinity, rate: 0.60, baseAmount: 34210000, base: 'F≧500000' }
+ ],
+ 'D4-6': [
+ { limit: 1000, rate: 5.00, baseAmount: 0, base: 'F<1000' },
+ { limit: 5000, rate: 3.50, baseAmount: 50000, base: '1000≦F<5000' },
+ { limit: 10000, rate: 2.00, baseAmount: 190000, base: '5000≦F<10000' },
+ { limit: 100000, rate: 1.00, baseAmount: 290000, base: '10000≦F<100000' },
+ { limit: Infinity, rate: 0.80, baseAmount: 1090000, base: 'F≧100000' }
+ ]
+}
+
+const calcServiceScaleAmount = (code: string, F: number): { formula: string; amount: number; base: string } => {
+ if (F == null || F < 0) return { formula: '', amount: 0, base: '' }
+ const rules = SERVICE_SCALE_RULES[code]
+ if (!rules) return { formula: '无对应规则', amount: 0, base: '' }
+
+ let prevLimit = 0
+ for (let i = 0; i < rules.length; i++) {
+ const { limit, rate, baseAmount, base } = rules[i]
+ if (F < limit) {
+ if (baseAmount === 0) {
+ // 第一档:直接按比例计算
+ const calculatedAmount = F * rate * 10000
+ return {
+ formula: `F×${rate}%`,
+ amount: Math.round(calculatedAmount),
+ base: base,
+ }
+ } else {
+ // 后续档位:基础金额 + 超出部分按比例计算
+ const calculatedAmount = baseAmount + (F - prevLimit) * rate * 10000
+ return {
+ formula: `${baseAmount.toLocaleString()}+(F-${prevLimit.toLocaleString()})×${rate}%`,
+ amount: Math.round(calculatedAmount),
+ base: base,
+ }
+ }
+ }
+ prevLimit = limit
+ }
+ return { formula: '', amount: 0, base: '' }
+}
+
+const calculateServiceFeeForRow = (row: DetailRow): number | null => {
+ const budgetFee = typeof row.budgetFee === 'number' ? row.budgetFee : 0
+ const workStageFactor = typeof row.workStageFactor === 'number' ? row.workStageFactor : 1
+ const workRatio = typeof row.workRatio === 'number' ? row.workRatio : 1
+
+ if (budgetFee === null) return null
+
+ return Math.round(budgetFee * workStageFactor * workRatio)
+}
+
+// ✅ 批量重新计算所有行的 serviceFee
+const recalculateServiceFees = () => {
+ for (const row of fallbackDetailRows.value) {
+ row.serviceFee = calculateServiceFeeForRow(row)
+ }
+}
+
+const fallbackDetailRows = ref([])
const detailRows = computed({
get: () => {
- const rows = getMethodState()?.detailRows
- return Array.isArray(rows) ? rows : []
+ return fallbackDetailRows.value;
+ /*const contractState = zxFwPricingStore.contracts[props.contractId]
+ if (!contractState?.detailRows) return []
+
+ const F = c0Amount.value
+ const isC0Available = F != null && F > 0
+
+ // 获取当前的investScale状态,用于保持用户编辑的系数等
+ const currentInvestScaleState = zxFwPricingStore.getServicePricingMethodState(
+ props.contractId,
+ props.serviceId,
+ 'investScale'
+ )
+ if (contractState.detailRows.length > 0) {
+ const rowsToMap = contractState.detailRows.slice(0, -1)
+ return rowsToMap.map(row => {
+ const code = row.code || ''
+
+ const { formula, amount, base } = isC0Available ? calcServiceScaleAmount(code, F) : { formula: '', amount: 0, base: '' }
+ // 查找当前状态中对应的行,获取用户编辑过的值
+ const currentDetailRow = currentInvestScaleState?.detailRows?.find(
+ r => r.majorDictId === row.id
+ )
+
+ // 使用用户编辑的值,如果没有则使用默认值
+ const workStageFactor = currentDetailRow?.workStageFactor ?? 1
+ const workRatio = currentDetailRow?.workRatio ?? 1
+
+
+
+ return {
+ id: row.id || '',
+ projectIndex: 1,
+ majorDictId: row.id || '',
+ groupCode: code,
+ groupName: row.name || '',
+ majorCode: code,
+ majorName: row.name || '',
+ hasCost: true,
+ hasArea: false,
+ amount: F,
+ benchmarkBudget: isC0Available ? amount : null,
+ benchmarkBudgetBasic: isC0Available ? amount : null,
+ benchmarkBudgetOptional: isC0Available ? 0 : null,
+ benchmarkBudgetBasicChecked: isC0Available ? true : true,
+ benchmarkBudgetOptionalChecked: isC0Available ? false : true,
+ basicFormula: isC0Available ? 'C0建设项目总费用' : '',
+ optionalFormula: isC0Available ? formula : '',
+ consultCategoryFactor: currentDetailRow?.consultCategoryFactor ?? null,
+ majorFactor: currentDetailRow?.majorFactor ?? null,
+ workStageFactor: workStageFactor, // 使用用户编辑的值
+ workRatio: workRatio, // 使用用户编辑的值
+ budgetFee: isC0Available ? amount : null,
+ budgetFeeBasic: isC0Available ? amount : null,
+ budgetFeeOptional: isC0Available ? 0 : null,
+ serviceFee: isC0Available ? Math.round(amount * workStageFactor * workRatio / 100) : null,
+ remark: row.remark || '',
+ path: [code, row.id || ''],
+ base: base,
+ code: code
+ }
+ })
+ }
+
+ return []*/
},
set: rows => {
+ saveToIndexedDB();
+ fallbackDetailRows.value = rows
+ /*// 将编辑后的视图数据转换回存储格式
+ const investScaleDetailRows = []
+ for (let i = 0; i < rows.length; i++) {
+ const row = rows[i]
+ investScaleDetailRows.push({
+ majorDictId: row.majorDictId,
+ consultCategoryFactor: row.consultCategoryFactor,
+ majorFactor: row.majorFactor,
+ workStageFactor: row.workStageFactor,
+ workRatio: row.workRatio
+ })
+ }
+
const currentState = getMethodState()
- zxFwPricingStore.setServicePricingMethodState(props.contractId, props.serviceId, 'investScale', {
- detailRows: rows,
- projectCount: currentState?.projectCount ?? getTargetProjectCount()
- })
+ zxFwPricingStore.setServicePricingMethodState(
+ props.contractId,
+ props.serviceId,
+ 'investScale',
+ {
+ detailRows: investScaleDetailRows,
+ projectCount: currentState?.projectCount ?? getTargetProjectCount()
+ }
+ )*/
}
})
type majorLite = {
@@ -272,6 +500,7 @@ type majorLite = {
hasArea?: boolean
industryId?: string | number | null
}
+
const serviceEntries: Array<[string, majorLite]> = []
const detailDict: ScaleDictGroup[] = []
const idLabelMap = new Map()
@@ -291,47 +520,63 @@ const rebuildScaleDictCaches = () => {
}
rebuildScaleDictCaches()
-const buildDefaultRows = (projectCountValue = getTargetProjectCount()): DetailRow[] => {
- return buildScaleRowsFromDict({
- detailDict,
- projectCount: projectCountValue,
- activeIndustryCode: activeIndustryCode.value,
- isMajorInIndustryScope: isMajorIdInIndustryScope,
- buildScopedRowId,
- buildProjectGroupPathKey,
- isMutipleService: isMutipleService.value,
- createRow: ({ projectIndex, group, child, rowId, path }) => ({
+const buildDefaultRows = async (): Promise => {
+ const rows: DetailRow[] = []
+
+ // ✅ 从 zxFw 数据获取专家列表
+ const experts = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-zxFw`, operator: 'eq' }
+ ])
+
+ // ✅ 为每个专家生成默认行
+ for (const expert of experts) {
+ const expertId = expert.id || expert._id
+ const contractId = props.contractId
+ const rowId = `${contractId}-investment-${expertId}`
+ const code = expert.code || ''
+
+ // ✅ 计算默认值
+ const F = c0Amount.value
+ const isC0Available = F != null && F > 0
+ const { formula, amount, base } = isC0Available ? calcServiceScaleAmount(code, F) : { formula: '', amount: 0, base: '' }
+
+ rows.push({
id: rowId,
- projectIndex,
- majorDictId: child.id,
- groupCode: group.code,
- groupName: group.name,
- majorCode: child.code,
- majorName: child.name,
- hasCost: child.hasCost,
- hasArea: child.hasArea,
- amount: null,
- benchmarkBudget: null,
- benchmarkBudgetBasic: null,
- benchmarkBudgetOptional: null,
+ projectIndex: 1,
+ majorDictId: expertId || '',
+ groupCode: code,
+ groupName: expert.name || '',
+ majorCode: code,
+ majorName: expert.name || '',
+ hasCost: true,
+ hasArea: false,
+ amount: F,
+ benchmarkBudget: isC0Available ? amount : null,
+ benchmarkBudgetBasic: isC0Available ? amount : null,
+ benchmarkBudgetOptional: isC0Available ? 0 : null,
benchmarkBudgetBasicChecked: true,
- benchmarkBudgetOptionalChecked: true,
- basicFormula: '',
- optionalFormula: '',
+ benchmarkBudgetOptionalChecked: false,
+ basicFormula: isC0Available ? 'C0建设项目总费用' : '',
+ optionalFormula: isC0Available ? formula : '',
consultCategoryFactor: null,
majorFactor: null,
- workStageFactor: 1,
- workRatio: 1,
- budgetFee: null,
- budgetFeeBasic: null,
- budgetFeeOptional: null,
- remark: '',
- path
+ workStageFactor: 1, // ✅ 默认值
+ workRatio: 1, // ✅ 默认值
+ budgetFee: isC0Available ? amount : null,
+ budgetFeeBasic: isC0Available ? amount : null,
+ budgetFeeOptional: isC0Available ? 0 : null,
+ serviceFee: isC0Available ? Math.round(amount * 1) : null,
+ remark: expert.remark || '',
+ path: [code, expertId || ''],
+ base: base,
+ code: code
})
- })
+ }
+
+ return rows
}
-const calcSingleTotalAmountFromRows = (
+const calcOnlyCostScaleAmountFromRows = (
rows?: Array<{ amount?: unknown; isGroupRow?: unknown }>,
totalAmount?: number | null
) => {
@@ -341,7 +586,7 @@ const calcSingleTotalAmountFromRows = (
return sumByNumber(rows || [], row => (typeof row?.amount === 'number' ? row.amount : null))
}
-const getSingleTotalMajorEntry = () => {
+const getOnlyCostScaleMajorEntry = () => {
const industryId = String(activeIndustryCode.value || '').trim()
if (!industryId) return null
const industryMajor = serviceEntries.find(([, item]) => {
@@ -353,8 +598,8 @@ const getSingleTotalMajorEntry = () => {
return { id, item }
}
-const getSingleTotalMajorFactorDefault = () => {
- const industryMajor = getSingleTotalMajorEntry()
+const getOnlyCostScaleMajorFactorDefault = () => {
+ const industryMajor = getOnlyCostScaleMajorEntry()
if (!industryMajor) return 1
const majorId = industryMajor.id
const majorItem = industryMajor.item
@@ -364,7 +609,7 @@ const getSingleTotalMajorFactorDefault = () => {
return 1
}
-const buildInvestScaleSingleTotalRow = (
+const buildOnlyCostScaleRow = (
amount: number | null,
projectIndex: number,
fromDb?: Partial<
@@ -379,41 +624,46 @@ const buildInvestScaleSingleTotalRow = (
| 'benchmarkBudgetOptionalChecked'
>
>
-): DetailRow => ({
- id: buildScopedRowId(projectIndex, getSingleTotalMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID),
- projectIndex,
- majorDictId: getSingleTotalMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID,
- groupCode: getSingleTotalMajorEntry()?.item?.code || 'TOTAL',
- groupName: getSingleTotalMajorEntry()?.item?.name || totalLabel.value,
- majorCode: getSingleTotalMajorEntry()?.item?.code || 'TOTAL',
- majorName: getSingleTotalMajorEntry()?.item?.name || totalLabel.value,
- hasCost: true,
- hasArea: false,
- amount,
- benchmarkBudget: null,
- benchmarkBudgetBasic: null,
- benchmarkBudgetOptional: null,
- benchmarkBudgetBasicChecked:
- typeof fromDb?.benchmarkBudgetBasicChecked === 'boolean' ? fromDb.benchmarkBudgetBasicChecked : true,
- benchmarkBudgetOptionalChecked:
- typeof fromDb?.benchmarkBudgetOptionalChecked === 'boolean' ? fromDb.benchmarkBudgetOptionalChecked : true,
- basicFormula: '',
- optionalFormula: '',
- consultCategoryFactor:
- typeof fromDb?.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : getDefaultConsultCategoryFactor(),
- majorFactor: typeof fromDb?.majorFactor === 'number' ? fromDb.majorFactor : getSingleTotalMajorFactorDefault(),
- workStageFactor: typeof fromDb?.workStageFactor === 'number' ? fromDb.workStageFactor : 1,
- workRatio: typeof fromDb?.workRatio === 'number' ? fromDb.workRatio : 1,
- budgetFee: null,
- budgetFeeBasic: null,
- budgetFeeOptional: null,
- remark: typeof fromDb?.remark === 'string' ? fromDb.remark : '',
- path: isMutipleService.value
- ? [buildProjectGroupPathKey(projectIndex), buildScopedRowId(projectIndex, getSingleTotalMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID)]
- : [buildScopedRowId(projectIndex, getSingleTotalMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID)]
-})
+): DetailRow => {
+ const service = getServiceDictItemById(props.serviceId) as { code?: string; name?: string } | undefined
+ const serviceCode = service?.code || 'D1'
+ const serviceName = service?.name || '全过程造价咨询'
+ return {
+ id: buildScopedRowId(projectIndex, getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID),
+ projectIndex,
+ majorDictId: getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID,
+ groupCode: serviceCode,
+ groupName: serviceName,
+ majorCode: serviceCode,
+ majorName: serviceName,
+ hasCost: true,
+ hasArea: false,
+ amount,
+ benchmarkBudget: null,
+ benchmarkBudgetBasic: null,
+ benchmarkBudgetOptional: null,
+ benchmarkBudgetBasicChecked:
+ typeof fromDb?.benchmarkBudgetBasicChecked === 'boolean' ? fromDb.benchmarkBudgetBasicChecked : true,
+ benchmarkBudgetOptionalChecked:
+ typeof fromDb?.benchmarkBudgetOptionalChecked === 'boolean' ? fromDb.benchmarkBudgetOptionalChecked : true,
+ basicFormula: '',
+ optionalFormula: '',
+ consultCategoryFactor:
+ typeof fromDb?.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : getDefaultConsultCategoryFactor(),
+ majorFactor: typeof fromDb?.majorFactor === 'number' ? fromDb.majorFactor : getOnlyCostScaleMajorFactorDefault(),
+ workStageFactor: typeof fromDb?.workStageFactor === 'number' ? fromDb.workStageFactor : 1,
+ workRatio: typeof fromDb?.workRatio === 'number' ? fromDb.workRatio : 100,
+ budgetFee: null,
+ budgetFeeBasic: null,
+ budgetFeeOptional: null,
+ remark: typeof fromDb?.remark === 'string' ? fromDb.remark : '',
+ path: isMutipleService.value
+ ? [buildProjectGroupPathKey(projectIndex), buildScopedRowId(projectIndex, getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID)]
+ : [buildScopedRowId(projectIndex, getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID)]
+ }
+}
-const buildInvestScaleSingleTotalRows = (
+const buildOnlyCostScaleRows = (
rowsFromDb?: Array & Pick>,
options?: {
projectCount?: number
@@ -423,10 +673,10 @@ const buildInvestScaleSingleTotalRows = (
}
): DetailRow[] => {
const targetProjectCount = normalizeProjectCount(options?.projectCount ?? getTargetProjectCount())
- const singleTotalMajorId = getSingleTotalMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID
+ const onlyCostMajorId = getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID
const singleRowSummaryAmount =
options?.preferSummaryAmountWhenSingleRow
- ? calcSingleTotalAmountFromRows(
+ ? calcOnlyCostScaleAmountFromRows(
rowsFromDb as Array<{ amount?: unknown; isGroupRow?: unknown }>,
options.totalAmount
)
@@ -434,26 +684,26 @@ const buildInvestScaleSingleTotalRows = (
const dbValueMap = new Map & Pick>()
for (const row of rowsFromDb || []) {
const projectIndex = resolveRowProjectIndex(row)
- const majorDictId = resolveRowMajorDictId(row) || singleTotalMajorId
+ const majorDictId = resolveRowMajorDictId(row) || onlyCostMajorId
dbValueMap.set(makeProjectMajorKey(projectIndex, majorDictId), row)
- if (String(row.id || '') === ONLY_COST_SCALE_ROW_ID && !dbValueMap.has(makeProjectMajorKey(projectIndex, singleTotalMajorId))) {
- dbValueMap.set(makeProjectMajorKey(projectIndex, singleTotalMajorId), row)
+ if (String(row.id || '') === ONLY_COST_SCALE_ROW_ID && !dbValueMap.has(makeProjectMajorKey(projectIndex, onlyCostMajorId))) {
+ dbValueMap.set(makeProjectMajorKey(projectIndex, onlyCostMajorId), row)
}
}
const result: DetailRow[] = []
for (let projectIndex = 1; projectIndex <= targetProjectCount; projectIndex++) {
- const key = makeProjectMajorKey(projectIndex, singleTotalMajorId)
- const firstProjectKey = makeProjectMajorKey(1, singleTotalMajorId)
+ const key = makeProjectMajorKey(projectIndex, onlyCostMajorId)
+ const firstProjectKey = makeProjectMajorKey(1, onlyCostMajorId)
const fromDb =
dbValueMap.get(key) ||
(options?.cloneFromProjectOne && projectIndex > 1 ? dbValueMap.get(firstProjectKey) : undefined)
const fallbackAmount =
options?.cloneFromProjectOne && projectIndex > 1 && fromDb == null
- ? calcSingleTotalAmountFromRows(rowsFromDb as Array<{ amount?: unknown; isGroupRow?: unknown }>, options.totalAmount)
+ ? calcOnlyCostScaleAmountFromRows(rowsFromDb as Array<{ amount?: unknown; isGroupRow?: unknown }>, options.totalAmount)
: null
result.push(
- buildInvestScaleSingleTotalRow(
+ buildOnlyCostScaleRow(
singleRowSummaryAmount ?? (typeof fromDb?.amount === 'number' ? fromDb.amount : fallbackAmount),
projectIndex,
fromDb
@@ -465,37 +715,67 @@ const buildInvestScaleSingleTotalRows = (
}
type SourceRow = Pick &
- Partial<
- Pick<
- DetailRow,
- | 'projectIndex'
- | 'majorDictId'
- | 'amount'
- | 'benchmarkBudget'
- | 'benchmarkBudgetBasic'
- | 'benchmarkBudgetOptional'
- | 'benchmarkBudgetBasicChecked'
- | 'benchmarkBudgetOptionalChecked'
- | 'basicFormula'
- | 'optionalFormula'
- | 'consultCategoryFactor'
- | 'majorFactor'
- | 'workStageFactor'
- | 'workRatio'
- | 'budgetFee'
- | 'budgetFeeBasic'
- | 'budgetFeeOptional'
- | 'remark'
- >
- >
-const mergeWithDictRows = (
- rowsFromDb: SourceRow[] | undefined,
- options?: {
- includeAmount?: boolean
- includeFactorValues?: boolean
- projectCount?: number
- cloneFromProjectOne?: boolean
+ Partial<
+ Pick<
+ DetailRow,
+ | 'projectIndex'
+ | 'majorDictId'
+ | 'amount'
+ | 'benchmarkBudget'
+ | 'benchmarkBudgetBasic'
+ | 'benchmarkBudgetOptional'
+ | 'benchmarkBudgetBasicChecked'
+ | 'benchmarkBudgetOptionalChecked'
+ | 'basicFormula'
+ | 'optionalFormula'
+ | 'consultCategoryFactor'
+ | 'majorFactor'
+ | 'workStageFactor'
+ | 'workRatio'
+ | 'budgetFee'
+ | 'budgetFeeBasic'
+ | 'budgetFeeOptional'
+ | 'remark'
+ >
+ >
+
+const mergeWithDictRows = async (rowsFromDb: DetailRow[]): Promise => {
+ const dbValueMap = new Map()
+
+ // ✅ 构建数据库数据映射
+ for (const row of rowsFromDb) {
+ dbValueMap.set(row.id, row)
}
+
+ // ✅ 获取默认行
+ const defaultRows = await buildDefaultRows()
+
+ // ✅ 合并数据库数据和默认数据
+ return defaultRows.map(row => {
+ const fromDb = dbValueMap.get(row.id)
+ if (!fromDb) return row
+
+ // ✅ 保留数据库中的所有可编辑字段
+ return {
+ ...row,
+ // 可编辑字段从数据库加载
+ serviceFee: typeof fromDb.serviceFee === 'number' ? fromDb.serviceFee : row.serviceFee,
+ consultCategoryFactor: typeof fromDb.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : null,
+ majorFactor: typeof fromDb.majorFactor === 'number' ? fromDb.majorFactor : null,
+ workStageFactor: typeof fromDb.workStageFactor === 'number' ? fromDb.workStageFactor : 1,
+ workRatio: typeof fromDb.workRatio === 'number' ? fromDb.workRatio : 1,
+ remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
+ }
+ })
+}
+/*const mergeWithDictRows = (
+ rowsFromDb: SourceRow[] | undefined,
+ options?: {
+ includeAmount?: boolean
+ includeFactorValues?: boolean
+ projectCount?: number
+ cloneFromProjectOne?: boolean
+ }
): DetailRow[] => {
const includeAmount = options?.includeAmount ?? true
const includeFactorValues = options?.includeFactorValues ?? true
@@ -508,48 +788,49 @@ const mergeWithDictRows = (
resolveMajorDictId: row => resolveRowMajorDictId(row),
cloneFromProjectOne: options?.cloneFromProjectOne,
mergeRow: (row, fromDb) => {
- if (!fromDb) return row
- const nextMajorDictId = resolveRowMajorDictId(row)
- const hasConsultCategoryFactor = Object.prototype.hasOwnProperty.call(fromDb, 'consultCategoryFactor')
- const hasMajorFactor = Object.prototype.hasOwnProperty.call(fromDb, 'majorFactor')
- return {
- ...row,
- amount: includeAmount && row.hasCost && typeof fromDb.amount === 'number' ? fromDb.amount : null,
- benchmarkBudget: typeof fromDb.benchmarkBudget === 'number' ? fromDb.benchmarkBudget : null,
- benchmarkBudgetBasic: typeof fromDb.benchmarkBudgetBasic === 'number' ? fromDb.benchmarkBudgetBasic : null,
- benchmarkBudgetOptional: typeof fromDb.benchmarkBudgetOptional === 'number' ? fromDb.benchmarkBudgetOptional : null,
- benchmarkBudgetBasicChecked:
- typeof fromDb.benchmarkBudgetBasicChecked === 'boolean' ? fromDb.benchmarkBudgetBasicChecked : true,
- benchmarkBudgetOptionalChecked:
- typeof fromDb.benchmarkBudgetOptionalChecked === 'boolean' ? fromDb.benchmarkBudgetOptionalChecked : true,
- basicFormula: typeof fromDb.basicFormula === 'string' ? fromDb.basicFormula : '',
- optionalFormula: typeof fromDb.optionalFormula === 'string' ? fromDb.optionalFormula : '',
- consultCategoryFactor:
- !includeFactorValues
- ? null
- : typeof fromDb.consultCategoryFactor === 'number'
- ? fromDb.consultCategoryFactor
- : hasConsultCategoryFactor
- ? null
- : getDefaultConsultCategoryFactor(),
- majorFactor:
- !includeFactorValues
- ? null
- : typeof fromDb.majorFactor === 'number'
- ? fromDb.majorFactor
- : hasMajorFactor
- ? null
- : getDefaultMajorFactorById(nextMajorDictId),
- workStageFactor: typeof fromDb.workStageFactor === 'number' ? fromDb.workStageFactor : row.workStageFactor,
- workRatio: typeof fromDb.workRatio === 'number' ? fromDb.workRatio : row.workRatio,
- budgetFee: typeof fromDb.budgetFee === 'number' ? fromDb.budgetFee : null,
- budgetFeeBasic: typeof fromDb.budgetFeeBasic === 'number' ? fromDb.budgetFeeBasic : null,
- budgetFeeOptional: typeof fromDb.budgetFeeOptional === 'number' ? fromDb.budgetFeeOptional : null,
- remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
- }
+ if (!fromDb) return row
+ const nextMajorDictId = resolveRowMajorDictId(row)
+ const hasConsultCategoryFactor = Object.prototype.hasOwnProperty.call(fromDb, 'consultCategoryFactor')
+ const hasMajorFactor = Object.prototype.hasOwnProperty.call(fromDb, 'majorFactor')
+ return {
+ ...row,
+ amount: includeAmount && row.hasCost && typeof fromDb.amount === 'number' ? fromDb.amount : null,
+ benchmarkBudget: typeof fromDb.benchmarkBudget === 'number' ? fromDb.benchmarkBudget : null,
+ benchmarkBudgetBasic: typeof fromDb.benchmarkBudgetBasic === 'number' ? fromDb.benchmarkBudgetBasic : null,
+ benchmarkBudgetOptional: typeof fromDb.benchmarkBudgetOptional === 'number' ? fromDb.benchmarkBudgetOptional : null,
+ benchmarkBudgetBasicChecked:
+ typeof fromDb.benchmarkBudgetBasicChecked === 'boolean' ? fromDb.benchmarkBudgetBasicChecked : true,
+ benchmarkBudgetOptionalChecked:
+ typeof fromDb.benchmarkBudgetOptionalChecked === 'boolean' ? fromDb.benchmarkBudgetOptionalChecked : true,
+ basicFormula: typeof fromDb.basicFormula === 'string' ? fromDb.basicFormula : '',
+ optionalFormula: typeof fromDb.optionalFormula === 'string' ? fromDb.optionalFormula : '',
+ consultCategoryFactor:
+ !includeFactorValues
+ ? null
+ : typeof fromDb.consultCategoryFactor === 'number'
+ ? fromDb.consultCategoryFactor
+ : hasConsultCategoryFactor
+ ? null
+ : getDefaultConsultCategoryFactor(),
+ majorFactor:
+ !includeFactorValues
+ ? null
+ : typeof fromDb.majorFactor === 'number'
+ ? fromDb.majorFactor
+ : hasMajorFactor
+ ? null
+ : getDefaultMajorFactorById(nextMajorDictId),
+ workStageFactor: typeof fromDb.workStageFactor === 'number' ? fromDb.workStageFactor : row.workStageFactor,
+ workRatio: typeof fromDb.workRatio === 'number' ? fromDb.workRatio : row.workRatio,
+ budgetFee: typeof fromDb.budgetFee === 'number' ? fromDb.budgetFee : null,
+ budgetFeeBasic: typeof fromDb.budgetFeeBasic === 'number' ? fromDb.budgetFeeBasic : null,
+ budgetFeeOptional: typeof fromDb.budgetFeeOptional === 'number' ? fromDb.budgetFeeOptional : null,
+ remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
+ }
}
})
-}
+}*/
+
const formatEditableMoney = (params: any) =>
formatScaleEditableConditionalNumber(params, {
@@ -616,17 +897,31 @@ const getBudgetFee = (
>
) => getScaleBudgetFeeByRow(row, 'cost')
+/**
+ * 计算服务费用:计算金额 × 工作环节系数 × 工作占比 / 100
+ * @param row 数据行对象,包含 benchmarkBudget、workStageFactor、workRatio 字段
+ * @returns 四舍五入后的服务费用(元)
+ */
+const getServiceFee = (row?: Pick) => {
+ const budget = typeof row?.benchmarkBudget === 'number' ? row.benchmarkBudget : null
+ const workStageFactor = typeof row?.workStageFactor === 'number' ? row.workStageFactor : 1
+ const workRatio = typeof row?.workRatio === 'number' ? row.workRatio : 1
+
+ if (budget == null) return null
+ return Math.round(budget * workStageFactor * workRatio * 10000)
+}
+
const getBudgetFeeSplit = (
- row?: Pick<
- DetailRow,
- | 'amount'
- | 'benchmarkBudgetBasicChecked'
- | 'benchmarkBudgetOptionalChecked'
- | 'majorFactor'
- | 'consultCategoryFactor'
- | 'workStageFactor'
- | 'workRatio'
- >
+ row?: Pick<
+ DetailRow,
+ | 'amount'
+ | 'benchmarkBudgetBasicChecked'
+ | 'benchmarkBudgetOptionalChecked'
+ | 'majorFactor'
+ | 'consultCategoryFactor'
+ | 'workStageFactor'
+ | 'workRatio'
+ >
) => getScaleBudgetFeeSplitByRow(row, 'cost')
const restoreAmountColumnDefaults = async () => {
@@ -635,10 +930,10 @@ const restoreAmountColumnDefaults = async () => {
const sourceRowMap = buildContractScaleMap(sourceRows)
const sourceRowIdMap = buildContractScaleIdMap(sourceRows)
const projectTotals = buildContractScaleProjectTotals(sourceRows, htData?.totalAmount)
- const useSummaryAmount = detailRows.value.length === 1 || usesInvestScaleSingleTotal.value
- const singleTotalFallbackAmount = usesInvestScaleSingleTotal.value
- ? calcSingleTotalAmountFromRows(sourceRows as Array<{ amount?: unknown; isGroupRow?: unknown }>, htData?.totalAmount)
- : null
+ const useSummaryAmount = detailRows.value.length === 1 || isOnlyCostScaleService.value
+ const onlyCostScaleFallbackAmount = isOnlyCostScaleService.value
+ ? calcOnlyCostScaleAmountFromRows(sourceRows as Array<{ amount?: unknown; isGroupRow?: unknown }>, htData?.totalAmount)
+ : null
await restoreScaleColumnDefaults({
gridApi: gridApi.value,
rows: detailRows.value,
@@ -647,7 +942,7 @@ const restoreAmountColumnDefaults = async () => {
if (!row.hasCost) return null
if (useSummaryAmount) return getContractScaleProjectTotalsByRow(row, projectTotals).amount
const sourceRow = getContractScaleRowByMajor(row, sourceRowMap, sourceRowIdMap)
- return typeof sourceRow?.amount === 'number' ? sourceRow.amount : singleTotalFallbackAmount
+ return typeof sourceRow?.amount === 'number' ? sourceRow.amount : onlyCostScaleFallbackAmount
},
isSameValue: isSameNullableNumber,
applyValue: (row, nextValue) => {
@@ -698,58 +993,265 @@ const restoreMajorFactorColumnDefaults = async () => {
}
const columnDefs: Array | ColGroupDef> = [
- createScaleValueColumn({
- headerName: t('pricingScale.columns.investAmount'),
+ {
+ headerName: t('pricingScale.columns.name'),
+ field: 'majorName',
+ minWidth: 150,
+ flex: 1.5,
+ wrapText: true,
+ autoHeight: true,
+ cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
+ valueFormatter: params => {
+ if (params.node?.rowPinned) return ''
+ return params.value || ''
+ }
+ },
+ {
+ headerName: t('pricingScale.columns.base'),
field: 'amount',
- headerTooltip: t('pricingScale.tooltip.resetInvestAmount'),
- headerComponent: AgGridResetHeader,
- onReset: restoreAmountColumnDefaults,
- resetTitle: t('pricingScale.tooltip.resetInvestAmount'),
- minWidth: 90,
- flex: 2,
- isEditable: row => Boolean(row?.hasCost),
- emptyTextPredicate: (row, value) => Boolean(row?.hasCost) && (value == null || value === ''),
- valueParser: params => parseNumberOrNull(params.newValue, { precision: 3 }),
- valueFormatter: formatEditableMoney
- }),
- createScaleBenchmarkBudgetColumnGroup({
- getCheckedSplit: getCheckedBenchmarkBudgetSplitByAmount,
- createBudgetCellRendererWithCheck,
- getHeaderComponent: () => ScaleBudgetToggleHeader,
- getHeaderComponentParams: getBenchmarkBudgetHeaderParams
- }),
- createScaleBudgetFeeColumnGroup({
- headerComponent: AgGridResetHeader,
- restoreConsultCategoryFactorColumnDefaults,
- restoreMajorFactorColumnDefaults,
- parseNumberOrNull,
- getBudgetFee,
- aggFunc: decimalAggSum
- }),
- createScaleRemarkColumn()
+ minWidth: 120,
+ flex: 1,
+ editable: false,
+ wrapText: true,
+ autoHeight: true,
+ cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
+ valueFormatter: params => params.value || ''
+ },
+ {
+ headerName: t('pricingScale.columns.base2'),
+ field: 'base',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 130,
+ flex: 1,
+ editable: false,
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ },
+ valueFormatter: params => {
+ const value = params.value
+ if (value == null) return ''
+ return typeof value === 'number' ? value.toLocaleString() : String(value)
+ }
+ },
+ {
+ headerName: t('pricingScale.columns.formula'),
+ field: 'optionalFormula',
+ minWidth: 200,
+ flex: 1.5,
+ editable: false,
+ wrapText: true,
+ autoHeight: true,
+ cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
+ valueFormatter: params => params.value || ''
+ },
+ {
+ headerName: t('pricingScale.columns.calculationAmount'),
+ field: 'budgetFee',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 120,
+ flex: 1,
+ editable: false,
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ },
+ // valueFormatter: params => {
+ // const value = params.value
+ // if (value == null) return ''
+ // // 结果乘 10000 后格式化显示
+ // const scaledValue = typeof value === 'number' ? value * 10000 : null
+ // if (scaledValue == null) return ''
+ // return scaledValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
+ // }
+ },
+ {
+ headerName: '本计算取值',
+ marryChildren: true,
+ children: [
+ {
+ headerName: t('pricingScale.columns.workStageFactor'),
+ field: 'workStageFactor',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 80,
+ flex: 1,
+ editable: params => !params.node?.group && !params.node?.rowPinned,
+ cellClass: params =>
+ !params.node?.group && !params.node?.rowPinned
+ ? 'editable-cell-line'
+ : '',
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true,
+ 'editable-cell-empty': params =>
+ !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
+ },
+ valueParser: params => parseNumberOrNull(params.newValue, { precision: 3 }),
+ valueFormatter: (params) => {
+ if (params.node?.rowPinned === 'bottom') {
+ return '/'
+ }
+ return formatScaleEditableNumber(params)
+ }
+ },
+ {
+ headerName: t('pricingScale.columns.workRatio'),
+ field: 'workRatio',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 80,
+ flex: 1,
+ editable: params => !params.node?.group && !params.node?.rowPinned,
+ cellClass: params =>
+ !params.node?.group && !params.node?.rowPinned
+ ? 'editable-cell-line'
+ : '',
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true,
+ 'editable-cell-empty': params =>
+ !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
+ },
+ valueParser: params => parseNumberOrNull(params.newValue, { precision: 2 }),
+ valueFormatter: (params) => {
+ if (params.node?.rowPinned === 'bottom') {
+ return '/'
+ }
+ return formatScaleEditableNumber(params, 2)
+ }
+ },
+ {
+ headerName: t('pricingScale.columns.serviceFee'),
+ field: 'serviceFee',
+ colId: 'serviceFeeTotal',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 120,
+ flex: 1,
+ aggFunc: decimalAggSum,
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ },
+ /*valueGetter: (params) => {
+ // ✅ 使用字符串字面量作为字段名
+ const workStageFactorValue = params.data?.['workStageFactor'] ?? 0;
+ const workRatioValue = params.data?.['workRatio'] ?? 0;
+ const budgetFeeValue = params.data?.['budgetFee'] ?? 0;
+
+ const subtotal = workRatioValue * workStageFactorValue * budgetFeeValue;
+
+ if (params.node?.rowPinned === 'bottom') {
+ // 计算总计
+ const allRows = fallbackDetailRows.value;
+ const total = allRows.reduce((sum, row) => {
+ return sum + (
+ (row['workStageFactor'] as number || 0) *
+ (row['workRatio'] as number || 0) *
+ (row['budgetFee'] as number || 0)
+ );
+ }, 0);
+ return Math.round(total);
+ }
+
+ return Math.round(subtotal);
+ },*/
+ // valueGetter: params => (params.node?.rowPinned ? (params.data as any)?.serviceFee ?? null : getServiceFee(params.data)),
+ valueFormatter: formatScaleReadonlyMoney
+ }
+ ]
+ },
+ {
+ headerName: t('pricingScale.columns.remark'),
+ field: 'remark',
+ minWidth: 100,
+ flex: 1.2,
+ cellEditor: 'agLargeTextCellEditor',
+ wrapText: true,
+ autoHeight: true,
+ cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
+ editable: params => !params.node?.group && !params.node?.rowPinned,
+ valueFormatter: params => {
+ if (!params.node?.group && !params.node?.rowPinned && !params.value) return t('pricingScale.clickToInput')
+ return params.value || ''
+ },
+ cellClass: params => (!params.node?.group && !params.node?.rowPinned ? ' remark-wrap-cell' : ''),
+ cellClassRules: {
+ 'editable-cell-empty': params =>
+ !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
+ }
+ }
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))
-const autoGroupColumnDef: ColDef = createScaleAutoGroupColumn({
- totalLabel: totalLabel.value,
- idLabelMap,
- parseProjectIndexFromPathKey
-})
-
-
+const autoGroupColumnDef: ColDef = {
+ headerName: t('pricingScale.columns.number'),
+ minWidth: 80,
+ flex: 2,
+ wrapText: true,
+ autoHeight: true,
+ cellStyle: {
+ whiteSpace: 'normal',
+ lineHeight: '1.4'
+ },
+ // 不使用默认的分组渲染器,避免显示折叠箭头
+ cellRenderer: undefined,
+ colSpan: params => {
+ // 如果是固定行(小计行),跨越 2 列
+ if (params.node?.rowPinned || params.data?.id === 'pinned-total-row') {
+ return 2
+ }
+ return 1
+ },
+ valueFormatter: params => {
+ if (params.node?.rowPinned) {
+ return '小计'
+ }
+ const rowData = params.data as any
+ // 直接显示编码和名称
+ if (rowData?.majorCode) {
+ return `${rowData.majorCode}`
+ }
+ return params.value || ''
+ },
+ tooltipValueGetter: params => {
+ if (params.node?.rowPinned) return totalLabel.value
+ const rowData = params.data as any
+ if (rowData?.majorCode && rowData?.majorName) {
+ return `${rowData.majorCode} ${rowData.majorName}`
+ }
+ return params.value || ''
+ }
+}
+// const totalBudgetFee = computed(() => sumNullableBy(detailRows.value, row => getBudgetFee(row)))
+const totalBudgetFee = computed(() => sumNullableBy(detailRows.value, row => row.budgetFee))
const totalBudgetFeeBasic = computed(() => sumNullableBy(detailRows.value, row => getBudgetFeeSplit(row)?.basic))
const totalBudgetFeeOptional = computed(() => sumNullableBy(detailRows.value, row => getBudgetFeeSplit(row)?.optional))
-const totalBudgetFee = computed(() => sumNullableBy(detailRows.value, row => getBudgetFee(row)))
-const pinnedTopRowData = computed(() =>
- createPinnedTopRowData(
- createScalePinnedTotalRow({
- budgetFee: totalBudgetFee.value,
- budgetFeeBasic: totalBudgetFeeBasic.value,
- budgetFeeOptional: totalBudgetFeeOptional.value
- })
- )
-)
+const totalServiceFee = computed(() => sumNullableBy(detailRows.value, row => row.serviceFee))
+const pinnedTopRowData = computed(() => [
+ {
+ id: 'pinned-total-row',
+ groupCode: '',
+ groupName: '',
+ majorCode: '',
+ majorName: totalLabel.value,
+ base: '/',
+ hasCost: false,
+ hasArea: false,
+ amount: '/',
+ benchmarkBudget: null,
+ benchmarkBudgetBasic: null,
+ benchmarkBudgetOptional: null,
+ benchmarkBudgetBasicChecked: true,
+ benchmarkBudgetOptionalChecked: true,
+ basicFormula: '/',
+ optionalFormula: '/',
+ workStageFactor: '/',
+ workRatio: '/',
+ consultCategoryFactor: null,
+ majorFactor: null,
+ budgetFee: totalBudgetFee.value,
+ budgetFeeBasic: totalBudgetFeeBasic.value,
+ budgetFeeOptional: totalBudgetFeeOptional.value,
+ serviceFee: totalServiceFee.value,
+ remark: '',
+ path: ['TOTAL']
+ }
+])
const syncComputedValuesToDetailRows = () => {
recomputeScaleDetailRowsInPlace(detailRows.value, 'cost')
@@ -758,7 +1260,11 @@ const syncComputedValuesToDetailRows = () => {
const buildPersistDetailRows = () => detailRows.value.map(row => ({ ...row }))
const saveToIndexedDB = async (options?: { skipComputedSync?: boolean }) => {
- if (shouldSkipPersist()) return
+ const rows = fallbackDetailRows.value.map(row => ({ ...row, type: `${props.contractId}-investment` }))
+ const stats = await useDataStore().upsertBatch(rows)
+ console.log('💾 数据保存成功:', stats)
+
+ /*if (shouldSkipPersist()) return
try {
if (!options?.skipComputedSync) {
syncComputedValuesToDetailRows()
@@ -774,6 +1280,7 @@ const saveToIndexedDB = async (options?: { skipComputedSync?: boolean }) => {
payload,
{ force: true }
)
+ console.log(totalBudgetFee.value)
const synced = await syncPricingTotalToZxFw({
contractId: props.contractId,
serviceId: props.serviceId,
@@ -783,11 +1290,11 @@ const saveToIndexedDB = async (options?: { skipComputedSync?: boolean }) => {
if (!synced) return
} catch (error) {
console.error('saveToIndexedDB failed:', error)
- }
+ }*/
}
const syncLinkedFieldsFromContractAndFactors = async () => {
- if (detailRows.value.length === 0) return
+ /*if (detailRows.value.length === 0) return
const consultChangeState =
(zxFwPricingStore.keyedStates[HT_CONSULT_FACTOR_CHANGE_KEY.value]
?? kvStore.entries[HT_CONSULT_FACTOR_CHANGE_KEY.value]
@@ -831,19 +1338,19 @@ const syncLinkedFieldsFromContractAndFactors = async () => {
}
if (!changed) return
syncComputedValuesToDetailRows()
- await saveToIndexedDB({ skipComputedSync: true })
+ await saveToIndexedDB({ skipComputedSync: true })*/
}
const syncLinkedScaleValuesFromContract = async (changedRowIds?: string[]) => {
- if (detailRows.value.length === 0) return
+ /*if (detailRows.value.length === 0) return
const htData = await kvStore.getItem<{ detailRows: SourceRow[]; totalAmount?: number | null }>(HT_DB_KEY.value)
const sourceRows = Array.isArray(htData?.detailRows) ? htData.detailRows : []
const sourceRowMap = buildContractScaleMap(sourceRows)
const sourceRowIdMap = buildContractScaleIdMap(sourceRows)
const projectTotals = buildContractScaleProjectTotals(sourceRows, htData?.totalAmount)
- const useSummaryAmount = detailRows.value.length === 1 || usesInvestScaleSingleTotal.value
- const singleTotalFallbackAmount = usesInvestScaleSingleTotal.value
- ? calcSingleTotalAmountFromRows(sourceRows as Array<{ amount?: unknown; isGroupRow?: unknown }>, htData?.totalAmount)
+ const useSummaryAmount = detailRows.value.length === 1 || isOnlyCostScaleService.value
+ const onlyCostScaleFallbackAmount = isOnlyCostScaleService.value
+ ? calcOnlyCostScaleAmountFromRows(sourceRows as Array<{ amount?: unknown; isGroupRow?: unknown }>, htData?.totalAmount)
: null
const changedRowIdSet = changedRowIds?.length ? normalizeChangedScaleRowIds(changedRowIds) : null
@@ -857,7 +1364,7 @@ const syncLinkedScaleValuesFromContract = async (changedRowIds?: string[]) => {
const nextAmount = row.hasCost
? (useSummaryAmount
? getContractScaleProjectTotalsByRow(row, projectTotals).amount
- : (typeof sourceRow?.amount === 'number' ? sourceRow.amount : singleTotalFallbackAmount))
+ : (typeof sourceRow?.amount === 'number' ? sourceRow.amount : onlyCostScaleFallbackAmount))
: null
if (isSameNullableNumber(row.amount, nextAmount)) continue
row.amount = nextAmount
@@ -865,13 +1372,15 @@ const syncLinkedScaleValuesFromContract = async (changedRowIds?: string[]) => {
}
if (!changed) return
syncComputedValuesToDetailRows()
- await saveToIndexedDB({ skipComputedSync: true })
+ await saveToIndexedDB({ skipComputedSync: true })*/
}
const getRowId = (params: { data?: DetailRow }) => String(params.data?.id || '')
const detailGridOptions: GridOptions = {
...gridOptions,
- getRowId
+ getRowId,
+ groupDefaultExpanded: -1, // 默认全部展开所有分组
+ groupHideOpenParents: true // 隐藏已展开的父行(分组标题行)
}
const linkedSourceSignature = computed(() => JSON.stringify({
@@ -893,18 +1402,18 @@ const buildRowsFromImportDefaultSource = async (
targetProjectCount: number
): Promise => {
// 与“使用默认数据”同源:先强制刷新系数,再按合同卡片默认带出。
- await loadFactorDefaults()
+ /*await loadFactorDefaults()
const htData = await kvStore.getItem<{ detailRows: SourceRow[]; totalAmount?: number | null }>(HT_DB_KEY.value)
const hasContractRows = Array.isArray(htData?.detailRows) && htData.detailRows.length > 0
- if (usesInvestScaleSingleTotal.value) {
+ if (isOnlyCostScaleService.value) {
return hasContractRows
- ? buildInvestScaleSingleTotalRows(htData!.detailRows as any, {
+ ? buildOnlyCostScaleRows(htData!.detailRows as any, {
projectCount: targetProjectCount,
cloneFromProjectOne: true,
totalAmount: htData?.totalAmount ?? null,
preferSummaryAmountWhenSingleRow: true
})
- : buildInvestScaleSingleTotalRows(undefined, {
+ : buildOnlyCostScaleRows(undefined, {
projectCount: targetProjectCount,
totalAmount: htData?.totalAmount ?? null,
preferSummaryAmountWhenSingleRow: true
@@ -920,7 +1429,7 @@ const buildRowsFromImportDefaultSource = async (
...row,
consultCategoryFactor: getDefaultConsultCategoryFactor(),
majorFactor: getDefaultMajorFactorById(row.majorDictId || row.id)
- }))
+ }))*/
}
const readBaseIndustryCode = async () => {
@@ -929,8 +1438,8 @@ const readBaseIndustryCode = async () => {
}
const buildRowsFromStoredState = (rows: DetailRow[]) =>
- usesInvestScaleSingleTotal.value
- ? buildInvestScaleSingleTotalRows(rows as any, {
+ isOnlyCostScaleService.value
+ ? buildOnlyCostScaleRows(rows as any, {
projectCount: getTargetProjectCount(),
cloneFromProjectOne: true
})
@@ -940,8 +1449,8 @@ const buildRowsFromStoredState = (rows: DetailRow[]) =>
})
const buildEmptyRows = (targetProjectCount: number) =>
- usesInvestScaleSingleTotal.value
- ? buildInvestScaleSingleTotalRows(undefined, { projectCount: targetProjectCount })
+ isOnlyCostScaleService.value
+ ? buildOnlyCostScaleRows(undefined, { projectCount: targetProjectCount })
: buildDefaultRows(targetProjectCount)
const applyDetailRows = (rows: DetailRow[]) => {
@@ -1036,8 +1545,8 @@ const applyProjectCountChange = async (nextValue: unknown) => {
normalizeProjectCount,
inferProjectCountFromRows: rows => inferProjectCountFromRows(rows),
buildRowsForReducedCount: (rows, targetProjectCount) =>
- usesInvestScaleSingleTotal.value
- ? buildInvestScaleSingleTotalRows(rows as any, { projectCount: targetProjectCount })
+ isOnlyCostScaleService.value
+ ? buildOnlyCostScaleRows(rows as any, { projectCount: targetProjectCount })
: mergeWithDictRows(rows as any, { projectCount: targetProjectCount }),
buildRowsFromImportDefaultSource,
getRowKey: row => getScaleProjectMajorKeyFromRow(row),
@@ -1049,7 +1558,50 @@ const applyProjectCountChange = async (nextValue: unknown) => {
}
const loadFromIndexedDB = async () => {
- await loadPricingScalePaneRows({
+ await loadC0Amount()
+ try {
+ const investmentRows = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-investment`, operator: 'eq' }
+ ])
+
+ const detailRowsFromStore: DetailRow[] = investmentRows.map(row => ({
+ id: String(row.id || ''),
+ projectIndex: row.projectIndex != null ? Number(row.projectIndex) : undefined,
+ majorDictId: row.majorDictId != null ? String(row.majorDictId) : undefined,
+ groupCode: String(row.groupCode || ''),
+ groupName: String(row.groupName || ''),
+ majorCode: String(row.majorCode || ''),
+ majorName: String(row.majorName || ''),
+ hasCost: Boolean(row.hasCost),
+ hasArea: Boolean(row.hasArea),
+ amount: row.amount != null ? Number(row.amount) : null,
+ benchmarkBudget: row.benchmarkBudget != null ? Number(row.benchmarkBudget) : null,
+ benchmarkBudgetBasic: row.benchmarkBudgetBasic != null ? Number(row.benchmarkBudgetBasic) : null,
+ benchmarkBudgetOptional: row.benchmarkBudgetOptional != null ? Number(row.benchmarkBudgetOptional) : null,
+ benchmarkBudgetBasicChecked: Boolean(row.benchmarkBudgetBasicChecked),
+ benchmarkBudgetOptionalChecked: Boolean(row.benchmarkBudgetOptionalChecked),
+ basicFormula: row.basicFormula != null ? String(row.basicFormula) : null,
+ optionalFormula: row.optionalFormula != null ? String(row.optionalFormula) : null,
+ consultCategoryFactor: row.consultCategoryFactor != null ? Number(row.consultCategoryFactor) : null,
+ majorFactor: row.majorFactor != null ? Number(row.majorFactor) : null,
+ workStageFactor: row.workStageFactor,
+ workRatio: row.workRatio,
+ budgetFee: row.budgetFee != null ? Number(row.budgetFee) : null,
+ budgetFeeBasic: row.budgetFeeBasic != null ? Number(row.budgetFeeBasic) : null,
+ budgetFeeOptional: row.budgetFeeOptional != null ? Number(row.budgetFeeOptional) : null,
+ serviceFee: row.serviceFee != null ? Number(row.budgetFee * row.workRatio * row.workStageFactor) : 0,
+ remark: String(row.remark || ''),
+ path: Array.isArray(row.path) ? row.path : [],
+ base: String(row.base || '')
+ }))
+ fallbackDetailRows.value = await mergeWithDictRows(detailRowsFromStore)
+ console.log('✅ 转换后的 DetailRow 数据:', detailRowsFromStore)
+ } catch (error) {
+ console.error('loadFromIndexedDB error:', error)
+ // ✅ 出错时生成默认行
+ fallbackDetailRows.value = await buildDefaultRows()
+ }
+ /*await loadPricingScalePaneRows({
industry: {
readIndustryCode: readBaseIndustryCode,
setIndustryCode: code => {
@@ -1076,6 +1628,13 @@ const loadFromIndexedDB = async () => {
console.error('loadFromIndexedDB failed:', error)
}
})
+ // ✅ 简单方案:直接调用 syncComputedValuesToDetailRows 并刷新表格
+ if (gridApi.value && detailRows.value.length > 0) {
+ syncComputedValuesToDetailRows()
+ await nextTick()
+ gridApi.value.refreshCells({ force: true })
+ gridApi.value.redrawRows()
+ }*/
}
const importContractData = async () => {
@@ -1122,11 +1681,13 @@ const commitGridChanges = async (source: string) => {
}
const handleCellValueChanged = (event?: any) => {
- if (isBulkClipboardMutation) return
- void commitGridChanges('cell-value-changed')
+ recalculateServiceFees();
+ saveToIndexedDB();
+ // if (isBulkClipboardMutation) return
+ // void commitGridChanges('cell-value-changed')
}
-const handleBulkMutationStart = () => {
+/*const handleBulkMutationStart = () => {
isBulkClipboardMutation = true
}
@@ -1137,7 +1698,7 @@ const handleBulkMutationEnd = (event?: any) => {
const handleGridReady = (event: GridReadyEvent) => {
gridApi.value = event.api
-}
+}*/
usePricingPaneLifecycle({
gridApi,
@@ -1157,6 +1718,15 @@ watch(
void relabelDetailRowsFromDict()
}
)
+watch(
+ () => useDataStore().items,
+ async (newItems) => {
+ if (Object.keys(newItems).length > 0) {
+ loadFromIndexedDB();
+ }
+ },
+ { immediate: true, deep: true }
+)
const processCellForClipboard = (params: any) => {
if (Array.isArray(params.value)) {
return JSON.stringify(params.value); // 数组转字符串复制
@@ -1191,10 +1761,7 @@ const processCellFromClipboard = (params: any) => {
-
-
{{ t('pricingPane.investment.title') }}
- {{ t('pricingPane.investment.titleHint') }}
-
+
{{ t('pricingPane.investment.title') }}
{{ t('pricingPane.projectCount') }}
{
-
-
-
-
-
-
-
-
- {{ t('pricingPane.clearTitle') }}
-
- {{ t('pricingPane.investment.clearDesc') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('pricingPane.overrideTitle') }}
-
- {{ t('pricingPane.investment.overrideDesc') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/src/features/pricing/components/LandScalePricingPane.vue b/src/features/pricing/components/LandScalePricingPane.vue
index d52dbf0..15e910b 100644
--- a/src/features/pricing/components/LandScalePricingPane.vue
+++ b/src/features/pricing/components/LandScalePricingPane.vue
@@ -310,7 +310,7 @@ const buildDefaultRows = (projectCountValue = getTargetProjectCount()): DetailRo
consultCategoryFactor: null,
majorFactor: null,
workStageFactor: 1,
- workRatio: 1,
+ workRatio: 100,
budgetFee: null,
budgetFeeBasic: null,
budgetFeeOptional: null,
diff --git a/src/features/pricing/components/OtherService.vue b/src/features/pricing/components/OtherService.vue
new file mode 100644
index 0000000..d492274
--- /dev/null
+++ b/src/features/pricing/components/OtherService.vue
@@ -0,0 +1,1441 @@
+
+
+
+
+
+
+
+
{{ props.title || t('otherService.title') }}
+
+
+
+
+
+
{{ title || "费用明细" }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('htZxFw.dialog.resetTitle') }}
+
+ {{ t('htZxFw.dialog.resetDesc', { name: pendingClearServiceName }) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('htZxFw.dialog.deleteTitle') }}
+
+ {{ t('htZxFw.dialog.deleteDesc', { name: pendingDeleteServiceName }) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/features/pricing/components/WorkloadPricingPane.vue b/src/features/pricing/components/WorkloadPricingPane.vue
index 3e48d94..77dafd2 100644
--- a/src/features/pricing/components/WorkloadPricingPane.vue
+++ b/src/features/pricing/components/WorkloadPricingPane.vue
@@ -20,6 +20,7 @@ import MethodUnavailableNotice from '@/features/shared/components/MethodUnavaila
import { buildProjectScopedSessionKey } from '@/lib/pricingPersistControl'
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale';
+import {useDataStore} from "@/pinia/zx";
interface DetailRow {
id: string
@@ -30,9 +31,12 @@ interface DetailRow {
workload: number | null
basicFee: number | null
budgetBase: string
- budgetReferenceUnitPrice: string
+ budgetReferenceUnitPrice: string | number | null
budgetAdoptedUnitPrice: number | null
consultCategoryFactor: number | null
+ cLow: number | null
+ cMid: number | null
+ cHigh: number | null
serviceFee: number | null
remark: string
path: string[]
@@ -45,7 +49,7 @@ interface XmInfoState {
const props = defineProps<{
contractId: string,
-
+ contractName: string,
serviceId: string | number
}>()
const zxFwPricingStore = useZxFwPricingStore()
@@ -60,15 +64,28 @@ let factorDefaultsLoaded = false
const paneInstanceCreatedAt = Date.now()
const gridApi = ref
| null>(null)
+/**
+ * 获取服务对应的咨询服务分类因子
+ * @returns 咨询服务分类因子值,如果没有则返回 null
+ */
const getDefaultConsultCategoryFactor = () =>
consultCategoryFactorMap.value.get(String(props.serviceId)) ?? null
+/**
+ * 确保咨询服务分类因子默认值已加载
+ * 从合同段的咨询因子配置中加载,避免重复加载
+ */
const ensureFactorDefaultsLoaded = async () => {
if (factorDefaultsLoaded) return
consultCategoryFactorMap.value = await loadConsultCategoryFactorMap(HT_CONSULT_FACTOR_KEY.value)
factorDefaultsLoaded = true
}
+/**
+ * 检查是否应该跳过数据持久化
+ * 用于在清空操作后的短时间内避免旧数据回填
+ * @returns 是否应该跳过持久化
+ */
const shouldSkipPersist = () => {
const storageKey = buildProjectScopedSessionKey(PRICING_CLEAR_SKIP_PREFIX, DB_KEY.value)
const raw = sessionStorage.getItem(storageKey)
@@ -92,6 +109,11 @@ const shouldSkipPersist = () => {
return false
}
+/**
+ * 检查是否应该强制加载默认数据
+ * 用于在恢复默认操作后强制使用初始值
+ * @returns 是否应该强制加载默认数据
+ */
const shouldForceDefaultLoad = () => {
const storageKey = buildProjectScopedSessionKey(PRICING_FORCE_DEFAULT_PREFIX, DB_KEY.value)
const raw = sessionStorage.getItem(storageKey)
@@ -101,8 +123,12 @@ const shouldForceDefaultLoad = () => {
return Number.isFinite(forceUntil) && Date.now() <= forceUntil
}
+/**
+ * 获取当前服务工作量法的状态
+ * @returns 工作量法状态对象,包含明细行数据
+ */
const getMethodState = () =>
- zxFwPricingStore.getServicePricingMethodState(props.contractId, props.serviceId, 'workload')
+ zxFwPricingStore.getServicePricingMethodState(props.contractId, props.serviceId, 'serviceFee')
const detailRows = computed({
get: () => {
@@ -110,7 +136,7 @@ const detailRows = computed({
return Array.isArray(rows) ? rows : []
},
set: rows => {
- zxFwPricingStore.setServicePricingMethodState(props.contractId, props.serviceId, 'workload', {
+ zxFwPricingStore.setServicePricingMethodState(props.contractId, props.serviceId, 'serviceFee', {
detailRows: rows
})
}
@@ -127,9 +153,17 @@ type taskLite = {
maxPrice: number | null
minPrice: number | null
defPrice: number | null
+ midPrice: number | null
+ highPrice: number | null
desc: string | null
}
+/**
+ * 获取任务显示名称
+ * 根据当前语言环境返回中文或英文名称
+ * @param task 任务对象
+ * @returns 任务显示名称
+ */
const getTaskDisplayName = (task: taskLite | undefined) => {
if (!task) return ''
return String(locale.value).toLowerCase().startsWith('en')
@@ -137,6 +171,12 @@ const getTaskDisplayName = (task: taskLite | undefined) => {
: task.name
}
+/**
+ * 格式化任务参考单价
+ * 根据任务的最小/最大价格生成价格区间字符串
+ * @param task 任务对象
+ * @returns 格式化后的价格区间字符串(如 "100元-200元")
+ */
const formatTaskReferenceUnitPrice = (task: taskLite) => {
const unit = task.unit || ''
const hasMin = typeof task.minPrice === 'number' && Number.isFinite(task.minPrice)
@@ -147,8 +187,16 @@ const formatTaskReferenceUnitPrice = (task: taskLite) => {
return ''
}
+/**
+ * 获取当前服务对应的工作任务 ID 列表
+ * 从 taskList 中筛选出属于当前服务的任务,并按 ID 排序
+ * @returns 任务 ID 数组
+ */
const getSourceTaskIds = () => {
- const currentServiceId = Number(props.serviceId)
+ // 从 serviceId 中提取最后的数字部分,例如:ct-1776069559338-f621-zx-9 -> 9
+ const serviceIdStr = String(props.serviceId)
+ const match = serviceIdStr.match(/-(\d+)$/)
+ const currentServiceId = match ? Number(match[1]) : NaN
return Object.entries(taskList as Record)
.filter(([, task]) => Number(task.serviceID) === currentServiceId)
.map(([key]) => Number(key))
@@ -158,6 +206,11 @@ const getSourceTaskIds = () => {
const isWorkloadMethodApplicable = computed(() => getSourceTaskIds().length > 0)
+/**
+ * 构建默认明细行数据
+ * 根据当前服务的任务列表生成初始行数据
+ * @returns 默认明细行数组
+ */
const buildDefaultRows = (): DetailRow[] => {
const rows: DetailRow[] = []
const sourceTaskIds = getSourceTaskIds()
@@ -166,22 +219,24 @@ const buildDefaultRows = (): DetailRow[] => {
const task = (taskList as Record)[String(taskId)]
const taskCode = task?.code || task?.ref || ''
if (!taskCode || !task?.name) continue
- const rowId = `task-${taskId}-${order}`
+ const contractId = props.contractId;
+ const rowId = `${contractId}-task-${taskId}`
rows.push({
id: rowId,
taskCode,
taskName: getTaskDisplayName(task),
unit: task.unit || '',
conversion: typeof task.conversion === 'number' && Number.isFinite(task.conversion) ? task.conversion : null,
- workload: null,
+ workload: typeof task.midPrice === 'number' && Number.isFinite(task.midPrice) ? task.midPrice : null,
basicFee: null,
budgetBase: task.basicParam || '',
- budgetReferenceUnitPrice: formatTaskReferenceUnitPrice(task),
+ budgetReferenceUnitPrice: null,
budgetAdoptedUnitPrice:
typeof task.defPrice === 'number' && Number.isFinite(task.defPrice) ? task.defPrice : null,
- consultCategoryFactor: getDefaultConsultCategoryFactor(),
+ consultCategoryFactor: typeof task.highPrice === 'number' && Number.isFinite(task.highPrice) ? task.highPrice : null,
serviceFee: null,
remark: task.desc|| '',
+ type: 'task',
path: [rowId]
})
}
@@ -191,6 +246,12 @@ const buildDefaultRows = (): DetailRow[] => {
const isNoTaskRow = (row: DetailRow | undefined) => row?.id?.startsWith('task-none-') ?? false
+/**
+ * 合并数据库中的行数据与默认行数据
+ * 保留用户编辑的值(工作量、单价、因子等),缺失时使用默认值
+ * @param rowsFromDb 从数据库加载的行数据
+ * @returns 合并后的明细行数组
+ */
const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] => {
const dbValueMap = new Map()
for (const row of rowsFromDb || []) {
@@ -202,20 +263,38 @@ const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] =>
if (!fromDb) return row
const hasRemark = Object.prototype.hasOwnProperty.call(fromDb, 'remark')
const hasConsultCategoryFactor = Object.prototype.hasOwnProperty.call(fromDb, 'consultCategoryFactor')
+ // ✅ 计算 cLow 值
+ let cLowValue: number | null = null
+ let cMidValue: number | null = null
+ let cHighValue: number | null = null
+ const refPrice = fromDb.budgetReferenceUnitPrice
+ const lowPrice = row.budgetAdoptedUnitPrice
+ const midPrice = row.workload
+ const highPrice = row.consultCategoryFactor
+ cLowValue = refPrice * lowPrice
+ cMidValue = refPrice * midPrice
+ cHighValue = refPrice * highPrice
+ let serviceFee = cMidValue
+ if (fromDb.serviceFee != null && fromDb.serviceFee != 0) {
+ serviceFee = fromDb.serviceFee
+ }
return {
...row,
workload: typeof fromDb.workload === 'number' ? fromDb.workload : null,
basicFee: typeof fromDb.basicFee === 'number' ? fromDb.basicFee : null,
- budgetAdoptedUnitPrice:
- typeof fromDb.budgetAdoptedUnitPrice === 'number' ? fromDb.budgetAdoptedUnitPrice : null,
+ budgetReferenceUnitPrice: fromDb.budgetReferenceUnitPrice ?? row.budgetReferenceUnitPrice,
+ budgetAdoptedUnitPrice: 1, // 固定为 1
+ cLow: cLowValue,
+ cMid: cMidValue,
+ cHigh: cHighValue,
consultCategoryFactor:
typeof fromDb.consultCategoryFactor === 'number'
? fromDb.consultCategoryFactor
: hasConsultCategoryFactor
? null
: getDefaultConsultCategoryFactor(),
- serviceFee: typeof fromDb.serviceFee === 'number' ? fromDb.serviceFee : null,
+ serviceFee: serviceFee,
remark: typeof fromDb.remark === 'string' ? fromDb.remark : hasRemark ? '' : row.remark
}
})
@@ -227,6 +306,12 @@ const parseSanitizedNumberOrNull = (value: unknown) =>
const parseSanitizedAdoptedPriceOrNull = (value: unknown) =>
parseNumberOrNull(value, { sanitize: true, precision: 6 })
+/**
+ * 计算基础费用
+ * 公式:基础费用 = 采用单价 × 换算系数 × 工作量
+ * @param row 明细行数据
+ * @returns 基础费用(保留2位小数),如果数据不完整则返回 null
+ */
const calcBasicFee = (row: DetailRow | undefined) => {
if (!row || isNoTaskRow(row)) return null
const price = row.budgetAdoptedUnitPrice
@@ -245,6 +330,12 @@ const calcBasicFee = (row: DetailRow | undefined) => {
return roundTo(toDecimal(price).mul(conversion).mul(workload), 2)
}
+/**
+ * 计算服务费用
+ * 公式:服务费用 = 基础费用 × 咨询服务分类因子
+ * @param row 明细行数据
+ * @returns 服务费用(保留2位小数),如果数据不完整则返回 null
+ */
const calcServiceFee = (row: DetailRow | undefined) => {
if (!row || isNoTaskRow(row)) return null
const factor = row.consultCategoryFactor
@@ -259,6 +350,12 @@ const calcServiceFee = (row: DetailRow | undefined) => {
return roundTo(toDecimal(basicFee).mul(factor), 2)
}
+/**
+ * 格式化可编辑数字单元格
+ * 根据行类型和值状态返回相应的显示文本
+ * @param params AG Grid 单元格参数
+ * @returns 格式化后的显示文本
+ */
const formatEditableNumber = (params: any) => {
if (isNoTaskRow(params.data)) return t('workloadPricing.none')
if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
@@ -268,6 +365,12 @@ const formatEditableNumber = (params: any) => {
return formatThousandsFlexible(params.value, 3)
}
+/**
+ * 判断两行是否应该合并显示(按任务名称和预算基数)
+ * 用于 AG Grid 的 spanRows 功能,相同任务和预算基数的行合并显示
+ * @param params AG Grid 行比较参数
+ * @returns 是否应该合并
+ */
const spanRowsByTaskName = (params: any) => {
const rowA = params?.nodeA?.data as DetailRow | undefined
const rowB = params?.nodeB?.data as DetailRow | undefined
@@ -285,9 +388,6 @@ const columnDefs: ColDef[] = [
width: 120,
pinned: 'left',
colSpan: params => (params.node?.rowPinned ? 2 : 1),
- cellClassRules: {
- 'ag-summary-label-cell': params => Boolean(params.node?.rowPinned)
- },
valueFormatter: params => (params.node?.rowPinned ? t('workloadPricing.total') : params.value || '')
},
{
@@ -307,8 +407,7 @@ const columnDefs: ColDef[] = [
headerName: t('workloadPricing.columns.budgetBase'),
field: 'budgetBase',
minWidth: 150,
- autoHeight: true,
-
+ autoHeight: true,
width: 180,
colSpan: params => (params.node?.rowPinned ? 3 : 1),
spanRows: spanRowsByTaskName,
@@ -319,15 +418,16 @@ const columnDefs: ColDef[] = [
field: 'budgetReferenceUnitPrice',
minWidth: 170,
flex: 1,
- valueFormatter: params => params.value || ''
+ editable: params => !params.node?.group && !params.node?.rowPinned && !isNoTaskRow(params.data),
+ valueFormatter: formatEditableNumber
},
- {
+ /*{
headerName: t('workloadPricing.columns.budgetAdoptedUnitPrice'),
field: 'budgetAdoptedUnitPrice',
headerClass: 'ag-right-aligned-header',
minWidth: 170,
flex: 1,
- editable: params => !params.node?.group && !params.node?.rowPinned && !isNoTaskRow(params.data),
+ // editable: params => !params.node?.group && !params.node?.rowPinned && !isNoTaskRow(params.data),
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
cellClassRules: {
'ag-right-aligned-cell': () => true,
@@ -347,8 +447,58 @@ const columnDefs: ColDef[] = [
const unit = params.data?.unit || ''
return `${formatThousandsFlexible(params.value, 6)}${unit}`
}
+ },*/
+ {
+ headerName: t('workloadPricing.columns.budgetAdoptedUnitPrice'),
+ field: 'budgetAdoptedUnitPrice',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 170,
+ flex: 1,
+ // ❌ 移除 editable 或设置为 false
+ editable: false,
+ // ✅ 添加单元格样式
+ cellClass: 'ag-right-aligned-cell',
+ // ✅ 移除 cellClassRules 中的 editable-cell 相关规则
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ },
+ // ✅ 固定显示值为 1
+ valueFormatter: params => {
+ const unit = params.data?.unit || ''
+ return `1`
+ // return `1${unit}`
+ },
+ // ✅ 阻止任何编辑尝试
+ valueParser: () => 1,
+ // ✅ 禁用单元格编辑
+ cellEditor: undefined
},
{
+ headerName: t('workloadPricing.columns.workload'),
+ field: 'workload',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 170,
+ flex: 1,
+ // ❌ 移除 editable 或设置为 false
+ editable: false,
+ // ✅ 添加单元格样式
+ cellClass: 'ag-right-aligned-cell',
+ // ✅ 移除 cellClassRules 中的 editable-cell 相关规则
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ },
+ // ✅ 固定显示值为 1
+ valueFormatter: params => {
+ const unit = params.data?.unit || ''
+ return `2`
+ // return `1${unit}`
+ },
+ // ✅ 阻止任何编辑尝试
+ valueParser: () => 1,
+ // ✅ 禁用单元格编辑
+ cellEditor: undefined
+ },
+ /*{
headerName: t('workloadPricing.columns.workload'),
field: 'workload',
minWidth: 140,
@@ -367,8 +517,33 @@ const columnDefs: ColDef[] = [
aggFunc: decimalAggSum,
valueParser: params => parseSanitizedNumberOrNull(params.newValue),
valueFormatter: formatEditableNumber
- },
+ },*/
{
+ headerName: t('workloadPricing.columns.consultCategoryFactor'),
+ field: 'consultCategoryFactor',
+ headerClass: 'ag-right-aligned-header',
+ minWidth: 170,
+ flex: 1,
+ // ❌ 移除 editable 或设置为 false
+ editable: false,
+ // ✅ 添加单元格样式
+ cellClass: 'ag-right-aligned-cell',
+ // ✅ 移除 cellClassRules 中的 editable-cell 相关规则
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ },
+ // ✅ 固定显示值为 1
+ valueFormatter: params => {
+ const unit = params.data?.unit || ''
+ return `3`
+ // return `1${unit}`
+ },
+ // ✅ 阻止任何编辑尝试
+ valueParser: () => 1,
+ // ✅ 禁用单元格编辑
+ cellEditor: undefined
+ },
+ /*{
headerName: t('workloadPricing.columns.consultCategoryFactor'),
field: 'consultCategoryFactor',
width: 80,
@@ -387,6 +562,54 @@ const columnDefs: ColDef[] = [
},
valueParser: params => parseSanitizedNumberOrNull(params.newValue),
valueFormatter: formatEditableNumber
+ },*/
+ {
+ headerName: t('workloadPricing.columns.cLow'),
+ field: 'cLow',
+ width: 100,
+ minWidth: 70,
+ maxWidth: 120,
+ // ✅ 设置为不可编辑
+ editable: false,
+ // ✅ 只读样式
+ cellClass: 'ag-right-aligned-cell',
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ }/*,
+ valueParser: params => parseSanitizedNumberOrNull(params.newValue),
+ valueFormatter: formatEditableNumber*/
+ },
+ {
+ headerName: t('workloadPricing.columns.cMid'),
+ field: 'cMid',
+ width: 100,
+ minWidth: 70,
+ maxWidth: 120,
+ // ✅ 设置为不可编辑
+ editable: false,
+ // ✅ 只读样式
+ cellClass: 'ag-right-aligned-cell',
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ }/*,
+ valueParser: params => parseSanitizedNumberOrNull(params.newValue),
+ valueFormatter: formatEditableNumber*/
+ },
+ {
+ headerName: t('workloadPricing.columns.cHigh'),
+ field: 'cHigh',
+ width: 100,
+ minWidth: 70,
+ maxWidth: 120,
+ // ✅ 设置为不可编辑
+ editable: false,
+ // ✅ 只读样式
+ cellClass: 'ag-right-aligned-cell',
+ cellClassRules: {
+ 'ag-right-aligned-cell': () => true
+ }/*,
+ valueParser: params => parseSanitizedNumberOrNull(params.newValue),
+ valueFormatter: formatEditableNumber*/
},
{
headerName: t('workloadPricing.columns.serviceFee'),
@@ -394,17 +617,19 @@ const columnDefs: ColDef[] = [
headerClass: 'ag-right-aligned-header',
minWidth: 150,
flex: 1,
- editable: false,
+ editable: params => !params.node?.group && !params.node?.rowPinned && !isNoTaskRow(params.data),
+ cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
cellClassRules: {
- 'ag-right-aligned-cell': () => true
+ 'ag-right-aligned-cell': () => true,
+
+ 'editable-cell-empty': params =>
+ !params.node?.group &&
+ !params.node?.rowPinned &&
+ !isNoTaskRow(params.data) &&
+ (params.value == null || params.value === '')
},
- valueGetter: params => (params.node?.rowPinned ? params.data?.serviceFee ?? null : calcServiceFee(params.data)),
- aggFunc: decimalAggSum,
- valueFormatter: params => {
- if (isNoTaskRow(params.data)) return t('workloadPricing.none')
- if (params.value == null || params.value === '') return ''
- return formatThousandsFlexible(roundTo(params.value, 3), 3)
- }
+ valueParser: params => parseSanitizedNumberOrNull(params.newValue),
+ valueFormatter: formatEditableNumber
},
{
headerName: t('workloadPricing.columns.remark'),
@@ -433,7 +658,9 @@ const columnDefs: ColDef[] = [
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))
-const totalWorkload = computed(() => sumByNumber(detailRows.value, row => row.workload))
+const totalWorkload = computed(() => {
+ return 1;
+})
const totalBasicFee = computed(() => sumByNumber(detailRows.value, row => calcBasicFee(row)))
const totalServiceFee = computed(() => sumNullableBy(detailRows.value, row => calcServiceFee(row)))
const pinnedTopRowData = computed(() =>
@@ -457,44 +684,63 @@ const pinnedTopRowData = computed(() =>
+/**
+ * 构建用于持久化的明细行数据
+ * 计算并附加基础费用和服务费用字段
+ * @returns 包含计算字段的明细行数组
+ */
const buildPersistDetailRows = () =>
- detailRows.value.map(row => ({
- ...row,
- basicFee: calcBasicFee(row),
- serviceFee: calcServiceFee(row)
- }))
+ detailRows.value.map(row => ({
+ ...row,
+ basicFee: calcBasicFee(row),
+ serviceFee: row.serviceFee
+ }))
+
+/**
+ * 保存数据到 IndexedDB 并同步到 zxFw store
+ * 保存时机:单元格编辑、批量操作结束、组件失活/卸载时
+ * 同步工作量法的总服务费用到咨询服务汇总表
+ */
const saveToIndexedDB = async () => {
- if (!isWorkloadMethodApplicable.value) return
- if (shouldSkipPersist()) return
try {
- const payload = {
- detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows()))
- }
- zxFwPricingStore.setServicePricingMethodState(
+ const rows = detailRows.value.map(row => ({ ...row, type: `${props.contractId}-task`}))
+ const stats = await useDataStore().upsertBatch(rows)
+ console.log('💾 数据保存成功:', stats)
+ /*zxFwPricingStore.setServicePricingMethodState(
props.contractId,
props.serviceId,
- 'workload',
+ 'serviceFee',
payload,
{ force: true }
- )
- const synced = await syncPricingTotalToZxFw({
- contractId: props.contractId,
- serviceId: props.serviceId,
- field: 'workload',
- value: totalServiceFee.value
- })
- if (!synced) return
+ )*/
+ // const synced = await syncPricingTotalToZxFw({
+ // contractId: props.contractId,
+ // serviceId: props.serviceId,
+ // field: 'serviceFee',
+ // value: totalWorkload.value
+ // })
+ // if (!synced) return
} catch (error) {
console.error('saveToIndexedDB failed:', error)
}
}
+/**
+ * 判断两个可空数值是否相等(考虑精度)
+ * @param left 第一个数值
+ * @param right 第二个数值
+ * @returns 是否相等
+ */
const isSameNullableNumber = (left: number | null | undefined, right: number | null | undefined) => {
if (left == null && right == null) return true
if (left == null || right == null) return false
return roundTo(left, 6) === roundTo(right, 6)
}
+/**
+ * 从合同段同步咨询服务分类因子
+ * 当合同段的咨询因子配置变化时,更新当前工作量的因子默认值
+ */
const syncLinkedConsultFactorFromHt = async () => {
if (!isWorkloadMethodApplicable.value || detailRows.value.length === 0) return
consultCategoryFactorMap.value = await loadConsultCategoryFactorMap(HT_CONSULT_FACTOR_KEY.value)
@@ -520,23 +766,30 @@ const linkedConsultFactorSignature = computed(() => JSON.stringify({
?? null
}))
+/**
+ * 从 IndexedDB 加载工作量法数据
+ * 加载时机:组件挂载、激活、storageKey 变化时
+ * 优先加载历史数据,没有则使用默认数据
+ */
const loadFromIndexedDB = async () => {
try {
if (!isWorkloadMethodApplicable.value) {
detailRows.value = []
return
}
-
- await ensureFactorDefaultsLoaded()
+ const taskRows = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-task`, operator: 'eq' }
+ ])
+ /*await ensureFactorDefaultsLoaded()
if (shouldForceDefaultLoad()) {
detailRows.value = buildDefaultRows()
return
- }
+ }*/
- const data = await zxFwPricingStore.loadServicePricingMethodState(props.contractId, props.serviceId, 'workload')
- if (data) {
- detailRows.value = mergeWithDictRows(data.detailRows)
+ // const data = await zxFwPricingStore.loadServicePricingMethodState(props.contractId, props.serviceId, 'serviceFee')
+ if (taskRows) {
+ detailRows.value = mergeWithDictRows(taskRows)
return
}
@@ -547,6 +800,10 @@ const loadFromIndexedDB = async () => {
}
}
+/**
+ * 根据任务词典更新行标签
+ * 当语言切换或任务词典更新时,同步更新任务名称、单位等信息
+ */
const relabelRowsFromTaskDict = async () => {
if (!isWorkloadMethodApplicable.value || detailRows.value.length === 0) return
let changed = false
@@ -584,24 +841,46 @@ const relabelRowsFromTaskDict = async () => {
let isBulkClipboardMutation = false
+/**
+ * 提交网格变更并保存
+ * 在单元格编辑完成后调用,触发数据持久化
+ */
const commitGridChanges = () => {
void saveToIndexedDB()
}
+/**
+ * 处理单元格值变化事件
+ * 触发时机:用户编辑完单元格后
+ * 批量操作期间跳过,避免重复保存
+ */
const handleCellValueChanged = () => {
if (isBulkClipboardMutation) return
commitGridChanges()
}
+/**
+ * 处理批量粘贴/填充操作开始
+ * 设置标志位,避免在批量操作过程中频繁保存
+ */
const handleBulkMutationStart = () => {
isBulkClipboardMutation = true
}
+/**
+ * 处理批量粘贴/填充操作结束
+ * 清除标志位并保存所有变更
+ */
const handleBulkMutationEnd = () => {
isBulkClipboardMutation = false
commitGridChanges()
}
+/**
+ * AG Grid 初始化完成回调
+ * 记录 gridApi 实例,用于后续刷新单元格等操作
+ * @param event AG Grid 初始化事件
+ */
const handleGridReady = (event: GridReadyEvent) => {
gridApi.value = event.api
}
@@ -619,6 +898,21 @@ watch(
void relabelRowsFromTaskDict()
}
)
+watch(
+ () => useDataStore().items,
+ async (newItems) => {
+ if (Object.keys(newItems).length > 0) {
+ loadFromIndexedDB();
+ }
+ },
+ { immediate: true, deep: true }
+)
+/**
+ * 处理复制到剪贴板的单元格数据
+ * 将数组类型的数据转换为 JSON 字符串
+ * @param params AG Grid 剪贴板参数
+ * @returns 处理后的单元格值
+ */
const processCellForClipboard = (params: any) => {
if (Array.isArray(params.value)) {
return JSON.stringify(params.value); // 数组转字符串复制
@@ -626,6 +920,12 @@ const processCellForClipboard = (params: any) => {
return params.value;
};
+/**
+ * 处理从剪贴板粘贴的单元格数据
+ * 根据字段类型解析数值(单价、工作量、因子等)
+ * @param params AG Grid 剪贴板参数
+ * @returns 解析后的单元格值
+ */
const processCellFromClipboard = (params: any) => {
const field = String(params.column?.getColDef?.().field || '')
if (field === 'budgetAdoptedUnitPrice') {
@@ -668,7 +968,7 @@ const mydiyTheme = myTheme.withParams({
-
-import { computed, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'
-import { useI18n } from 'vue-i18n'
-import { AgGridVue } from 'ag-grid-vue3'
+import {computed, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch} from 'vue'
+import {useI18n} from 'vue-i18n'
+import {AgGridVue} from 'ag-grid-vue3'
import type {
ColDef,
ColGroupDef,
@@ -10,17 +10,24 @@ import type {
GridReadyEvent,
RowDataUpdatedEvent
} from 'ag-grid-community'
-import { expertList } from '@/sql'
-import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
-import { decimalAggSum, roundTo, sumByNumber, sumNullableNumbers, toDecimal } from '@/lib/decimal'
-import { formatThousandsFlexible } from '@/lib/numberFormat'
-import { parseNumberOrNull } from '@/lib/number'
-import { syncPricingTotalToZxFw, type ZxFwPricingField } from '@/lib/zxFwPricingSync'
-import { useZxFwPricingStore, type HtFeeMethodType, type ServicePricingMethod } from '@/pinia/zxFwPricing'
-import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
-import { buildProjectScopedSessionKey } from '@/lib/pricingPersistControl'
-import { withReadonlyAutoHeight } from '@/lib/agGridReadonlyAutoHeight'
-
+import {expertList} from '@/sql'
+import {myTheme, gridOptions, agGridWrapClass, agGridStyle} from '@/lib/diyAgGridOptions'
+import {decimalAggSum, roundTo, sumByNumber, sumNullableNumbers, toDecimal} from '@/lib/decimal'
+import {formatThousandsFlexible} from '@/lib/numberFormat'
+import {parseNumberOrNull} from '@/lib/number'
+import {syncPricingTotalToZxFw, type ZxFwPricingField} from '@/lib/zxFwPricingSync'
+import {useZxFwPricingStore, type HtFeeMethodType, type ServicePricingMethod} from '@/pinia/zxFwPricing'
+import {AG_GRID_LOCALE_CN} from '@ag-grid-community/locale'
+import {buildProjectScopedSessionKey} from '@/lib/pricingPersistControl'
+import {withReadonlyAutoHeight} from '@/lib/agGridReadonlyAutoHeight'
+import {formatScaleEditableNumber, formatScaleReadonlyMoney} from "@/lib/pricingScaleGrid";
+import {ValueParserParams, ValueFormatterParams} from 'ag-grid-community';
+import {useKvStore} from "@/pinia/kv";
+import {useDataStore} from '@/pinia/zx'
+/**
+ * 数据行接口定义
+ * 注意:此接口需与 columnDefs 中的字段保持一致
+ */
interface DetailRow {
id: string
expertCode: string
@@ -29,35 +36,55 @@ interface DetailRow {
compositeBudgetUnitPrice: string
adoptedBudgetUnitPrice: number | null
personnelCount: number | null
- workdayCount: number | null
- serviceBudget: number | null
+ workdayCount: number | string | null
+ serviceBudget: number | string | null
remark: string
path: string[]
+ // 新增:按职称分类的工时字段(与 columnDefs 对应)
+ unitPrice?: number | string | null
+ workdayCount1?: number | string | null
+ feeSubtotal?: number | string | null
+ unitPrice2?: number | string | null
+ workdayCount2?: number | string | null
+ feeSubtotal2?: number | string | null
+ unitPrice3?: number | string | null
+ workdayCount3?: number | string | null
+ feeSubtotal3?: number | string | null
+ unitPrice4?: number | string | null
+ workdayCount4?: number | string | null
+ feeSubtotal4?: number | string | null
+ unitPrice5?: number | string | null
+ workdayCount5?: number | string | null
+ feeSubtotal5?: number | string | null
+ workdayCount6?: number | string | null
+ feeSubtotal6?: number | string | null,
+ avgUnitPrice: number | string | null
}
interface GridState {
detailRows: DetailRow[]
}
+
const props = withDefaults(
- defineProps<{
- storageKey: string
- title?: string
- contractId?: string
- serviceId?: string | number
- enableZxFwSync?: boolean
- syncField?: ZxFwPricingField
- htMainStorageKey?: string
- htRowId?: string
- htMethodType?: HtFeeMethodType
- }>(),
- {
- title: undefined,
- enableZxFwSync: false,
- syncField: 'hourly'
- }
+ defineProps<{
+ storageKey: string
+ title?: string
+ contractId?: string
+ serviceId?: string | number
+ enableZxFwSync?: boolean
+ syncField?: ZxFwPricingField
+ htMainStorageKey?: string
+ htRowId?: string
+ htMethodType?: HtFeeMethodType
+ }>(),
+ {
+ title: undefined,
+ enableZxFwSync: false,
+ syncField: 'hourly'
+ }
)
const zxFwPricingStore = useZxFwPricingStore()
-const { t, locale } = useI18n()
+const {t, locale} = useI18n()
const PRICING_CLEAR_SKIP_PREFIX = 'pricing-clear-skip:'
const PRICING_FORCE_DEFAULT_PREFIX = 'pricing-force-default:'
@@ -105,10 +132,10 @@ const serviceMethod = computed(() => {
return null
})
const useServicePricingState = computed(
- () => Boolean(props.enableZxFwSync && props.contractId && props.serviceId != null && serviceMethod.value)
+ () => Boolean(props.enableZxFwSync && props.contractId && props.serviceId != null && serviceMethod.value)
)
const useHtMethodState = computed(
- () => Boolean(props.htMainStorageKey && props.htRowId && props.htMethodType)
+ () => Boolean(props.htMainStorageKey && props.htRowId && props.htMethodType)
)
const getServiceMethodState = () => {
if (!useServicePricingState.value || !serviceMethod.value) return null
@@ -117,41 +144,16 @@ const getServiceMethodState = () => {
const getHtMethodState = () => {
if (!useHtMethodState.value) return null
return zxFwPricingStore.getHtFeeMethodState(
- props.htMainStorageKey!,
- props.htRowId!,
- props.htMethodType!
+ props.htMainStorageKey!,
+ props.htRowId!,
+ props.htMethodType!
)
}
const detailRows = computed({
get: () => {
- if (useServicePricingState.value) {
- const rows = getServiceMethodState()?.detailRows
- return Array.isArray(rows) ? rows : []
- }
- if (useHtMethodState.value) {
- const rows = getHtMethodState()?.detailRows
- return Array.isArray(rows) ? rows : []
- }
return fallbackDetailRows.value
},
set: rows => {
- if (useServicePricingState.value && serviceMethod.value) {
- const currentState = getServiceMethodState()
- zxFwPricingStore.setServicePricingMethodState(props.contractId!, props.serviceId!, serviceMethod.value, {
- detailRows: rows,
- projectCount: currentState?.projectCount ?? null
- })
- return
- }
- if (useHtMethodState.value) {
- zxFwPricingStore.setHtFeeMethodState(
- props.htMainStorageKey!,
- props.htRowId!,
- props.htMethodType!,
- { detailRows: rows }
- )
- return
- }
fallbackDetailRows.value = rows
}
})
@@ -168,16 +170,16 @@ type ExpertLite = {
const getExpertDisplayName = (expert: ExpertLite | undefined) => {
if (!expert) return ''
return String(locale.value).toLowerCase().startsWith('en')
- ? (expert as ExpertLite & { nameEn?: string }).nameEn || expert.name
- : expert.name
+ ? (expert as ExpertLite & { nameEn?: string }).nameEn || expert.name
+ : expert.name
}
const expertEntries = Object.entries(expertList as Record)
- .sort((a, b) => Number(a[0]) - Number(b[0]))
- .filter((entry): entry is [string, ExpertLite] => {
- const item = entry[1]
- return Boolean(item?.code && item?.name)
- })
+ .sort((a, b) => Number(a[0]) - Number(b[0]))
+ .filter((entry): entry is [string, ExpertLite] => {
+ const item = entry[1]
+ return Boolean(item?.code && item?.name)
+ })
const formatPriceRange = (min: number | null, max: number | null) => {
const hasMin = typeof min === 'number' && Number.isFinite(min)
@@ -191,34 +193,40 @@ const formatPriceRange = (min: number | null, max: number | null) => {
const getCompositeBudgetUnitPriceRange = (expert: ExpertLite) => {
if (typeof expert.manageCoe !== 'number' || !Number.isFinite(expert.manageCoe)) return ''
const min =
- typeof expert.minPrice === 'number' && Number.isFinite(expert.minPrice)
- ? roundTo(toDecimal(expert.minPrice).mul(expert.manageCoe), 2)
- : null
+ typeof expert.minPrice === 'number' && Number.isFinite(expert.minPrice)
+ ? roundTo(toDecimal(expert.minPrice).mul(expert.manageCoe), 2)
+ : null
const max =
- typeof expert.maxPrice === 'number' && Number.isFinite(expert.maxPrice)
- ? roundTo(toDecimal(expert.maxPrice).mul(expert.manageCoe), 2)
- : null
+ typeof expert.maxPrice === 'number' && Number.isFinite(expert.maxPrice)
+ ? roundTo(toDecimal(expert.maxPrice).mul(expert.manageCoe), 2)
+ : null
return formatPriceRange(min, max)
}
const getDefaultAdoptedBudgetUnitPrice = (expert: ExpertLite) => {
if (
- typeof expert.defPrice !== 'number' ||
- !Number.isFinite(expert.defPrice) ||
- typeof expert.manageCoe !== 'number' ||
- !Number.isFinite(expert.manageCoe)
+ typeof expert.defPrice !== 'number' ||
+ !Number.isFinite(expert.defPrice) ||
+ typeof expert.manageCoe !== 'number' ||
+ !Number.isFinite(expert.manageCoe)
) {
return null
}
return roundTo(toDecimal(expert.defPrice).mul(expert.manageCoe), 2)
}
-const buildDefaultRows = (): DetailRow[] => {
+const buildDefaultRows = async (): Promise => {
const rows: DetailRow[] = []
- for (const [expertId, expert] of expertEntries) {
- const rowId = `expert-${expertId}`
+ const rowsToMap = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-zxFw`, operator: 'eq' }
+ ])
+ for (const expert of rowsToMap) {
+ const expertId = expert.id || expert._id // 根据实际字段调整
+ const contractId = props.contractId
+ const rowId = `${contractId}-hourly-${expertId}`
rows.push({
id: rowId,
+ type: `${props.contractId}-hourly`,
expertCode: expert.code,
expertName: getExpertDisplayName(expert),
laborBudgetUnitPrice: formatPriceRange(expert.minPrice, expert.maxPrice),
@@ -234,30 +242,55 @@ const buildDefaultRows = (): DetailRow[] => {
return rows
}
-const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] => {
+/**
+ * 合并数据库中的行数据与默认行数据
+ * 保留用户编辑的所有字段值(包括新增的职称分类字段)
+ */
+const mergeWithDictRows = async (rowsFromDb: DetailRow[] | undefined): Promise => {
const dbValueMap = new Map()
for (const row of rowsFromDb || []) {
dbValueMap.set(row.id, row)
}
- return buildDefaultRows().map(row => {
+ const defaultRows = await buildDefaultRows()
+ return defaultRows.map(row => {
const fromDb = dbValueMap.get(row.id)
if (!fromDb) return row
+
+ // 使用展开运算符合并所有字段,确保新增字段也能正确合并
return {
...row,
- adoptedBudgetUnitPrice:
- typeof fromDb.adoptedBudgetUnitPrice === 'number' ? fromDb.adoptedBudgetUnitPrice : null,
+ // 保留数据库中的所有可编辑字段
+ adoptedBudgetUnitPrice: typeof fromDb.adoptedBudgetUnitPrice === 'number' ? fromDb.adoptedBudgetUnitPrice : null,
personnelCount: typeof fromDb.personnelCount === 'number' ? fromDb.personnelCount : null,
workdayCount: typeof fromDb.workdayCount === 'number' ? fromDb.workdayCount : null,
serviceBudget: typeof fromDb.serviceBudget === 'number' ? fromDb.serviceBudget : null,
- remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
+ remark: typeof fromDb.remark === 'string' ? fromDb.remark : '',
+ // 合并新增的职称分类字段
+ unitPrice: typeof fromDb.unitPrice === 'number' ? fromDb.unitPrice : null,
+ workdayCount1: typeof fromDb.workdayCount1 === 'number' ? fromDb.workdayCount1 : null,
+ feeSubtotal: typeof fromDb.feeSubtotal === 'number' ? fromDb.feeSubtotal : null,
+ unitPrice2: typeof fromDb.unitPrice2 === 'number' ? fromDb.unitPrice2 : null,
+ workdayCount2: typeof fromDb.workdayCount2 === 'number' ? fromDb.workdayCount2 : null,
+ feeSubtotal2: typeof fromDb.feeSubtotal2 === 'number' ? fromDb.feeSubtotal2 : null,
+ unitPrice3: typeof fromDb.unitPrice3 === 'number' ? fromDb.unitPrice3 : null,
+ workdayCount3: typeof fromDb.workdayCount3 === 'number' ? fromDb.workdayCount3 : null,
+ feeSubtotal3: typeof fromDb.feeSubtotal3 === 'number' ? fromDb.feeSubtotal3 : null,
+ unitPrice4: typeof fromDb.unitPrice4 === 'number' ? fromDb.unitPrice4 : null,
+ workdayCount4: typeof fromDb.workdayCount4 === 'number' ? fromDb.workdayCount4 : null,
+ feeSubtotal4: typeof fromDb.feeSubtotal4 === 'number' ? fromDb.feeSubtotal4 : null,
+ unitPrice5: typeof fromDb.unitPrice5 === 'number' ? fromDb.unitPrice5 : null,
+ workdayCount5: typeof fromDb.workdayCount5 === 'number' ? fromDb.workdayCount5 : null,
+ feeSubtotal5: typeof fromDb.feeSubtotal5 === 'number' ? fromDb.feeSubtotal5 : null,
+ feeSubtotal6: typeof fromDb.feeSubtotal6 === 'number' ? fromDb.feeSubtotal6 : null,
+ avgUnitPrice: typeof fromDb.avgUnitPrice === 'number' ? fromDb.avgUnitPrice : null,
}
})
}
const parseNonNegativeIntegerOrNull = (value: unknown) => {
if (value === '' || value == null) return null
- const parsed = parseNumberOrNull(value, { sanitize: true, precision: 0 })
+ const parsed = parseNumberOrNull(value, {sanitize: true, precision: 0})
if (parsed == null) return null
if (!Number.isSafeInteger(parsed) || parsed < 0) return null
return parsed
@@ -284,12 +317,12 @@ const calcServiceBudget = (row: DetailRow | undefined) => {
const personnel = row?.personnelCount
const workday = row?.workdayCount
if (
- typeof adopted !== 'number' ||
- !Number.isFinite(adopted) ||
- typeof personnel !== 'number' ||
- !Number.isFinite(personnel) ||
- typeof workday !== 'number' ||
- !Number.isFinite(workday)
+ typeof adopted !== 'number' ||
+ !Number.isFinite(adopted) ||
+ typeof personnel !== 'number' ||
+ !Number.isFinite(personnel) ||
+ typeof workday !== 'number' ||
+ !Number.isFinite(workday)
) {
return null
}
@@ -298,14 +331,265 @@ const calcServiceBudget = (row: DetailRow | undefined) => {
const syncServiceBudgetToRows = () => {
for (const row of detailRows.value) {
- row.serviceBudget = calcServiceBudget(row)
+ // row.serviceBudget = calcServiceBudget(row)
+
+ // 计算各职称的费用小计(单价 × 工日)
+ row.feeSubtotal = Math.round((row.unitPrice ?? 0) * (row.workdayCount ?? 0))
+ row.feeSubtotal2 = Math.round((row.unitPrice2 ?? 0) * (row.workdayCount2 ?? 0))
+ row.feeSubtotal3 = Math.round((row.unitPrice3 ?? 0) * (row.workdayCount3 ?? 0))
+ row.feeSubtotal4 = Math.round((row.unitPrice4 ?? 0) * (row.workdayCount4 ?? 0))
+ row.feeSubtotal5 = Math.round((row.unitPrice5 ?? 0) * (row.workdayCount5 ?? 0))
+
+ // 计算总工日
+ row.workdayCount6 = (row.workdayCount ?? 0) +
+ (row.workdayCount2 ?? 0) +
+ (row.workdayCount3 ?? 0) +
+ (row.workdayCount4 ?? 0) +
+ (row.workdayCount5 ?? 0)
+
+ // 计算总费用
+ row.feeSubtotal6 = Math.round(
+ (row.workdayCount ?? 0) * (row.unitPrice ?? 0) +
+ (row.workdayCount2 ?? 0) * (row.unitPrice2 ?? 0) +
+ (row.workdayCount3 ?? 0) * (row.unitPrice3 ?? 0) +
+ (row.workdayCount4 ?? 0) * (row.unitPrice4 ?? 0) +
+ (row.workdayCount5 ?? 0) * (row.unitPrice5 ?? 0)
+ )
+
+ // 计算平均单价
+ const totalWorkday = row.workdayCount6 ?? 0
+ const totalFee = row.feeSubtotal6 ?? 0
+ row.avgUnitPrice = Math.round(totalWorkday * totalFee)
+ }
+}
+
+function editableNumberCol2(
+ field: string,
+ headerName: string,
+ options: {
+ decimals?: 0 | 1; // 精度:0=整数,1=1位小数
+ aggFunc?: string;
+ } = {}
+): ColDef {
+ const {decimals = 0, aggFunc = 'sum'} = options;
+
+ /*const valueParser = (params: ValueParserParams) => {
+ const val = params.newValue?.trim();
+ if (!val) return null;
+ const num = parseFloat(val);
+ return isNaN(num) || num < 0 ? null : num;
+ };*/
+
+ const valueFormatter = (params: ValueFormatterParams) => {
+ if (params.node?.rowPinned === 'bottom') {
+ return '/';
+ }
+ const val = params.value;
+ if (val === null || val === undefined) return 0;
+ if (decimals === 0) {
+ return Math.round(val).toString(); // 强制整数显示
+ } else {
+ return Number(val).toFixed(1); // 保留1位小数
+ }
+ };
+
+ return {
+ field,
+ headerName,
+ editable: (params) => {
+ if (params.node?.rowPinned === 'bottom') {
+ return false;
+ } else {
+ return true;
+ }
+ },
+ cellDataType: 'number',
+ valueFormatter,
+ aggFunc,
+ };
+}
+
+function editableNumberCol3(
+ field: string,
+ headerName: string,
+ options: {
+ decimals?: 0 | 1; // 精度:0=整数,1=1位小数
+ aggFunc?: string;
+ } = {}
+): ColDef {
+ const {decimals = 0, aggFunc = 'sum'} = options;
+
+ const valueParser = (params: ValueParserParams) => {
+ const val = params.newValue?.trim();
+ if (!val) return null;
+ const num = parseFloat(val);
+ return isNaN(num) || num < 0 ? null : num;
+ };
+
+ const valueFormatter = (params: ValueFormatterParams) => {
+ const val = params.value;
+ if (val === null || val === undefined) return 0;
+ if (decimals === 0) {
+ return Math.round(val).toString(); // 强制整数显示
+ } else {
+ return Number(val).toFixed(1); // 保留1位小数
+ }
+ };
+
+ return {
+ field,
+ headerName,
+ editable: (params) => {
+ if (params.node?.rowPinned === 'bottom') {
+ return false;
+ } else {
+ return true;
+ }
+ },
+ cellDataType: 'number',
+ valueParser,
+ valueFormatter,
+ aggFunc,
+ };
+}
+
+// 费用小计列(计算列,不可编辑)
+function calculatedFeeSubtotalCol(
+ field: string,
+ headerName: string,
+ unitPriceField: string = 'unitPrice',
+ workdayCountField: string = 'workdayCount'
+): ColDef {
+ return {
+ field,
+ headerName,
+ editable: false,
+ cellDataType: 'number',
+ valueGetter: (params) => {
+ const unitPrice = params.data?.[unitPriceField] ?? 0;
+ const workdayCount = params.data?.[workdayCountField] ?? 0;
+ const subtotal = unitPrice * workdayCount;
+ if (params.node?.rowPinned === 'bottom') {
+ // 总计行的特殊计算逻辑
+ // 例如:使用不同的计算方式或直接返回预计算的值
+ const allRows = fallbackDetailRows.value;
+ const total = allRows.reduce((sum, row) => {
+ return sum + ((row[unitPriceField as keyof DetailRow] as number || 0) *
+ (row[workdayCountField as keyof DetailRow] as number || 0));
+ }, 0);
+ return Math.round(total); // 显示为整数
+ }
+ return Math.round(subtotal); // 费用小计为整数
+ },
+ /*valueFormatter: (params: ValueFormatterParams) => {
+ const unitPrice = params.data?.[unitPriceField] ?? 0;
+ const workdayCount = params.data?.[workdayCountField] ?? 0;
+ const subtotal = unitPrice * workdayCount;
+ return Math.round(subtotal); // 显示为整数
+ },*/
+ aggFunc: 'sum'
+ };
+}
+
+function calculatedFeeSubtotalCol2(
+ field: string,
+ headerName: string,
+ unitPriceField: string = 'unitPrice',
+ workdayCountField: string = 'workdayCount'
+): ColDef {
+ return {
+ field,
+ headerName,
+ editable: false,
+ cellDataType: 'number',
+ valueGetter: (params) => {
+ const unitPrice = params.data?.[unitPriceField] ?? 0;
+ const workdayCount = params.data?.[workdayCountField] ?? 0;
+ const subtotal = unitPrice * workdayCount;
+ return Math.round(subtotal); // 费用小计为整数
+ },
+ valueFormatter: (params: ValueFormatterParams) => {
+ const allRows = fallbackDetailRows.value;
+ const total = allRows.reduce((sum, row) => {
+ return sum + ((row[unitPriceField as keyof DetailRow] as number || 0) *
+ (row[workdayCountField as keyof DetailRow] as number || 0));
+ }, 0);
+ return Math.round(total); // 显示为整数
+ },
+ aggFunc: 'sum'
+ };
+}
+
+function calculatedWorkdayTotalCol(
+ field: string,
+ headerName: string,
+ options: {
+ decimals?: 0 | 1; // 精度:0=整数,1=1位小数
+ aggFunc?: string;
+ }): ColDef {
+ const {decimals = 0, aggFunc = 'sum'} = options;
+ return {
+ field,
+ headerName,
+ editable: false,
+ cellDataType: 'number',
+ valueGetter: (params) => {
+ const workdayCount1 = params.data?.['workdayCount'] ?? 0;
+ const workdayCount2 = params.data?.['workdayCount2'] ?? 0;
+ const workdayCount3 = params.data?.['workdayCount3'] ?? 0;
+ const workdayCount4 = params.data?.['workdayCount4'] ?? 0;
+ const workdayCount5 = params.data?.['workdayCount5'] ?? 0;
+ const count = workdayCount1 + workdayCount2 + workdayCount3 + workdayCount4 + workdayCount5;
+ return count; // 费用小计为整数
+ },
+ valueFormatter: (params: ValueFormatterParams) => {
+ const val = params.value;
+ if (val === null || val === undefined) return '';
+ if (decimals === 0) {
+ return Math.round(val).toString(); // 强制整数显示
+ } else {
+ return Number(val).toFixed(1); // 保留1位小数
+ }
+ }
+ }
+}
+
+function calculatedAvgUnitPriceCol(
+ field: string,
+ headerName: string,
+ options: {
+ decimals?: 0 | 1; // 精度:0=整数,1=1位小数
+ aggFunc?: string;
+ }): ColDef {
+ const {decimals = 0, aggFunc = 'sum'} = options;
+ return {
+ field,
+ headerName,
+ editable: false,
+ cellDataType: 'number'
+ }
+}
+
+function calculatedSubTotalCol(
+ field: string,
+ headerName: string,
+ options: {
+ decimals?: 0 | 1; // 精度:0=整数,1=1位小数
+ aggFunc?: string;
+ }): ColDef {
+ const {decimals = 0, aggFunc = 'sum'} = options;
+ return {
+ field,
+ headerName,
+ editable: false,
+ cellDataType: 'number'
}
}
const editableNumberCol = (
- field: K,
- headerName: string,
- extra: Partial> = {}
+ field: K,
+ headerName: string,
+ extra: Partial> = {}
): ColDef => ({
headerName,
field,
@@ -314,19 +598,19 @@ const editableNumberCol = (
editable: params => !params.node?.group && !params.node?.rowPinned,
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
cellClassRules: {
- 'ag-right-aligned-cell':()=>true,
+ 'ag-right-aligned-cell': () => true,
'editable-cell-empty': params =>
- !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
+ !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
},
- valueParser: params => parseNumberOrNull(params.newValue, { precision: 3 }),
+ valueParser: params => parseNumberOrNull(params.newValue, {precision: 3}),
valueFormatter: formatEditableNumber,
...extra
})
const editableMoneyCol = (
- field: K,
- headerName: string,
- extra: Partial> = {}
+ field: K,
+ headerName: string,
+ extra: Partial> = {}
): ColDef => ({
headerName,
field,
@@ -335,17 +619,17 @@ const editableMoneyCol = (
flex: 1,
editable: params => !params.node?.group && !params.node?.rowPinned,
cellClass: params =>
- !params.node?.group && !params.node?.rowPinned
- ? 'editable-cell-line'
- : '',
+ !params.node?.group && !params.node?.rowPinned
+ ? 'editable-cell-line'
+ : '',
cellClassRules: {
'ag-right-aligned-cell': () => true,
'editable-cell-empty': params =>
- !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
+ !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
},
- valueParser: params => parseNumberOrNull(params.newValue, { precision: 3 }),
- valueFormatter: params => {
- if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
+ valueParser: params => parseNumberOrNull(params.newValue, {precision: 3}),
+ valueFormatter: params => {
+ if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
return t('hourlyFeeGrid.clickToInput')
}
if (params.value == null) return ''
@@ -355,9 +639,9 @@ const editableMoneyCol = (
})
const readonlyTextCol = (
- field: K,
- headerName: string,
- extra: Partial> = {}
+ field: K,
+ headerName: string,
+ extra: Partial> = {}
): ColDef => ({
headerName,
field,
@@ -376,10 +660,7 @@ const columnDefs: (ColDef | ColGroupDef)[] = [
width: 100,
pinned: 'left',
colSpan: params => (params.node?.rowPinned ? 2 : 1),
- cellClassRules: {
- 'ag-summary-label-cell': params => Boolean(params.node?.rowPinned)
- },
- valueFormatter: params => (params.node?.rowPinned ? t('hourlyFeeGrid.total') : params.value || '')
+ valueFormatter: params => (params.node?.rowPinned ? t('hourlyFeeGrid.total') : params.value || 0)
},
{
headerName: t('hourlyFeeGrid.columns.name'),
@@ -391,27 +672,87 @@ const columnDefs: (ColDef | ColGroupDef)[] = [
wrapText: true,
autoHeight: true,
cellClass: 'hourly-fee-name-cell',
- cellStyle: { whiteSpace: 'normal', lineHeight: '1.2' },
+ cellStyle: {whiteSpace: 'normal', lineHeight: '1.2'},
valueFormatter: params => (params.node?.rowPinned ? '' : params.value || '')
},
{
- headerName: t('hourlyFeeGrid.columns.referenceUnitPrice'),
+ headerName: t('hourlyFeeGrid.columns.technician'),
marryChildren: true,
children: [
- readonlyTextCol('laborBudgetUnitPrice', t('hourlyFeeGrid.columns.laborBudgetUnitPrice'), {
- colSpan: params => (params.node?.rowPinned ? 3 : 1),
- valueFormatter: params => (params.node?.rowPinned ? '' : params.value || '')
- }),
- readonlyTextCol('compositeBudgetUnitPrice', t('hourlyFeeGrid.columns.compositeBudgetUnitPrice'))
+ // 单价(元/工日)→ 整数,非必填
+ editableNumberCol2('unitPrice', t('hourlyFeeGrid.columns.unitPrice'), {decimals: 0}),
+ // 工日数量(工日)→ 1位小数,非必填
+ editableNumberCol3('workdayCount', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ // 费用小计(元)→ 计算列,整数
+ calculatedFeeSubtotalCol('feeSubtotal', '费用小计(元)', 'unitPrice', 'workdayCount')
]
},
- editableMoneyCol('adoptedBudgetUnitPrice', t('hourlyFeeGrid.columns.adoptedBudgetUnitPrice')),
+ {
+ headerName: t('hourlyFeeGrid.columns.assistantEngineer'),
+ marryChildren: true,
+ children: [
+ // 单价(元/工日)→ 整数,非必填
+ editableNumberCol2('unitPrice2', t('hourlyFeeGrid.columns.unitPrice'), {decimals: 0}),
+ // 工日数量(工日)→ 1位小数,非必填
+ editableNumberCol3('workdayCount2', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ // 费用小计(元)→ 计算列,整数
+ calculatedFeeSubtotalCol('feeSubtotal2', '费用小计(元)', 'unitPrice2', 'workdayCount2')
+ ]
+ },
+ {
+ headerName: t('hourlyFeeGrid.columns.midEngineer'),
+ marryChildren: true,
+ children: [
+ // 单价(元/工日)→ 整数,非必填
+ editableNumberCol2('unitPrice3', t('hourlyFeeGrid.columns.unitPrice'), {decimals: 0}),
+ // 工日数量(工日)→ 1位小数,非必填
+ editableNumberCol3('workdayCount3', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ // 费用小计(元)→ 计算列,整数
+ calculatedFeeSubtotalCol('feeSubtotal3', '费用小计(元)', 'unitPrice3', 'workdayCount3')
+ ]
+ },
+ {
+ headerName: t('hourlyFeeGrid.columns.seniorEngineer'),
+ marryChildren: true,
+ children: [
+ // 单价(元/工日)→ 整数,非必填
+ editableNumberCol2('unitPrice4', t('hourlyFeeGrid.columns.unitPrice'), {decimals: 0}),
+ // 工日数量(工日)→ 1位小数,非必填
+ editableNumberCol3('workdayCount4', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ // 费用小计(元)→ 计算列,整数
+ calculatedFeeSubtotalCol('feeSubtotal4', '费用小计(元)', 'unitPrice4', 'workdayCount4')
+ ]
+ },
+ {
+ headerName: t('hourlyFeeGrid.columns.profSeniorEngineer'),
+ marryChildren: true,
+ children: [
+ // 单价(元/工日)→ 整数,非必填
+ editableNumberCol2('unitPrice5', t('hourlyFeeGrid.columns.unitPrice'), {decimals: 0}),
+ // 工日数量(工日)→ 1位小数,非必填
+ editableNumberCol3('workdayCount5', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ // 费用小计(元)→ 计算列,整数
+ calculatedFeeSubtotalCol('feeSubtotal5', '费用小计(元)', 'unitPrice5', 'workdayCount5')
+ ]
+ },
+ {
+ headerName: t('hourlyFeeGrid.columns.total'),
+ marryChildren: true,
+ children: [
+ /*editableNumberCol2('workdayCount6', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ editableNumberCol2('subtotal6', t('hourlyFeeGrid.columns.subtotal'), {decimals: 0}),*/
+ calculatedWorkdayTotalCol('workdayCount6', t('hourlyFeeGrid.columns.workdayCount'), {decimals: 1}),
+ calculatedSubTotalCol('feeSubtotal6', t('hourlyFeeGrid.columns.subtotal'), {decimals: 0}),
+ calculatedAvgUnitPriceCol('avgUnitPrice', t('hourlyFeeGrid.columns.avgUnitPrice'), {decimals: 0})
+ ]
+ },
+ /*editableMoneyCol('adoptedBudgetUnitPrice', t('hourlyFeeGrid.columns.adoptedBudgetUnitPrice')),
editableNumberCol('personnelCount', t('hourlyFeeGrid.columns.personnelCount'), {
aggFunc: decimalAggSum,
valueParser: params => parseNonNegativeIntegerOrNull(params.newValue),
valueFormatter: formatEditableInteger
}),
- editableNumberCol('workdayCount', t('hourlyFeeGrid.columns.workdayCount'), { aggFunc: decimalAggSum }),
+ editableNumberCol('workdayCount', t('hourlyFeeGrid.columns.workdayCount'), {aggFunc: decimalAggSum}),
{
headerName: t('hourlyFeeGrid.columns.serviceBudget'),
field: 'serviceBudget',
@@ -428,7 +769,7 @@ const columnDefs: (ColDef | ColGroupDef)[] = [
if (params.value == null || params.value === '') return ''
return formatThousandsFlexible(params.value, 3)
}
- },
+ },*/
{
headerName: t('hourlyFeeGrid.columns.remark'),
field: 'remark',
@@ -437,7 +778,7 @@ const columnDefs: (ColDef | ColGroupDef)[] = [
cellEditor: 'agLargeTextCellEditor',
wrapText: true,
autoHeight: true,
- cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
+ cellStyle: {whiteSpace: 'normal', lineHeight: '1.4'},
editable: params => !params.node?.group && !params.node?.rowPinned,
valueFormatter: params => {
if (!params.node?.group && !params.node?.rowPinned && !params.value) return t('hourlyFeeGrid.clickToInput')
@@ -446,101 +787,147 @@ const columnDefs: (ColDef | ColGroupDef)[] = [
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? ' remark-wrap-cell' : ''),
cellClassRules: {
'editable-cell-empty': params =>
- !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
+ !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
}
}
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))
-const totalPersonnelCount = computed(() => sumByNumber(detailRows.value, row => row.personnelCount))
const totalWorkdayCount = computed(() => sumByNumber(detailRows.value, row => row.workdayCount))
+const totalWorkdayCount2 = computed(() => sumByNumber(detailRows.value, row => row.workdayCount2))
+const totalWorkdayCount3 = computed(() => sumByNumber(detailRows.value, row => row.workdayCount3))
+const totalWorkdayCount4 = computed(() => sumByNumber(detailRows.value, row => row.workdayCount4))
+const totalWorkdayCount5 = computed(() => sumByNumber(detailRows.value, row => row.workdayCount5))
+const totalFeeSubtotal = computed(() => {
+ return sumByNumber(detailRows.value, row => row.feeSubtotal)
+})
+const totalFeeSubtotal2 = computed(() => sumByNumber(detailRows.value, row => row.feeSubtotal2))
+const totalFeeSubtotal3 = computed(() => sumByNumber(detailRows.value, row => row.feeSubtotal3))
+const totalFeeSubtotal4 = computed(() => sumByNumber(detailRows.value, row => row.feeSubtotal4))
+const totalFeeSubtotal5 = computed(() => sumByNumber(detailRows.value, row => row.feeSubtotal5))
+const totalFeeSubtotal6 = computed(() => {
+ const allRows = fallbackDetailRows.value;
+ return allRows.reduce((sum, row) => {
+ const value = Number(row?.feeSubtotal6) || 0
+ return sum + value
+ }, 0);
+})
+const totalAvgUnitPrice = computed(() => sumByNumber(detailRows.value, row => row.avgUnitPrice))
+const totalPersonnelCount = computed(() => sumByNumber(detailRows.value, row => row.personnelCount))
const totalServiceBudget = computed(() => sumNullableNumbers(detailRows.value.map(row => calcServiceBudget(row))))
-const pinnedTopRowData = computed(() => [
- {
- id: 'pinned-total-row',
- expertCode: t('hourlyFeeGrid.total'),
- expertName: '',
- laborBudgetUnitPrice: '',
- compositeBudgetUnitPrice: '',
- adoptedBudgetUnitPrice: null,
- personnelCount: totalPersonnelCount.value,
- workdayCount: totalWorkdayCount.value,
- serviceBudget: totalServiceBudget.value,
- remark: '',
- path: ['TOTAL']
- }
-])
-
-const saveToIndexedDB = async () => {
- if (shouldSkipPersist()) return
- try {
- syncServiceBudgetToRows()
- const payload: GridState = {
- detailRows: JSON.parse(JSON.stringify(detailRows.value))
+const pinnedTopRowData = computed(() => {
+ const result = [
+ {
+ id: 'pinned-total-row',
+ expertCode: t('hourlyFeeGrid.total'),
+ expertName: '',
+ laborBudgetUnitPrice: '',
+ compositeBudgetUnitPrice: '',
+ adoptedBudgetUnitPrice: null,
+ // personnelCount: totalPersonnelCount.value,
+ unitPrice: '/',
+ workdayCount: totalWorkdayCount.value,
+ workdayCount2: totalWorkdayCount2.value,
+ workdayCount3: totalWorkdayCount3.value,
+ workdayCount4: totalWorkdayCount4.value,
+ workdayCount5: totalWorkdayCount5.value,
+ avgUnitPrice: totalAvgUnitPrice.value,
+ feeSubtotal2: totalFeeSubtotal2.value,
+ feeSubtotal3: totalFeeSubtotal3.value,
+ feeSubtotal4: totalFeeSubtotal4.value,
+ feeSubtotal5: totalFeeSubtotal5.value,
+ feeSubtotal6: totalFeeSubtotal6.value,
+ serviceBudget: totalServiceBudget.value,
+ remark: '',
+ path: ['TOTAL']
}
+ ]
- if (useServicePricingState.value && serviceMethod.value) {
- zxFwPricingStore.setServicePricingMethodState(
- props.contractId!,
- props.serviceId!,
- serviceMethod.value,
- payload,
- { force: true }
- )
- } else if (useHtMethodState.value) {
- zxFwPricingStore.setHtFeeMethodState(
- props.htMainStorageKey!,
- props.htRowId!,
- props.htMethodType!,
- payload,
- { force: true }
- )
- } else {
- zxFwPricingStore.setKeyState(props.storageKey, payload)
- }
+ return result
+})
- if (props.enableZxFwSync && props.contractId && props.serviceId != null) {
- const synced = await syncPricingTotalToZxFw({
- contractId: props.contractId,
- serviceId: props.serviceId,
- field: props.syncField,
- value: totalServiceBudget.value
- })
- if (!synced) return
- }
+/**
+ * 保存数据到 IndexedDB
+ * 保存时机:
+ * 1. 单元格值变化时(handleCellValueChanged)
+ * 2. 组件失活时(onDeactivated)- 切换页面
+ * 3. 组件卸载前(onBeforeUnmount)- 关闭页面
+ */
- } catch (error) {
- console.error('saveToIndexedDB failed:', error)
+const recalculateServiceFees = () => {
+ for (const row of fallbackDetailRows.value) {
+ row.workdayCount6 = row.workdayCount + row.workdayCount2 + row.workdayCount3 + row.workdayCount4 + row.workdayCount5
+ row.feeSubtotal6 = row.feeSubtotal + row.feeSubtotal2 + row.feeSubtotal3 + row.feeSubtotal4 + row.feeSubtotal5
+ row.avgUnitPrice = row.feeSubtotal6 * row.workdayCount6
}
}
+
+const saveToIndexedDB = async () => {
+ try {
+ // syncServiceBudgetToRows()
+ syncServiceBudgetToRows();
+ // ✅ 使用 upsertBatch:存在则更新,不存在则新增
+ const rows = detailRows.value.map(row => ({ ...row }))
+ const stats = await useDataStore().upsertBatch(rows)
+
+ console.log('💾 数据保存成功:', stats)
+ } catch (error) {
+ console.error('❌ saveToIndexedDB 失败:', error)
+ }
+}
+
+/**
+ * 从 IndexedDB 加载数据
+ * 加载时机:
+ * 1. 组件挂载时(onMounted)
+ * 2. 组件激活时(onActivated)- 切换回页面
+ * 3. storageKey 变化时(watch)
+ */
const loadFromIndexedDB = async () => {
try {
- if (shouldForceDefaultLoad()) {
- detailRows.value = buildDefaultRows()
- syncServiceBudgetToRows()
- return
- }
- const data = useServicePricingState.value && serviceMethod.value
- ? await zxFwPricingStore.loadServicePricingMethodState(props.contractId!, props.serviceId!, serviceMethod.value)
- : useHtMethodState.value
- ? await zxFwPricingStore.loadHtFeeMethodState(
- props.htMainStorageKey!,
- props.htRowId!,
- props.htMethodType!
- )
- : await zxFwPricingStore.loadKeyState(props.storageKey)
- if (data) {
- detailRows.value = mergeWithDictRows(data.detailRows)
- syncServiceBudgetToRows()
- return
- }
- detailRows.value = buildDefaultRows()
- syncServiceBudgetToRows()
+
+ // ✅ 查询 type 等于 'hourly' 的数据
+ const hourlyRows = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-hourly`, operator: 'eq' }
+ ])
+ // ✅ 将 DataItem[] 转换为 DetailRow[]
+ const detailRowsFromStore: DetailRow[] = hourlyRows.map(row => ({
+ id: String(row.id || ''),
+ expertCode: String(row.expertCode || ''),
+ expertName: String(row.expertName || ''),
+ laborBudgetUnitPrice: String(row.laborBudgetUnitPrice || ''),
+ compositeBudgetUnitPrice: String(row.compositeBudgetUnitPrice || ''),
+ adoptedBudgetUnitPrice: row.adoptedBudgetUnitPrice != null ? Number(row.adoptedBudgetUnitPrice) : null,
+ personnelCount: row.personnelCount != null ? Number(row.personnelCount) : null,
+ workdayCount: row.workdayCount != null ? Number(row.workdayCount) : null,
+ serviceBudget: row.serviceBudget != null ? Number(row.serviceBudget) : null,
+ remark: String(row.remark || ''),
+ path: Array.isArray(row.path) ? row.path : [],
+ unitPrice: row.unitPrice != null ? Number(row.unitPrice) : null,
+ workdayCount1: row.workdayCount1 != null ? Number(row.workdayCount1) : null,
+ feeSubtotal: row.feeSubtotal != null ? Number(row.feeSubtotal) : null,
+ unitPrice2: row.unitPrice2 != null ? Number(row.unitPrice2) : null,
+ workdayCount2: row.workdayCount2 != null ? Number(row.workdayCount2) : null,
+ feeSubtotal2: row.feeSubtotal2 != null ? Number(row.feeSubtotal2) : null,
+ unitPrice3: row.unitPrice3 != null ? Number(row.unitPrice3) : null,
+ workdayCount3: row.workdayCount3 != null ? Number(row.workdayCount3) : null,
+ feeSubtotal3: row.feeSubtotal3 != null ? Number(row.feeSubtotal3) : null,
+ unitPrice4: row.unitPrice4 != null ? Number(row.unitPrice4) : null,
+ workdayCount4: row.workdayCount4 != null ? Number(row.workdayCount4) : null,
+ feeSubtotal4: row.feeSubtotal4 != null ? Number(row.feeSubtotal4) : null,
+ unitPrice5: row.unitPrice5 != null ? Number(row.unitPrice5) : null,
+ workdayCount5: row.workdayCount5 != null ? Number(row.workdayCount5) : null,
+ feeSubtotal5: row.feeSubtotal5 != null ? Number(row.feeSubtotal5) : null,
+ workdayCount6: row.workdayCount6 != null ? Number(row.workdayCount6) : null,
+ feeSubtotal6: row.feeSubtotal6 != null ? Number(row.feeSubtotal6) : null,
+ avgUnitPrice: row.avgUnitPrice != null ? Number(row.avgUnitPrice) : null
+ }))
+ fallbackDetailRows.value = await mergeWithDictRows(detailRowsFromStore)
+ console.log('✅ 转换后的 DetailRow 数据:', detailRowsFromStore)
+
} catch (error) {
- console.error('loadFromIndexedDB failed:', error)
- detailRows.value = buildDefaultRows()
- syncServiceBudgetToRows()
+ detailRows.value = await buildDefaultRows()
}
}
@@ -560,23 +947,36 @@ const relabelRowsFromExpertDict = async () => {
expertName: nextName
}
})
- gridApi.value?.refreshCells({ force: true })
+ gridApi.value?.refreshCells({force: true})
if (!changed) return
await saveToIndexedDB()
}
let isBulkClipboardMutation = false
+/**
+ * 提交网格变更:同步计算值、刷新UI、保存到数据库
+ * @param source 变更来源(用于日志追踪)
+ */
const commitGridChanges = (source: string) => {
+ console.log('🔄 提交网格变更:', source)
syncServiceBudgetToRows()
- gridApi.value?.refreshCells({ force: true })
+ gridApi.value?.refreshCells({force: true})
scheduleAutoRowHeights()
void saveToIndexedDB()
}
+/**
+ * 处理单元格值变化事件
+ * 触发时机:用户编辑完单元格后
+ */
const handleCellValueChanged = (event?: any) => {
- if (isBulkClipboardMutation) return
- commitGridChanges('cell-value-changed')
+ /*if (isBulkClipboardMutation) {
+ return
+ }
+
+ commitGridChanges('cell-value-changed')*/
+ saveToIndexedDB()
}
const handleBulkMutationStart = () => {
@@ -584,8 +984,8 @@ const handleBulkMutationStart = () => {
}
const handleBulkMutationEnd = (event?: any) => {
- isBulkClipboardMutation = false
- commitGridChanges(event?.type || 'bulk-end')
+ // isBulkClipboardMutation = false
+ // commitGridChanges(event?.type || 'bulk-end')
}
const handleGridReady = (event: GridReadyEvent) => {
@@ -595,14 +995,14 @@ const handleGridReady = (event: GridReadyEvent) => {
let autoHeightSyncTimer: ReturnType | null = null
const isGridApiAlive = (api: GridApi | null | undefined): api is GridApi =>
- Boolean(api && !api.isDestroyed?.())
+ Boolean(api && !api.isDestroyed?.())
const forceRefreshCellsOnLiveApi = () => {
// 再次触发一轮强制刷新,覆盖 AG Grid 异步布局后的高度计算。
setTimeout(() => {
const liveApi = gridApi.value
if (!isGridApiAlive(liveApi)) return
- liveApi.refreshCells({ force: true })
+ liveApi.refreshCells({force: true})
liveApi.redrawRows()
}, 16)
}
@@ -612,7 +1012,7 @@ const syncAutoRowHeights = async () => {
const api = gridApi.value
if (!isGridApiAlive(api)) return
api.onRowHeightChanged()
- api.refreshCells({ force: true })
+ api.refreshCells({force: true})
api.redrawRows()
forceRefreshCellsOnLiveApi()
}
@@ -652,7 +1052,7 @@ const processCellFromClipboard = (params: any) => {
return parseNonNegativeIntegerOrNull(params.value)
}
if (field === 'adoptedBudgetUnitPrice' || field === 'workdayCount') {
- return parseNumberOrNull(params.value, { precision: 3 })
+ return parseNumberOrNull(params.value, {precision: 3})
}
try {
const parsed = JSON.parse(params.value)
@@ -663,44 +1063,71 @@ const processCellFromClipboard = (params: any) => {
return params.value
}
+/**
+ * 组件挂载时加载数据
+ */
onMounted(async () => {
+ console.log('🚀 组件挂载')
await loadFromIndexedDB()
scheduleAutoRowHeights()
})
+/**
+ * 组件激活时重新加载数据(从其他页面切换回来时)
+ */
onActivated(async () => {
+ console.log('🔙 组件激活')
await loadFromIndexedDB()
scheduleAutoRowHeights()
})
watch(
- () => props.storageKey,
- () => {
- void loadFromIndexedDB()
- scheduleAutoRowHeights()
- }
+ () => useDataStore().items,
+ async (newItems) => {
+ if (Object.keys(newItems).length > 0) {
+ loadFromIndexedDB();
+ }
+ },
+ { immediate: true, deep: true }
)
watch(
- () => detailRows.value.length,
- () => {
- scheduleAutoRowHeights()
- }
+ () => props.storageKey,
+ () => {
+ void loadFromIndexedDB()
+ scheduleAutoRowHeights()
+ }
)
watch(
- () => locale.value,
- () => {
- void relabelRowsFromExpertDict()
- }
+ () => detailRows.value.length,
+ () => {
+ scheduleAutoRowHeights()
+ }
)
+watch(
+ () => locale.value,
+ () => {
+ void relabelRowsFromExpertDict()
+ }
+)
+
+/**
+ * 组件失活时保存数据(切换页面时触发)
+ * 配合 Vue 的 使用
+ */
onDeactivated(() => {
+ console.log('🔄 组件失活,保存数据')
gridApi.value?.stopEditing()
void saveToIndexedDB()
})
+/**
+ * 组件卸载前保存数据(关闭页面时触发)
+ */
onBeforeUnmount(() => {
+ console.log('💔 组件卸载,保存数据')
gridApi.value?.stopEditing()
gridApi.value = null
if (autoHeightSyncTimer) {
@@ -721,35 +1148,35 @@ onBeforeUnmount(() => {
diff --git a/src/features/shared/components/HtFeeGrid.vue b/src/features/shared/components/HtFeeGrid.vue
index c4e2b88..11b27a7 100644
--- a/src/features/shared/components/HtFeeGrid.vue
+++ b/src/features/shared/components/HtFeeGrid.vue
@@ -279,9 +279,6 @@ const columnDefs: ColDef[] = [
: typeof params.node?.rowIndex === 'number'
? params.node.rowIndex + 1
: '',
- cellClassRules: {
- 'ag-summary-label-cell': params => isSubtotalRow(params.data)
- },
colSpan: params => (isSubtotalRow(params.data) ? 2 : 1)
},
{
diff --git a/src/features/shared/components/HtFeeMethodGrid.vue b/src/features/shared/components/HtFeeMethodGrid.vue
index 99e2dae..780f336 100644
--- a/src/features/shared/components/HtFeeMethodGrid.vue
+++ b/src/features/shared/components/HtFeeMethodGrid.vue
@@ -375,12 +375,6 @@ const saveToIndexedDB = async (force = false) => {
const snapshot = JSON.stringify(payload.detailRows)
if (!force && snapshot === lastSavedSnapshot.value) return
zxFwPricingStore.setHtFeeMainState(props.storageKey, payload, { force })
- if (String(props.storageKey || '').includes('-additional-work')) {
- const contractId = String(props.contractId || '').trim()
- if (contractId) {
- await zxFwPricingStore.syncHtExtraFeeByContractBase(contractId)
- }
- }
lastSavedSnapshot.value = snapshot
} catch (error) {
console.error('saveToIndexedDB failed:', error)
@@ -504,7 +498,6 @@ const columnDefs: ColDef[] = [
? ''
: 'editable-cell-line',
cellClassRules: {
- 'ag-summary-label-cell': params => isSummaryRow(params.data),
'editable-cell-empty': params => params.value == null || params.value === ''
}
},
diff --git a/src/features/shared/components/ServiceCheckboxSelector.vue b/src/features/shared/components/ServiceCheckboxSelector.vue
index 6a6bcfa..402a533 100644
--- a/src/features/shared/components/ServiceCheckboxSelector.vue
+++ b/src/features/shared/components/ServiceCheckboxSelector.vue
@@ -1,5 +1,6 @@
+
+
+
+
+
+
+
+
+
+
+
+
{{ t('serviceSelector.empty') }}
diff --git a/src/features/shared/components/WorkContentGrid.vue b/src/features/shared/components/WorkContentGrid.vue
index dfc1df4..6b6ed83 100644
--- a/src/features/shared/components/WorkContentGrid.vue
+++ b/src/features/shared/components/WorkContentGrid.vue
@@ -31,6 +31,7 @@ import { getServiceDictItemById, getWorkListEntries, wholeProcessTasks } from '@
import { WorkType } from '@/sql'
import { useZxFwPricingStore } from '@/pinia/zxFwPricing'
import { useKvStore } from '@/pinia/kv'
+import { useDataStore } from '@/pinia/zx'
import { Trash2 } from 'lucide-vue-next'
interface WorkContentRow {
@@ -149,21 +150,136 @@ const loadProjectIndustryId = async () => {
const buildDefaultRowsFromDict = async (): Promise
=> {
const rows: WorkContentRow[] = []
- const entries = getWorkListEntries(locale.value) as Array<{ text: string; serviceid: number; order: number; type: number }>
+ const contentRows = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-content`, operator: 'eq' }
+ ])
+ let contentArray = [];
+ if (contentRows.length > 0) {
+ contentArray = contentRows[0].value;
+ }
+ const entries = getWorkListEntries(locale.value) as Array<{
+ text: string
+ serviceid: number
+ order: number
+ type: number
+ code: string
+ leaf?: boolean
+ textEn?: string
+ checked: boolean
+ custom: boolean
+ remark: string
+ }>;
- let filtered: typeof entries = []
+ // 根据 code 将 contentArray 里存在的数据替换到 entries 中
+ const contentMap = new Map()
+ if (Array.isArray(contentArray)) {
+ for (const item of contentArray) {
+ if (item?.code != null) {
+ contentMap.set(`${item.code}-${item.content}`, item)
+ }
+ }
+ }
+ for (let entry of entries) {
+ const item = contentMap.get(`${entry.code}-${entry.text}`)
+ if (item != null && `${entry.code}-${entry.text}` == `${item.code}-${item.content}`) {
+ entry.checked = item.checked
+ entry.custom = item.custom
+ entry.remark = item.remark
+ }
+ }
+
+ // 过滤数据
+ let filtered = [...entries]
+
+ // 按 order 排序
+ filtered.sort((a, b) => a.order - b.order)
+
+ // 构建 code -> 父节点信息的映射
+ const parentMap = new Map()
+
+ // 第一次遍历:收集所有 leaf: false 的父节点
+ let i = 1;
+ for (const entry of filtered) {
+ if (entry.leaf === false) {
+ /*const serviceItem = getServiceDictItemById(entry.serviceid) as { code?: string; name?: string } | undefined
+ const serviceGroup = serviceItem
+ ? `${String(serviceItem.code || '').trim()} ${String(serviceItem.name || '').trim()}`.trim()
+ : entry.code*/
+
+ parentMap.set(entry.code, {
+ serviceGroup: `${entry.text}`,
+ content: String(entry.text || '').trim()
+ })
+ i++;
+ }
+ }
+ // 第二次遍历:处理 leaf: true 的子节点
+ for (const entry of filtered) {
+ // 只处理 leaf: true 的节点(子节点)
+ if (entry.leaf !== true) {
+ continue
+ }
+
+ const content = String(entry.text || '').trim()
+ if (!content) continue
+
+ const typeLabel = ((): WorkType => {
+ if (entry.type === 1) return t('workContent.type.optional') as WorkType
+ if (entry.type === 2) return t('workContent.type.daily') as WorkType
+ if (entry.type === 3) return t('workContent.type.special') as WorkType
+ if (entry.type === 4) return t('workContent.type.additional') as WorkType
+ return t('workContent.type.basic') as WorkType
+ })()
+
+ /*const serviceItem = getServiceDictItemById(entry.serviceid) as { code?: string; name?: string } | undefined
+ const serviceGroup = serviceItem
+ ? `${String(serviceItem.code || '').trim()} ${String(serviceItem.name || '').trim()}`.trim()
+ : entry.code*/
+
+ // 查找父节点
+ const parent = parentMap.get(entry.code)
+ const parentName = parent?.serviceGroup
+
+ // 构建 path: [父节点名称, 子节点内容]
+ const path = [parentName, content]
+
+ rows.push({
+ id: `dict-${entry.serviceid}-${entry.code}-${entry.order}` ||
+ `dict-${entry.serviceid}-${entry.content.substring(0, 8)}-${entry.order}`,
+ code: entry.code,
+ content,
+ type: typeLabel,
+ dictOrder: entry.order,
+ serviceGroup: parentName, // 保留 serviceGroup 用于显示
+ serviceid: toServiceId(entry.serviceid),
+ remark: entry.remark == null ? '' : entry.remark,
+ checked: entry.checked == null ? true : entry.checked,
+ custom: entry.custom == null ? false : entry.custom,
+ leaf: entry.leaf,
+ path // 使用 [父节点, 子节点] 的路径结构
+ })
+ }
+
+ return rows
+}
+
+const buildDefaultRowsFromDict2 = async (): Promise => {
+ const rows: WorkContentRow[] = []
+ const entries = getWorkListEntries(locale.value) as Array<{ text: string; serviceid: number; order: number; type: number }>
+ const filtered = [...entries]
+ /*let filtered: typeof entries = []
let groupedServiceIds: number[] = []
let groupedBy: 'fid' | 'sid' | null = null
let matchedWholeProcessGroup: { fid: number; industry: number; sid: number[] } | null = null
isWholeProcessGroupedMode.value = false
groupedServiceGroups.value = []
if (props.dictMode === 'service') {
- const sid = Number(props.serviceId)
+ const sid = Number(props.serviceId.split('-').pop())
const industryId = await loadProjectIndustryId()
const wholeProcessGroupByFid = wholeProcessTasks.find(
item => Number(item.fid) === sid && Number(item.industry) === industryId
)
-
+
const wholeProcessGroup = wholeProcessGroupByFid
groupedBy = wholeProcessGroupByFid ? 'fid' : null
if (wholeProcessGroup) {
@@ -204,7 +320,7 @@ const buildDefaultRowsFromDict = async (): Promise => {
})
} else {
filtered.sort((a, b) => a.order - b.order)
- }
+ }*/
for (const entry of filtered) {
const content = String(entry.text || '').trim()
@@ -263,20 +379,67 @@ const emitCheckedChange = () => {
emit('checkedChange', [...checkedIds.value])
}
-const saveToStore = () => {
- const payload: WorkContentState = {
+const saveToStore = async () => {
+ /*const payload: WorkContentState = {
detailRows: getPersistableRows(rowData.value).map(item => ({ ...item }))
}
zxFwPricingStore.setKeyState(props.storageKey, payload)
- emitCheckedChange()
+ emitCheckedChange()*/
+ const rows = { value: [...rowData.value], type: `${props.contractId}-content`, id: `${props.contractId}-content` }
+ const stats = await useDataStore().upsert(rows)
+ console.log('💾 数据保存成功:', rows)
}
const loadFromStore = async () => {
- const defaultRows =
- props.dictMode === 'none'
- ? []
- : await buildDefaultRowsFromDict()
- const state = await zxFwPricingStore.loadKeyState(props.storageKey)
+ // TODO 数据重新加载
+ let defaultRows = await buildDefaultRowsFromDict()
+ const zxRows = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-zxFw`, operator: 'eq' }
+ ])
+ const zxRowCodes = [
+ ...new Set(
+ zxRows
+ .map(row => row.code)
+ .filter(Boolean)
+ .flatMap(code => {
+ const mapping = {
+ 'D1': ['D3-1', 'D3-2', 'D3-3', 'D3-4', 'D3-6-1', 'D3-7', 'D4-6', 'D5-1'],
+ 'D2-1': ['D3-1', 'D3-2', 'D3-3'],
+ 'D2-2': ['D3-4', 'D3-5', 'D3-6'],
+ 'D3-1': ['D3-1'],
+ 'D3-2': ['D3-2'],
+ 'D3-3': ['D3-3'],
+ 'D3-4': ['D3-4'],
+ 'D3-6-1': ['D3-6-1'],
+ 'D3-7': ['D3-7'],
+ 'D4-6': ['D4-6'],
+ 'D5-1': ['D5-1']
+ }
+ return mapping[code] || []
+ })
+ ),
+ 'D0-1',
+ 'D0'
+ ]
+
+ // 过滤 defaultRows,只保留 code 在 zxRowCodes 中的行
+ rowData.value = defaultRows.filter(row =>
+ row.code && zxRowCodes.includes(row.code)
+ )
+
+
+ /*const contentRows = await useDataStore().query([
+ { field: 'type', value: `${props.contractId}-content`, operator: 'eq' }
+ ])
+ if (contentRows.length > 0) {
+ rowData.value = contentRows[0].value;
+ } else {
+
+ }*/
+ /*console.log(rowData.value)
+ console.log('zxRowCodes', zxRowCodes)*/
+
+ /*const state = await zxFwPricingStore.loadKeyState(props.storageKey)
if (Array.isArray(state?.detailRows) && state.detailRows.length > 0) {
const persistedRows = state.detailRows.map(item => ({
...item,
@@ -331,9 +494,9 @@ const loadFromStore = async () => {
} else {
rowData.value = withAddTriggerRows(defaultRows)
saveToStore()
- }
- emitCheckedChange()
- await syncGroupedRowsRender()
+ }*/
+ // emitCheckedChange()
+ // await syncGroupedRowsRender()
}
const handleCheckedToggle = (id: string, checked: boolean) => {
@@ -376,24 +539,11 @@ const groupRowRendererParams = computed
innerRenderer: (params: ICellRendererParams) => {
const wrapper = document.createElement('div')
wrapper.className = 'work-content-group-row'
- const checkbox = document.createElement('input')
- checkbox.type = 'checkbox'
- checkbox.className = 'work-content-group-check'
- const rows = getGroupCheckableRows(params.node)
- const checkedCount = rows.filter(item => item.checked).length
- checkbox.checked = rows.length > 0 && checkedCount === rows.length
- checkbox.indeterminate = checkedCount > 0 && checkedCount < rows.length
- checkbox.disabled = rows.length === 0
- checkbox.addEventListener('mousedown', event => event.stopPropagation())
- checkbox.addEventListener('click', event => event.stopPropagation())
- checkbox.addEventListener('change', event => {
- event.stopPropagation()
- handleGroupCheckedToggle(params.node, checkbox.checked)
- })
+ // 只渲染标签,不渲染复选框
const label = document.createElement('span')
label.className = 'work-content-group-label'
label.textContent = String(params.valueFormatted || params.value || params.node.key || '')
- wrapper.append(checkbox, label)
+ wrapper.appendChild(label)
return wrapper
}
}
@@ -416,30 +566,27 @@ const contentCellRenderer = (params: ICellRendererParams) => {
wrapper.appendChild(label)
return wrapper
}
- // 自定义行不显示 checkbox,直接显示文本;空时显示 placeholder
- if (data.custom) {
- const label = document.createElement('span')
- if (!data.content) {
- label.className = 'work-content-placeholder'
- label.textContent = t('workContent.clickToInputContent')
- } else {
- label.className = 'work-content-text'
- label.textContent = data.content
- }
- wrapper.appendChild(label)
- return wrapper
+
+ if (!isAddTriggerRow(data) && !data.custom) {
+ const checkbox = document.createElement('input')
+ checkbox.type = 'checkbox'
+ checkbox.checked = data.checked
+ checkbox.className = 'work-content-check'
+ checkbox.addEventListener('change', (event: Event) => {
+ const target = event.target as HTMLInputElement
+ handleCheckedToggle(data.id, target.checked)
+ })
+ wrapper.appendChild(checkbox)
}
- const checkbox = document.createElement('input')
- checkbox.type = 'checkbox'
- checkbox.className = 'work-content-check'
- checkbox.checked = Boolean(data.checked)
- checkbox.addEventListener('change', () => {
- handleCheckedToggle(data.id, checkbox.checked)
- })
+
const label = document.createElement('span')
- label.className = 'work-content-text'
- label.textContent = String(data.content || '')
- wrapper.appendChild(checkbox)
+ if (!data.content) {
+ label.className = 'work-content-placeholder'
+ label.textContent = t('workContent.clickToInputContent')
+ } else {
+ label.className = 'work-content-text'
+ label.textContent = data.content
+ }
wrapper.appendChild(label)
return wrapper
}
@@ -452,13 +599,45 @@ const columnDefs: ColDef[] = [
suppressMovable: true,
editable: false,
colSpan: params => (isAddTriggerRow(params.data) ? 5 : 1),
- valueGetter: params => {
+ /*valueGetter: params => {
if (!params.node || params.node.group || isAddTriggerRow(params.data)) return ''
if (!isWholeProcessGroupedMode.value) return (params.node.rowIndex ?? 0) + 1
const siblings = params.node.parent?.childrenAfterSort || []
const visibleLeafSiblings = siblings.filter(node => !node.group && !isAddTriggerRow(node.data as WorkContentRow))
const index = visibleLeafSiblings.findIndex(node => node.id === params.node?.id)
return index >= 0 ? index + 1 : ''
+ },*/
+ valueGetter: params => {
+ // 1. 添加触发行不显示序号
+ if (isAddTriggerRow(params.data)) return ''
+
+ // 2. 分组行(一级标题)处理
+ if (params.node.group) {
+ // 获取当前分组在所有分组中的索引
+ const allGroups = params.api.getRowNode(params.node.id)?.allChildren
+ ?.filter(node => node.group && !isAddTriggerRow(node.data))
+ const groupIndex = allGroups?.indexOf(params.node) + 1 || 1
+ return String(groupIndex)
+ }
+
+ // 3. 二级节点处理(叶子节点)
+ const parentNode = params.node.parent
+ if (!parentNode) return ''
+
+ // 获取父分组的序号
+ const parentGroupIndex = parentNode.allChildren
+ ?.filter(node => node.group && !isAddTriggerRow(node.data))
+ .indexOf(parentNode) + 1 || 1
+
+ // 获取当前节点在分组内的序号
+ const siblings = parentNode.childrenAfterSort || []
+ const visibleLeafSiblings = siblings.filter(node =>
+ !node.group && !isAddTriggerRow(node.data as WorkContentRow)
+ )
+ const childIndex = visibleLeafSiblings.findIndex(node => node.id === params.node?.id) + 1
+
+ return `${childIndex}`
+ // return `${parentGroupIndex}.${childIndex}`
},
cellRenderer: (params: ICellRendererParams) => {
const row = params.data
@@ -491,7 +670,7 @@ const columnDefs: ColDef[] = [
cellStyle: { whiteSpace: 'normal', lineHeight: '1.5' },
cellRenderer: contentCellRenderer
},
- {
+ /*{
headerName: t('workContent.columns.type'),
field: 'type',
minWidth: 100,
@@ -499,7 +678,7 @@ const columnDefs: ColDef[] = [
editable: false,
valueFormatter: (params: ValueFormatterParams) =>
isAddTriggerRow(params.data) ? '' : String(params.value || '')
- },
+ },*/
{
headerName: t('workContent.columns.remark'),
field: 'remark',
@@ -516,7 +695,7 @@ const columnDefs: ColDef[] = [
},
valueFormatter: params => (isAddTriggerRow(params.data) ? '' : (params.value || t('workContent.clickToInput')))
},
- {
+ /*{
headerName: t('workContent.columns.actions'),
colId: 'actions',
minWidth: 92,
@@ -556,7 +735,7 @@ const columnDefs: ColDef[] = [
}
}
})
- }
+ }*/
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))
@@ -579,7 +758,7 @@ const createAddTriggerRow = (groupName?: string): WorkContentRow => {
}
}
-const withAddTriggerRows = (rows: WorkContentRow[]) => {
+const withAddTriggerRows2 = (rows: WorkContentRow[]) => {
const pureRows = getPersistableRows(rows)
if (isWholeProcessGroupedMode.value) {
const groupedMap = new Map()
@@ -589,8 +768,8 @@ const withAddTriggerRows = (rows: WorkContentRow[]) => {
groupedMap.get(groupName)?.push(row)
}
const groupOrder = groupedServiceGroups.value.length
- ? [...groupedServiceGroups.value]
- : [...groupedMap.keys()]
+ ? [...groupedServiceGroups.value]
+ : [...groupedMap.keys()]
const result: WorkContentRow[] = []
const used = new Set()
for (const groupName of groupOrder) {
@@ -608,6 +787,11 @@ const withAddTriggerRows = (rows: WorkContentRow[]) => {
return [...pureRows, createAddTriggerRow()]
}
+const withAddTriggerRows = (rows: WorkContentRow[]) => {
+ const pureRows = getPersistableRows(rows)
+ return pureRows
+}
+
const getDataPath = (data: WorkContentRow) => {
const path = Array.isArray(data?.path)
? data.path.map(segment => String(segment || '').trim()).filter(Boolean)
@@ -685,11 +869,21 @@ watch(isWholeProcessGroupedMode, () => {
})
watch(
+ () => useDataStore().items,
+ async (newItems) => {
+ if (Object.keys(newItems).length > 0) {
+ loadFromStore();
+ }
+ },
+ { immediate: true, deep: true }
+)
+
+/*watch(
() => rowData.value.length,
() => {
void syncGroupedRowsRender()
}
-)
+)*/
watch(locale, () => {
void loadFromStore()
@@ -732,10 +926,10 @@ const confirmDeleteRow = () => {
:columnDefs="gridColumnDefs"
:theme="myTheme"
:getRowId="(params: { data: WorkContentRow }) => params.data.id"
- :treeData="isWholeProcessGroupedMode"
+ :treeData="true"
:getDataPath="getDataPath"
- :groupDefaultExpanded="isWholeProcessGroupedMode ? -1 : 0"
- :groupDisplayType="isWholeProcessGroupedMode ? 'groupRows' : undefined"
+ :groupDefaultExpanded="true ? -1 : 0"
+ :groupDisplayType="true ? 'groupRows' : undefined"
:groupRowRendererParams="groupRowRendererParams"
:animateRows="true"
:localeText="AG_GRID_LOCALE_CN"
@@ -824,6 +1018,11 @@ const confirmDeleteRow = () => {
gap: 8px;
}
+/* 隐藏一级分组行的复选框,但保留折叠箭头 */
+:deep(.ag-group-cell .ag-cell-value .ag-cell-wrapper > input[type='checkbox']) {
+ display: none !important;
+}
+
:deep(.work-content-group-check) {
width: 14px;
height: 14px;
diff --git a/src/features/shared/components/XmFactorGrid.vue b/src/features/shared/components/XmFactorGrid.vue
index cd5d9ba..ac04e4d 100644
--- a/src/features/shared/components/XmFactorGrid.vue
+++ b/src/features/shared/components/XmFactorGrid.vue
@@ -138,16 +138,6 @@ const hasMeaningfulFactorValue = (rows: SourceRow[] | undefined) =>
return hasBudgetValue || hasRemark
})
-const hasUsablePersistedRows = (state: GridState | null | undefined) =>
- Array.isArray(state?.detailRows) &&
- state.detailRows.some(row => {
- const hasFactor =
- typeof row?.budgetValue === 'number' ||
- typeof row?.standardFactor === 'number'
- const hasRemark = typeof row?.remark === 'string' && row.remark.trim() !== ''
- return hasFactor || hasRemark || String(row?.id || '').trim() !== ''
- })
-
const mergeWithDictRows = (rowsFromDb: SourceRow[] | undefined): FactorRow[] => {
const dbValueMap = new Map()
for (const row of rowsFromDb || []) {
@@ -318,7 +308,7 @@ const saveFactorChangeState = async (changedRowIds: string[]) => {
const loadGridState = async (storageKey: string): Promise => {
if (!storageKey) return null
const piniaData = await zxFwPricingStore.loadKeyState(storageKey)
- if (hasUsablePersistedRows(piniaData)) return piniaData
+ if (piniaData?.detailRows && Array.isArray(piniaData.detailRows)) return piniaData
// 兼容历史 kvStore 数据:命中后迁移到 pinia keyed state。
const legacyData = await kvStore.getItem(storageKey)
diff --git a/src/features/shared/components/xmCommonAgGrid.vue b/src/features/shared/components/xmCommonAgGrid.vue
index cf6abdf..5409c69 100644
--- a/src/features/shared/components/xmCommonAgGrid.vue
+++ b/src/features/shared/components/xmCommonAgGrid.vue
@@ -9,7 +9,7 @@ import { withReadonlyAutoHeight } from '@/lib/agGridReadonlyAutoHeight'
import { decimalAggSum, roundTo, sumByNumber } from '@/lib/decimal'
import { parseNumberOrNull } from '@/lib/number'
import { formatThousandsFlexible } from '@/lib/numberFormat'
-import { getIndustryDisplayName, getMajorDictEntries, isMajorIdInIndustryScope } from '@/sql'
+import { getIndustryDisplayName, getMajorDictEntries, isMajorIdInIndustryScope, xmProjectConfig } from '@/sql'
import { syncContractScaleToPricing, type ContractScaleSyncResult } from '@/lib/zxFwPricingSync'
import { SwitchRoot, SwitchThumb } from 'reka-ui'
import { useKvStore } from '@/pinia/kv'
@@ -22,8 +22,6 @@ import {
ToastViewport
} from 'reka-ui'
import { Button } from '@/components/ui/button'
-import { CircleHelp } from 'lucide-vue-next'
-import { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '@/components/ui/tooltip'
@@ -112,14 +110,35 @@ const buildDetailDict = (entries: Array<[string, MajorLite]>) => {
hasArea: item.hasArea !== false
})
}
-
- return groupOrder.map(code => groupMap.get(code)).filter((group): group is DictGroup => Boolean(group))
+ const result = groupOrder.map(code => groupMap.get(code)).filter((group): group is DictGroup => Boolean(group))
+ return result
}
const buildDefaultRows = (): DetailRow[] => {
const rows: DetailRow[] = []
+
+ // 1. 首先添加所有分组行(即使没有子项)
+ for (const group of detailDict.value) {
+ if (group.code != 'C0') {
+ rows.push({
+ id: group.id,
+ groupCode: group.code,
+ groupName: group.name,
+ majorCode: group.code,
+ majorName: group.name,
+ hasCost: true,
+ hasArea: true,
+ amount: null,
+ landArea: null,
+ path: [`${group.code} ${group.name}`],
+ isGroupRow: true,
+ hide: false
+ })
+ }
+ }
+
for (const group of detailDict.value) {
for (const child of group.children) {
@@ -326,25 +345,61 @@ interface ContractScaleChangeState {
updatedAt: number
}
+const XM_PROJECT_PHASE_KEY = 'xm-project-phase-v1'
+
+interface ProjectPhaseState {
+ feePhase?: string
+ feeStage?: string
+}
+
const props = defineProps<{
title: string
dbKey: string
xmInfoKey?: string | null
baseInfoKey?: string
- titleHint?: string
- titleHintAria?: string
}>()
let persistTimer: ReturnType | null = null
const gridApi = ref | null>(null)
const activeIndustryId = ref('')
-const totalLabel = computed(() => {
- const industryName = getIndustryDisplayName(activeIndustryId.value.trim(), locale.value)
- return industryName ? t('pricingScale.totalInvestmentByIndustry', { industryName }) : t('pricingScale.totalInvestment')
-})
+const totalLabel = ref(xmProjectConfig.pinnedTotalLabel)
const roughCalcEnabled = ref(false)
const visibleRowData = computed(() => { return detailRows.value.filter(row => !row.hide) })
+const feePhaseOptions = xmProjectConfig.feePhaseOptions
+const feeStageOptions = xmProjectConfig.feeStageOptions
+const feePhase = ref('')
+const feeStage = ref('')
+
+const loadPhaseState = async () => {
+ try {
+ const state = await kvStore.getItem(XM_PROJECT_PHASE_KEY)
+ if (state) {
+ feePhase.value = state.feePhase || ''
+ feeStage.value = state.feeStage || ''
+ }
+ } catch (error) {
+ console.error('load phase state failed:', error)
+ }
+}
+
+const savePhaseState = async () => {
+ try {
+ await kvStore.setItem(XM_PROJECT_PHASE_KEY, {
+ feePhase: feePhase.value,
+ feeStage: feeStage.value
+ })
+ } catch (error) {
+ console.error('save phase state failed:', error)
+ }
+}
+
+watch([feePhase, feeStage], () => {
+ void savePhaseState()
+})
+
+void loadPhaseState()
+
const refreshPinnedTotalLabelCell = () => {
if (!gridApi.value) return
const pinnedTopNode = gridApi.value.getPinnedTopRow(0)
@@ -398,34 +453,26 @@ const columnDefs: ColDef[] = [
}
},
{
- headerName: t('pricingScale.columns.landArea'),
- field: 'landArea',
+ headerName: '造价金额(元)',
+ field: 'amountYuan',
headerClass: 'ag-right-aligned-header',
- minWidth: 100,
+ minWidth: 120,
flex: 1,
- editable: params => !roughCalcEnabled.value && !params.node?.group && !params.node?.rowPinned && Boolean(params.data?.hasArea),
- cellClass: params =>
- !params.node?.group && !params.node?.rowPinned && params.data?.hasArea
- ? 'editable-cell-line'
- : '',
+ editable: false,
+ aggFunc: decimalAggSum,
+ valueGetter: params => params.data?.amount,
cellClassRules: {
- 'ag-right-aligned-cell': () => true,
- 'editable-cell-empty': params =>
- !params.node?.group && !params.node?.rowPinned && Boolean(params.data?.hasArea) && (params.value == null || params.value === '')
+ 'ag-right-aligned-cell': () => true
},
- valueParser: params => parseNumberOrNull(params.newValue, { precision: 3 }),
valueFormatter: params => {
if (roughCalcEnabled.value) {
return ''
}
- if (!params.node?.group && !params.node?.rowPinned && !params.data?.hasArea) {
+ const amount = params.value
+ if (typeof amount !== 'number' || !Number.isFinite(amount)) {
return ''
}
- if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
- return t('pricingScale.clickToInput')
- }
- if (params.value == null) return ''
- return formatThousandsFlexible(params.value, 3)
+ return formatThousandsFlexible(roundTo(amount * 10000, 0), 0)
}
}
]
@@ -435,9 +482,6 @@ const autoGroupColumnDef: ColDef = {
headerName: t('pricingScale.columns.majorGroup'),
minWidth: 200,
flex: 2,
- cellClassRules: {
- 'ag-summary-label-cell': params => Boolean(params.node?.rowPinned)
- },
cellRendererParams: {
suppressCount: true
},
@@ -763,24 +807,10 @@ onMounted(() => {