This commit is contained in:
wintsa 2026-02-24 17:14:01 +08:00
parent 6ba08da229
commit f121aa233e
13 changed files with 2559 additions and 128 deletions

View File

@ -1,14 +1,18 @@
{ {
"lockfileVersion": 1, "lockfileVersion": 1,
"configVersion": 1,
"workspaces": { "workspaces": {
"": { "": {
"name": "my-vue-app", "name": "my-vue-app",
"dependencies": { "dependencies": {
"@ag-grid-community/locale": "^35.1.0",
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"@vueuse/core": "^14.2.1", "@vueuse/core": "^14.2.1",
"ag-grid-community": "^35.1.0",
"ag-grid-enterprise": "^35.1.0",
"ag-grid-vue3": "^35.1.0",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"localforage": "^1.10.0",
"lucide-vue-next": "^0.563.0", "lucide-vue-next": "^0.563.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1", "pinia-plugin-persistedstate": "^4.7.1",
@ -16,6 +20,7 @@
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18", "tailwindcss": "^4.1.18",
"vue": "^3.5.25", "vue": "^3.5.25",
"vuedraggable": "^4.1.0",
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "latest", "@types/bun": "latest",
@ -30,6 +35,8 @@
}, },
}, },
"packages": { "packages": {
"@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", "", {}, "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", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
@ -186,6 +193,22 @@
"@vueuse/shared": ["@vueuse/shared@14.2.1", "", { "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", "", { "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-core": ["ag-charts-core@13.1.0", "", { "dependencies": { "ag-charts-types": "13.1.0" } }, "sha512-mLHJZ8oU5CPeLRURescdISCtMsiiA/m4d1iBr6aQBEgiTVogRMGpFpsYNtQiYtoW2sRh+62I9sN8fhC3JQjX/g=="],
"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-locale": ["ag-charts-locale@13.1.0", "", {}, "sha512-mPgJnVsOI4Cf17CAlRh8BvLz19e165sdQJeUXNaB7M+DPB+pxODOcfx4oqZlR4Wc8Zu++TGb/2ueHa/aeV2qeQ=="],
"ag-charts-types": ["ag-charts-types@13.1.0", "", {}, "sha512-DytRM3CXli+Y013SC1Mr8lQBrhVTACK+11ilDHOhwUM0sRpmGuR51XFGcBKOliW1Vas1AycP31Cm3Pp0jx3hqw=="],
"ag-grid-community": ["ag-grid-community@35.1.0", "", { "dependencies": { "ag-charts-types": "13.1.0" } }, "sha512-yWFQfRNjv3KUBkHHzFdDOYGjPcDMU0B8Up4qG651diFlGRUGEGVs94SK73niWvk1FDZdpV9oWrwq3f30/qAoVg=="],
"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=="],
"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=="],
"alien-signals": ["alien-signals@3.1.2", "", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="], "alien-signals": ["alien-signals@3.1.2", "", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="],
"aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
@ -220,10 +243,14 @@
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="],
"is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="], "is-what": ["is-what@5.5.0", "", {}, "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw=="],
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
"lie": ["lie@3.1.1", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw=="],
"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": ["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-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.31.1", "", { "os": "android", "cpu": "arm64" }, "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg=="],
@ -248,6 +275,8 @@
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="], "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.31.1", "", { "os": "win32", "cpu": "x64" }, "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw=="],
"localforage": ["localforage@1.10.0", "", { "dependencies": { "lie": "3.1.1" } }, "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg=="],
"lucide-vue-next": ["lucide-vue-next@0.563.0", "", { "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA=="], "lucide-vue-next": ["lucide-vue-next@0.563.0", "", { "peerDependencies": { "vue": ">=3.0.1" } }, "sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
@ -280,6 +309,8 @@
"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=="], "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=="],
"sortablejs": ["sortablejs@1.14.0", "", {}, "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="], "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="],
@ -312,6 +343,8 @@
"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=="], "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=="],
"vuedraggable": ["vuedraggable@4.1.0", "", { "dependencies": { "sortablejs": "1.14.0" }, "peerDependencies": { "vue": "^3.0.1" } }, "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww=="],
"@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/@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/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],

1870
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,26 +10,32 @@
"type-check": "bunx vue-tsc --noEmit" "type-check": "bunx vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@ag-grid-community/locale": "^35.1.0",
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"@vueuse/core": "^14.2.1", "@vueuse/core": "^14.2.1",
"ag-grid-community": "^35.1.0",
"ag-grid-enterprise": "^35.1.0",
"ag-grid-vue3": "^35.1.0",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"localforage": "^1.10.0",
"lucide-vue-next": "^0.563.0", "lucide-vue-next": "^0.563.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1", "pinia-plugin-persistedstate": "^4.7.1",
"reka-ui": "^2.8.0", "reka-ui": "^2.8.0",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.18", "tailwindcss": "^4.1.18",
"vue": "^3.5.25" "vue": "^3.5.25",
"vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "latest",
"@types/node": "^24.10.1", "@types/node": "^24.10.1",
"@vitejs/plugin-vue": "^6.0.2", "@vitejs/plugin-vue": "^6.0.2",
"@vue/tsconfig": "^0.8.1", "@vue/tsconfig": "^0.8.1",
"tw-animate-css": "^1.4.0", "tw-animate-css": "^1.4.0",
"typescript": "~5.9.3", "typescript": "~5.9.3",
"vite": "^8.0.0-beta.13", "vite": "^8.0.0-beta.13",
"vue-tsc": "^3.1.5", "vue-tsc": "^3.1.5"
"@types/bun": "latest"
} }
} }

View File

@ -3,7 +3,7 @@ import { ref } from 'vue'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import { Card, CardHeader, CardTitle } from '@/components/ui/card' import { Card, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { useTabStore } from '@/stores/tab' import { useTabStore } from '@/pinia/tab'
import { Plus, Trash2, Edit3, ExternalLink } from 'lucide-vue-next' import { Plus, Trash2, Edit3, ExternalLink } from 'lucide-vue-next'
const tabStore = useTabStore() const tabStore = useTabStore()

View File

@ -1,4 +1,22 @@
<template>1</template> <template>
<script> <TypeLine
// const typeLine=markRaw(defineAsyncComponent(() => import('@/layout/typeLine.vue'))) scene="xm-tab"
</script> title="项目配置"
storage-key="project-active-cat"
default-category="info"
:categories="xmCategories"
/>
</template>
<script setup lang="ts">
import { markRaw, defineAsyncComponent } from 'vue'
import TypeLine from '@/layout/typeLine.vue'
const xmView = markRaw(defineAsyncComponent(() => import('@/components/views/xmInfo.vue')))
const htView = markRaw(defineAsyncComponent(() => import('@/components/views/Ht.vue')))
const xmCategories = [
{ key: 'info', label: '分类信息', component: xmView },
{ key: 'contract', label: '合同段管理', component: htView }
]
</script>

View File

@ -1,32 +1,477 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { AgGridVue } from 'ag-grid-vue3'
import type { ColDef, GridOptions } from 'ag-grid-community'
import 'ag-grid-enterprise'
import {
themeQuartz
} from "ag-grid-community"
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale';
// 线+线
const borderConfig = {
style: "solid", // 线线 dotted solid
width: 0.5, //
color: "#e5e7eb" //
};
//
const myTheme = themeQuartz.withParams({
//
wrapperBorder: false,
//
headerBackgroundColor: "#f9fafb", // #e7f3fc
headerTextColor: "#374151", //
headerFontSize: 15, //
headerFontWeight: "normal", //
// //
rowBorder: borderConfig,
columnBorder: borderConfig,
headerRowBorder: borderConfig,
//
dataBackgroundColor: "#fefefe"
});
interface DictLeaf {
code: string
name: string
}
interface DictGroup {
code: string
name: string
children: DictLeaf[]
}
interface DetailRow {
id: string
groupCode: string
groupName: string
majorCode: string
majorName: string
amount: number | null
landArea: number | null
path: string[]
}
interface XmInfoState {
projectName: string
detailRows: DetailRow[]
}
const DB_NAME = 'jgjs-pricing-db'
const DB_STORE = 'form-state'
const DB_KEY = 'xm-info-v3'
const DEFAULT_PROJECT_NAME = 'xxx造价咨询服务'
const projectName = ref(DEFAULT_PROJECT_NAME)
const detailRows = ref<DetailRow[]>([])
const detailDict: DictGroup[] = [
{
code: 'E1',
name: '交通运输工程通用专业',
children: [
{ code: 'E1-1', name: '征地(用海)补偿' },
{ code: 'E1-2', name: '拆迁补偿' },
{ code: 'E1-3', name: '迁改工程' },
{ code: 'E1-4', name: '工程建设其他费' }
]
},
{
code: 'E2',
name: '公路工程专业',
children: [
{ code: 'E2-1', name: '临时工程' },
{ code: 'E2-2', name: '路基工程' },
{ code: 'E2-3', name: '路面工程' },
{ code: 'E2-4', name: '桥涵工程' },
{ code: 'E2-5', name: '隧道工程' },
{ code: 'E2-6', name: '交叉工程' },
{ code: 'E2-7', name: '机电工程' },
{ code: 'E2-8', name: '交通安全设施工程' },
{ code: 'E2-9', name: '绿化及环境保护工程' },
{ code: 'E2-10', name: '房建工程' }
]
},
{
code: 'E3',
name: '铁路工程专业',
children: [
{ code: 'E3-1', name: '大型临时设施和过渡工程' },
{ code: 'E3-2', name: '路基工程' },
{ code: 'E3-3', name: '桥涵工程' },
{ code: 'E3-4', name: '隧道及明洞工程' },
{ code: 'E3-5', name: '轨道工程' },
{ code: 'E3-6', name: '通信、信号、信息及灾害监测工程' },
{ code: 'E3-7', name: '电力及电力牵引供电工程' },
{ code: 'E3-8', name: '房建工程(房屋建筑及附属工程)' },
{ code: 'E3-9', name: '装饰装修工程' }
]
},
{
code: 'E4',
name: '水运工程专业',
children: [
{ code: 'E4-1', name: '临时工程' },
{ code: 'E4-2', name: '土建工程' },
{ code: 'E4-3', name: '机电与金属结构工程' },
{ code: 'E4-4', name: '设备工程' },
{ code: 'E4-5', name: '附属房建工程(房屋建筑及附属工程)' }
]
}
]
const codeNameMap = new Map<string, string>()
for (const group of detailDict) {
codeNameMap.set(group.code, group.name)
for (const child of group.children) {
codeNameMap.set(child.code, child.name)
}
}
const buildDefaultRows = (): DetailRow[] => {
const rows: DetailRow[] = []
for (const group of detailDict) {
for (const child of group.children) {
rows.push({
id: `row-${child.code}`,
groupCode: group.code,
groupName: group.name,
majorCode: child.code,
majorName: child.name,
amount: null,
landArea: null,
path: [group.code, child.code]
})
}
}
return rows
}
const mergeWithDictRows = (rowsFromDb: DetailRow[] | undefined): DetailRow[] => {
const dbValueMap = new Map<string, DetailRow>()
for (const row of rowsFromDb || []) {
dbValueMap.set(row.majorCode, row)
}
return buildDefaultRows().map(row => {
const fromDb = dbValueMap.get(row.majorCode)
if (!fromDb) return row
return {
...row,
amount: typeof fromDb.amount === 'number' ? fromDb.amount : null,
landArea: typeof fromDb.landArea === 'number' ? fromDb.landArea : null
}
})
}
const columnDefs: ColDef<DetailRow>[] = [
{
headerName: '造价金额(万元)',
field: 'amount',
minWidth: 170,
flex: 1, //
editable: params => !params.node?.group && !params.node?.rowPinned,
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
cellClassRules: {
'editable-cell-empty': params =>
!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
},
aggFunc: 'sum',
valueParser: params => {
if (params.newValue === '' || params.newValue == null) return null
const v = Number(params.newValue)
return Number.isFinite(v) ? v : null
},
valueFormatter: params => {
if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
return '点击输入'
}
if (params.value == null) return ''
return Number(params.value).toFixed(2)
}
},
{
headerName: '用地面积(亩)',
field: 'landArea',
minWidth: 170,
flex: 1, //
editable: params => !params.node?.group && !params.node?.rowPinned,
cellClass: params => (!params.node?.group && !params.node?.rowPinned ? 'editable-cell-line' : ''),
cellClassRules: {
'editable-cell-empty': params =>
!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
},
aggFunc: 'sum',
valueParser: params => {
if (params.newValue === '' || params.newValue == null) return null
const v = Number(params.newValue)
return Number.isFinite(v) ? v : null
},
valueFormatter: params => {
if (!params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')) {
return '点击输入'
}
if (params.value == null) return ''
return Number(params.value).toFixed(2)
}
}
]
const autoGroupColumnDef: ColDef = {
headerName: '专业编码以及工程专业名称',
minWidth: 320,
pinned: 'left',
flex:2, //
cellRendererParams: {
suppressCount: true
},
valueFormatter: params => {
if (params.node?.rowPinned) {
return '总合计'
}
const code = String(params.value || '')
const name = codeNameMap.get(code) || ''
return name ? `${code} ${name}` : code
}
}
const gridOptions: GridOptions<DetailRow> = {
treeData: true,
animateRows: true,
singleClickEdit: true,
suppressClickEdit: false,
suppressContextMenu: false,
groupDefaultExpanded: -1,
suppressFieldDotNotation: true,
getDataPath: data => data.path,
getContextMenuItems: () => ['copy', 'paste', 'separator', 'export'],
defaultColDef: {
resizable: true,
sortable: false,
filter: false
}
}
const totalAmount = computed(() =>
detailRows.value.reduce((sum, row) => sum + (row.amount || 0), 0)
)
const totalLandArea = computed(() =>
detailRows.value.reduce((sum, row) => sum + (row.landArea || 0), 0)
)
const pinnedTopRowData = computed(() => [
{
id: 'pinned-total-row',
groupCode: '',
groupName: '',
majorCode: '',
majorName: '',
amount: totalAmount.value,
landArea: totalLandArea.value,
path: ['TOTAL']
}
])
const openDB = () =>
new Promise<IDBDatabase>((resolve, reject) => {
const request = window.indexedDB.open(DB_NAME, 1)
request.onupgradeneeded = () => {
const db = request.result
if (!db.objectStoreNames.contains(DB_STORE)) {
db.createObjectStore(DB_STORE)
}
}
request.onsuccess = () => resolve(request.result)
request.onerror = () => reject(request.error)
})
const saveToIndexedDB = async () => {
try {
const db = await openDB()
const tx = db.transaction(DB_STORE, 'readwrite')
const store = tx.objectStore(DB_STORE)
const payload: XmInfoState = {
projectName: projectName.value,
detailRows: detailRows.value
}
store.put(payload, DB_KEY)
await new Promise<void>((resolve, reject) => {
tx.oncomplete = () => resolve()
tx.onerror = () => reject(tx.error)
tx.onabort = () => reject(tx.error)
})
db.close()
} catch (error) {
console.error('saveToIndexedDB failed:', error)
}
}
const loadFromIndexedDB = async () => {
try {
const db = await openDB()
const tx = db.transaction(DB_STORE, 'readonly')
const store = tx.objectStore(DB_STORE)
const request = store.get(DB_KEY)
const data = await new Promise<XmInfoState | undefined>((resolve, reject) => {
request.onsuccess = () => resolve(request.result as XmInfoState | undefined)
request.onerror = () => reject(request.error)
})
await new Promise<void>((resolve, reject) => {
tx.oncomplete = () => resolve()
tx.onerror = () => reject(tx.error)
tx.onabort = () => reject(tx.error)
})
db.close()
if (data) {
projectName.value = data.projectName || DEFAULT_PROJECT_NAME
detailRows.value = mergeWithDictRows(data.detailRows)
return
}
detailRows.value = buildDefaultRows()
} catch (error) {
console.error('loadFromIndexedDB failed:', error)
detailRows.value = buildDefaultRows()
}
}
let persistTimer: ReturnType<typeof setTimeout> | null = null
const schedulePersist = () => {
if (persistTimer) clearTimeout(persistTimer)
persistTimer = setTimeout(() => {
void saveToIndexedDB()
}, 250)
}
const handleBeforeUnload = () => {
void saveToIndexedDB()
}
const handleCellValueChanged = () => {
schedulePersist()
}
watch(projectName, schedulePersist)
onMounted(async () => {
await loadFromIndexedDB()
window.addEventListener('beforeunload', handleBeforeUnload)
})
onBeforeUnmount(() => {
window.removeEventListener('beforeunload', handleBeforeUnload)
if (persistTimer) clearTimeout(persistTimer)
void saveToIndexedDB()
})
const processCellForClipboard = (params:any) => {
if (Array.isArray(params.value)) {
return JSON.stringify(params.value); //
}
return params.value;
};
const processCellFromClipboard = (params:any) => {
try {
const parsed = JSON.parse(params.value);
if (Array.isArray(parsed)) return parsed;
} catch (e) {
//
}
return params.value;
};
</script>
<template> <template>
<div class="space-y-6"> <div class="space-y-6">
<div class="p-4 border rounded-lg bg-card shadow-sm"> <div class="rounded-lg border bg-card p-4 shadow-sm">
<label class="text-sm font-medium mb-2 block">项目名称</label> <label class="mb-2 block text-sm font-medium text-foreground">项目名称</label>
<Input placeholder="请输入项目名称" class="max-w-md" /> <input
v-model="projectName"
type="text"
placeholder="请输入项目名称"
class="h-10 w-full max-w-xl rounded-md border bg-background px-3 text-sm outline-none ring-offset-background transition focus-visible:ring-2 focus-visible:ring-ring"
/>
</div> </div>
<Table class="border rounded-md"> <div class="rounded-lg border bg-card xmMx">
<TableHeader> <div class="flex items-center justify-between border-b px-4 py-3">
<TableRow> <h3 class="text-sm font-semibold text-foreground">项目明细</h3>
<TableHead>专业编码</TableHead> <div class="text-xs text-muted-foreground">导入导出</div>
<TableHead>工程专业名称</TableHead> </div>
<TableHead>造价金额(万元)</TableHead>
<TableHead>用地面积()</TableHead> <div class="ag-theme-quartz h-[580px] w-full">
<TableHead class="text-right">操作</TableHead> <AgGridVue
</TableRow> :style="{ height: '100%' }"
</TableHeader> :rowData="detailRows"
<TableBody> :pinnedTopRowData="pinnedTopRowData"
<TableRow v-for="i in 3" :key="i"> :columnDefs="columnDefs"
<TableCell>010{{i}}</TableCell> :autoGroupColumnDef="autoGroupColumnDef"
<TableCell>土木工程建设</TableCell> :gridOptions="gridOptions"
<TableCell><Input type="number" class="h-8 w-24" value="1200" /></TableCell> :theme="myTheme"
<TableCell><Input type="number" class="h-8 w-24" value="50" /></TableCell> @cell-value-changed="handleCellValueChanged"
<TableCell class="text-right"> :suppressColumnVirtualisation="true"
<Button variant="ghost" size="sm" class="text-destructive">删除</Button> :suppressRowVirtualisation="true"
</TableCell> :cellSelection="{ handle: { mode: 'range' } }"
</TableRow> :enableClipboard="true"
</TableBody> :localeText="AG_GRID_LOCALE_CN"
</Table> :tooltipShowDelay="500"
<Button variant="outline" class="w-full border-dashed"><Plus class="mr-2 h-4 w-4" /> 新增专业行</Button> :headerHeight="50"
:processCellForClipboard="processCellForClipboard"
:processCellFromClipboard="processCellFromClipboard"
:undoRedoCellEditing="true"
:undoRedoCellEditingLimit="20"
/>
</div>
</div>
</div> </div>
</template> </template>
<style >
.ag-floating-top{
overflow-y:auto !important
}
.xmMx .editable-cell-line .ag-cell-value {
display: inline-block;
min-width: 84%;
padding: 2px 4px;
border-bottom: 1px solid #cbd5e1;
}
.xmMx .editable-cell-line.ag-cell-focus .ag-cell-value,
.xmMx .editable-cell-line:hover .ag-cell-value {
border-bottom-color: #2563eb;
}
.xmMx .editable-cell-empty .ag-cell-value {
color: #94a3b8 !important;
font-style: italic;
opacity: 1 !important;
}
.xmMx .ag-cell.editable-cell-empty,
.xmMx .ag-cell.editable-cell-empty .ag-cell-value {
color: #94a3b8 !important;
}
</style>

View File

@ -1,50 +1,105 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { computed, ref, watch, type Component } from 'vue'
import xmView from '@/components/views/xmInfo.vue' import { ScrollArea } from '@/components/ui/scroll-area'
// 使 sessionStorage interface TypeLineCategory {
const activeCategory = ref(sessionStorage.getItem('project-active-cat') || 'info') key: string
label: string
component: Component
}
const props = withDefaults(
defineProps<{
scene?: string
title?: string
categories: TypeLineCategory[]
storageKey?: string
defaultCategory?: string
}>(),
{
scene: 'default',
title: '配置',
storageKey: '',
defaultCategory: ''
}
)
const cacheKey = computed(() => props.storageKey || `type-line-active-cat-${props.scene}`)
const resolveInitialCategory = () => {
const defaultKey = props.defaultCategory || props.categories[0]?.key || ''
const savedKey = sessionStorage.getItem(cacheKey.value)
const validSavedKey = props.categories.some(item => item.key === savedKey)
return validSavedKey ? (savedKey as string) : defaultKey
}
const activeCategory = ref(resolveInitialCategory())
watch(
() => [props.categories, props.defaultCategory, cacheKey.value],
() => {
activeCategory.value = resolveInitialCategory()
},
{ deep: true }
)
const switchCategory = (cat: string) => { const switchCategory = (cat: string) => {
activeCategory.value = cat activeCategory.value = cat
sessionStorage.setItem('project-active-cat', cat) sessionStorage.setItem(cacheKey.value, cat)
} }
const activeComponent = computed(() => {
const selected = props.categories.find(item => item.key === activeCategory.value)
return selected?.component || props.categories[0]?.component || null
})
</script> </script>
<template> <template>
<div class="flex h-full w-full bg-background"> <div class="flex h-full w-full bg-background">
<div class="w-1/5 border-r p-6 flex flex-col gap-8 relative"> <div class="w-1/5 border-r p-6 flex flex-col gap-8 relative">
<div class="font-bold text-lg mb-4 text-primary">项目配置</div> <div class="font-bold text-lg mb-4 text-primary">{{ props.title }}</div>
<div class="flex flex-col gap-10 relative"> <div class="flex flex-col gap-10 relative">
<div class="absolute left-[11px] top-2 bottom-2 w-[2px] bg-muted"></div> <div class="absolute left-[11px] top-2 bottom-2 w-[2px] bg-muted"></div>
<div class="relative flex items-center gap-4 cursor-pointer group" @click="switchCategory('info')"> <div
<div :class="['z-10 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all', v-for="item in props.categories"
activeCategory === 'info' ? 'bg-primary border-primary scale-110' : 'bg-background border-muted-foreground']"> :key="item.key"
<div v-if="activeCategory === 'info'" class="w-2 h-2 bg-background rounded-full"></div> class="relative flex items-center gap-4 cursor-pointer group"
@click="switchCategory(item.key)"
>
<div
:class="[
'z-10 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all',
activeCategory === item.key
? 'bg-primary border-primary scale-110'
: 'bg-background border-muted-foreground'
]"
>
<div v-if="activeCategory === item.key" class="w-2 h-2 bg-background rounded-full"></div>
</div> </div>
<span :class="['text-sm transition-colors', activeCategory === 'info' ? 'font-bold text-primary' : 'text-muted-foreground group-hover:text-foreground']"> <span
分类信息 :class="[
</span> 'text-sm transition-colors',
</div> activeCategory === item.key
? 'font-bold text-primary'
<div class="relative flex items-center gap-4 cursor-pointer group" @click="switchCategory('contract')"> : 'text-muted-foreground group-hover:text-foreground'
<div :class="['z-10 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all', ]"
activeCategory === 'contract' ? 'bg-primary border-primary scale-110' : 'bg-background border-muted-foreground']"> >
<div v-if="activeCategory === 'contract'" class="w-2 h-2 bg-background rounded-full"></div> {{ item.label }}
</div>
<span :class="['text-sm transition-colors', activeCategory === 'contract' ? 'font-bold text-primary' : 'text-muted-foreground group-hover:text-foreground']">
合同段管理
</span> </span>
</div> </div>
</div> </div>
</div> </div>
<div class="w-4/5 p-8 overflow-auto"> <div class="w-4/5 min-h-0">
<keep-alive> <ScrollArea class="h-full w-full">
<component :is="activeCategory === 'info' ? xmView : xmView" /> <div class="p-3">
</keep-alive> <keep-alive>
<component :is="activeComponent" />
</keep-alive>
</div>
</ScrollArea>
</div> </div>
</div> </div>
</template> </template>

View File

@ -2,7 +2,12 @@ import { createApp } from 'vue'
import './style.css' import './style.css'
import App from './App.vue' import App from './App.vue'
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import { AllCommunityModule, ModuleRegistry } from 'ag-grid-community';
import { TreeDataModule ,LicenseManager,CellSelectionModule,ContextMenuModule,ClipboardModule } from 'ag-grid-enterprise';
LicenseManager.setLicenseKey("[v3][RELEASE][0102]_NDg2Njc4MzY3MDgzNw==16d78ca762fb5d2ff740aed081e2af7b");
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' // 引入 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' // 引入
const pinia = createPinia() const pinia = createPinia()
pinia.use(piniaPluginPersistedstate) pinia.use(piniaPluginPersistedstate)
ModuleRegistry.registerModules([AllCommunityModule,TreeDataModule,CellSelectionModule,ContextMenuModule ,ClipboardModule ]);
createApp(App).use(pinia).mount('#app') createApp(App).use(pinia).mount('#app')

View File

@ -1,21 +0,0 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"types": ["vite/client"],
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
},
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

View File

@ -1,19 +1,30 @@
// tsconfig.json
{ {
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.node.json"
}
],
"compilerOptions": { "compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": true, // VueViteTS
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": ["./src/*"] "@/*": ["./src/*"]
}, },
"types": ["@types/node", "@types/bun"] // @types/bun "types": ["@types/node", "@types/bun", "vite/client"] //
},
} "include": [
} "src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"exclude": ["node_modules"]
}

View File

@ -1,26 +0,0 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

1
tsconfig.tsbuildinfo Normal file
View File

@ -0,0 +1 @@
{"root":["./src/main.ts","./src/components/ui/button/index.ts","./src/components/ui/card/index.ts","./src/components/ui/scroll-area/index.ts","./src/lib/utils.ts","./src/pinia/tab.ts","./src/app.vue","./src/components/ui/button/button.vue","./src/components/ui/card/card.vue","./src/components/ui/card/cardaction.vue","./src/components/ui/card/cardcontent.vue","./src/components/ui/card/carddescription.vue","./src/components/ui/card/cardfooter.vue","./src/components/ui/card/cardheader.vue","./src/components/ui/card/cardtitle.vue","./src/components/ui/scroll-area/scrollarea.vue","./src/components/ui/scroll-area/scrollbar.vue","./src/components/views/ht.vue","./src/components/views/xm.vue","./src/components/views/xminfo.vue","./src/layout/tab.vue","./src/layout/typeline.vue"],"version":"5.9.3"}

View File

@ -3,11 +3,45 @@ import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite' import tailwindcss from '@tailwindcss/vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
export default defineConfig({ export default defineConfig({
plugins: [vue(), tailwindcss()], plugins: [vue(),tailwindcss()],
// 路径别名(和 tsconfig 保持一致)
resolve: { resolve: {
alias: { alias: {
'@': path.resolve(__dirname, './src'), '@': path.resolve(__dirname, 'src')
}, }
}, },
}) // 核心build 输出配置
build: {
// 1. 打包输出根目录(默认 dist可自定义
outDir: 'dist',
// 2. 静态资源js/css/img输出子目录默认 assets
assetsDir: 'static',
// 3. 生成的静态资源文件名是否包含哈希(用于缓存控制)
assetsInlineLimit: 4096, // 小于4kb的资源内联不生成文件
rollupOptions: {
// 4. 自定义入口/出口(进阶,一般无需修改)
output: {
// 自定义 chunk 文件名(拆分公共代码)
chunkFileNames: 'static/js/[name]-[hash].js',
// 自定义入口文件名
entryFileNames: 'static/js/[name]-[hash].js',
// 自定义 css 文件名
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
// 拆分第三方依赖(如 vue、axios 单独打包)
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString();
}
}
}
},
// 5. 生产环境是否生成 sourcemap默认 false关闭可减小包体积
sourcemap: false,
// 6. 清空输出目录(默认 true
emptyOutDir: true
},
// 7. 部署的公共路径(关键!如部署到子路径 https://xxx.com/my-app/,需设为 '/my-app/'
base: './' // 相对路径(推荐),或绝对路径 '/'
})