diff --git a/apps/web/index.html b/apps/web/index.html index 63d7e98..b35acdb 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -7,7 +7,10 @@ - ERP Platform + + + + HMS 健康管理平台
diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml index af60352..4face1f 100644 --- a/apps/web/pnpm-lock.yaml +++ b/apps/web/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: '@vitejs/plugin-react': specifier: ^6.0.1 version: 6.0.1(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)) + '@vitest/coverage-v8': + specifier: ^4.1.5 + version: 4.1.5(vitest@4.1.5) eslint: specifier: ^9.39.4 version: 9.39.4(jiti@2.6.1) @@ -93,6 +96,9 @@ importers: jsdom: specifier: ^29.0.2 version: 29.0.2 + msw: + specifier: ^2.13.6 + version: 2.13.6(@types/node@24.12.2)(typescript@6.0.2) tailwindcss: specifier: ^4.2.2 version: 4.2.2 @@ -107,7 +113,7 @@ importers: version: 8.0.8(@types/node@24.12.2)(jiti@2.6.1) vitest: specifier: ^4.1.5 - version: 4.1.5(@types/node@24.12.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)) + version: 4.1.5(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.0.2)(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)) packages: @@ -344,6 +350,10 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + '@bramus/specificity@2.4.2': resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true @@ -490,6 +500,41 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@inquirer/ansi@2.0.5': + resolution: {integrity: sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/confirm@6.0.12': + resolution: {integrity: sha512-h9FgGun3QwVYNj5TWIZZ+slii73bMoBFjPfVIGtnFuL4t8gBiNDV9PcSfIzkuxvgquJKt9nr1QzszpBzTbH8Og==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@11.1.9': + resolution: {integrity: sha512-BDE4fG22uYh1bGSifcj7JSx119TVYNViMhMu85usp4Fswrzh6M0DV3yld64jA98uOAa2GSQ4Bg4bZRm2d2cwSg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@2.0.5': + resolution: {integrity: sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/type@4.0.5': + resolution: {integrity: sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -506,12 +551,28 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mswjs/interceptors@0.41.6': + resolution: {integrity: sha512-qmDvJIjcNsZ6tXWy2G9yuCgMPTTn35GMA3dPpSLm7QJVpbQzYdw0ALy1bKoivXnEM3U93/OrK+/M719b+fg84Q==} + engines: {node: '>=18'} + '@napi-rs/wasm-runtime@1.1.3': resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/deferred-promise@3.0.0': + resolution: {integrity: sha512-XW375UK8/9SqUVNVa6M0yEy8+iTi4QN5VZ7aZuRFQmy76LRwI9wy5F4YIBU6T+eTe2/DNDo8tqu8RHlwLHM6RA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@oxc-project/types@0.124.0': resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} @@ -1131,6 +1192,12 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/set-cookie-parser@2.4.10': + resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==} + + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@typescript-eslint/eslint-plugin@8.58.1': resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1220,6 +1287,15 @@ packages: babel-plugin-react-compiler: optional: true + '@vitest/coverage-v8@4.1.5': + resolution: {integrity: sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==} + peerDependencies: + '@vitest/browser': 4.1.5 + vitest: 4.1.5 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@4.1.5': resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} @@ -1392,6 +1468,9 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1454,6 +1533,14 @@ packages: classcat@5.0.5: resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1686,6 +1773,9 @@ packages: electron-to-chromium@1.5.334: resolution: {integrity: sha512-mgjZAz7Jyx1SRCwEpy9wefDS7GvNPazLthHg8eQMJ76wBdGQQDW33TCrUTvQ4wzpmOrv2zrFoD3oNufMdyMpog==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + enhanced-resolve@5.20.1: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} @@ -1818,6 +1908,15 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.0: + resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1879,6 +1978,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1912,6 +2015,10 @@ packages: graphlib@2.1.8: resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==} + graphql@16.13.2: + resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1928,6 +2035,9 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + headers-polyfill@5.0.1: + resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} @@ -1938,6 +2048,9 @@ packages: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-void-elements@2.0.1: resolution: {integrity: sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==} @@ -1989,6 +2102,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1999,6 +2116,9 @@ packages: is-mobile@5.0.0: resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} @@ -2012,10 +2132,25 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2181,6 +2316,13 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -2225,6 +2367,20 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msw@2.13.6: + resolution: {integrity: sha512-GAJbQy8Ra/Ydjt0Hb2MGT2qhzd83J3+QZMHdH85uW7r/XkKc846+Ma2PLif5hGvTm5Yqa+wkcstpim0WeLZU9g==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} + namespace-emitter@2.0.1: resolution: {integrity: sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==} @@ -2249,6 +2405,9 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -2272,6 +2431,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -2358,6 +2520,10 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -2366,6 +2532,9 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + rettime@0.11.8: + resolution: {integrity: sha512-0fERGXktJTyJ+h8fBEiPxHPEFOu0h15JY7JtwrOVqR5K+vb99ho6IyOo7ekLS3h4sJCzIDy4VWKIbZUfe9njmg==} + rolldown@1.0.0-rc.15: resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2402,6 +2571,9 @@ packages: set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-cookie-parser@3.1.0: + resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2413,6 +2585,10 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + simple-swizzle@0.2.4: resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} @@ -2438,12 +2614,27 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -2481,6 +2672,10 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + tailwindcss@4.2.2: resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} @@ -2541,6 +2736,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@5.6.0: + resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==} + engines: {node: '>=20'} + type@2.7.3: resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} @@ -2563,6 +2762,9 @@ packages: resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} + until-async@3.0.2: + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -2697,6 +2899,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -2704,9 +2910,21 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -3181,6 +3399,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@bcoe/v8-coverage@1.0.2': {} + '@bramus/specificity@2.4.2': dependencies: css-tree: 3.2.1 @@ -3319,6 +3539,33 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@inquirer/ansi@2.0.5': {} + + '@inquirer/confirm@6.0.12(@types/node@24.12.2)': + dependencies: + '@inquirer/core': 11.1.9(@types/node@24.12.2) + '@inquirer/type': 4.0.5(@types/node@24.12.2) + optionalDependencies: + '@types/node': 24.12.2 + + '@inquirer/core@11.1.9(@types/node@24.12.2)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@24.12.2) + cli-width: 4.1.0 + fast-wrap-ansi: 0.2.0 + mute-stream: 3.0.0 + signal-exit: 4.1.0 + optionalDependencies: + '@types/node': 24.12.2 + + '@inquirer/figures@2.0.5': {} + + '@inquirer/type@4.0.5(@types/node@24.12.2)': + optionalDependencies: + '@types/node': 24.12.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -3338,6 +3585,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@mswjs/interceptors@0.41.6': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': dependencies: '@emnapi/core': 1.9.2 @@ -3345,6 +3601,17 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/deferred-promise@3.0.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@oxc-project/types@0.124.0': {} '@playwright/test@1.59.1': @@ -3949,6 +4216,12 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/set-cookie-parser@2.4.10': + dependencies: + '@types/node': 24.12.2 + + '@types/statuses@2.0.6': {} + '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2))(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -4074,6 +4347,20 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.7 vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1) + '@vitest/coverage-v8@4.1.5(vitest@4.1.5)': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.5 + ast-v8-to-istanbul: 1.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.1.0 + tinyrainbow: 3.1.0 + vitest: 4.1.5(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.0.2)(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)) + '@vitest/expect@4.1.5': dependencies: '@standard-schema/spec': 1.1.0 @@ -4083,12 +4370,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))': + '@vitest/mocker@4.1.5(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1))': dependencies: '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.13.6(@types/node@24.12.2)(typescript@6.0.2) vite: 8.0.8(@types/node@24.12.2)(jiti@2.6.1) '@vitest/pretty-format@4.1.5': @@ -4336,6 +4624,12 @@ snapshots: assertion-error@2.0.1: {} + ast-v8-to-istanbul@1.0.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + asynckit@0.4.0: {} axios@1.15.0: @@ -4395,6 +4689,14 @@ snapshots: classcat@5.0.5: {} + cli-width@4.1.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clsx@2.1.1: {} color-convert@2.0.1: @@ -4609,6 +4911,8 @@ snapshots: electron-to-chromium@1.5.334: {} + emoji-regex@8.0.0: {} + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 @@ -4770,6 +5074,16 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-wrap-ansi@0.2.0: + dependencies: + fast-string-width: 3.0.2 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -4814,6 +5128,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4850,6 +5166,8 @@ snapshots: dependencies: lodash: 4.18.1 + graphql@16.13.2: {} + has-flag@4.0.0: {} has-symbols@1.1.0: {} @@ -4862,6 +5180,11 @@ snapshots: dependencies: function-bind: 1.1.2 + headers-polyfill@5.0.1: + dependencies: + '@types/set-cookie-parser': 2.4.10 + set-cookie-parser: 3.1.0 + hermes-estree@0.25.1: {} hermes-parser@0.25.1: @@ -4874,6 +5197,8 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + html-escaper@2.0.2: {} + html-void-elements@2.0.1: {} html2canvas@1.4.1: @@ -4912,6 +5237,8 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@3.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -4920,6 +5247,8 @@ snapshots: is-mobile@5.0.0: {} + is-node-process@1.2.0: {} + is-plain-object@5.0.0: {} is-potential-custom-element-name@1.0.1: {} @@ -4928,8 +5257,23 @@ snapshots: isexe@2.0.0: {} + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + jiti@2.6.1: {} + js-tokens@10.0.0: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -5068,6 +5412,16 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.4 + math-intrinsics@1.1.0: {} mdn-data@2.27.1: {} @@ -5113,6 +5467,33 @@ snapshots: ms@2.1.3: {} + msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2): + dependencies: + '@inquirer/confirm': 6.0.12(@types/node@24.12.2) + '@mswjs/interceptors': 0.41.6 + '@open-draft/deferred-promise': 3.0.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.13.2 + headers-polyfill: 5.0.1 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.11.8 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.1 + type-fest: 5.6.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 6.0.2 + transitivePeerDependencies: + - '@types/node' + + mute-stream@3.0.0: {} + namespace-emitter@2.0.1: {} nanoid@3.3.11: {} @@ -5134,6 +5515,8 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + outvariant@1.4.3: {} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -5154,6 +5537,8 @@ snapshots: path-key@3.1.1: {} + path-to-regexp@6.3.0: {} + pathe@2.0.3: {} pdfast@0.2.0: {} @@ -5222,10 +5607,14 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 + require-directory@2.1.1: {} + require-from-string@2.0.2: {} resolve-from@4.0.0: {} + rettime@0.11.8: {} + rolldown@1.0.0-rc.15: dependencies: '@oxc-project/types': 0.124.0 @@ -5271,6 +5660,8 @@ snapshots: set-cookie-parser@2.7.2: {} + set-cookie-parser@3.1.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -5279,6 +5670,8 @@ snapshots: siginfo@2.0.0: {} + signal-exit@4.1.0: {} + simple-swizzle@0.2.4: dependencies: is-arrayish: 0.3.4 @@ -5302,10 +5695,24 @@ snapshots: stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@4.1.0: {} + strict-event-emitter@0.5.1: {} + string-convert@0.2.1: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -5331,6 +5738,8 @@ snapshots: symbol-tree@3.2.4: {} + tagged-tag@1.0.0: {} + tailwindcss@4.2.2: {} tapable@2.3.2: {} @@ -5378,6 +5787,10 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@5.6.0: + dependencies: + tagged-tag: 1.0.0 + type@2.7.3: {} typescript-eslint@8.58.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.2): @@ -5397,6 +5810,8 @@ snapshots: undici@7.25.0: {} + until-async@3.0.2: {} + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: browserslist: 4.28.2 @@ -5427,10 +5842,10 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 - vitest@4.1.5(@types/node@24.12.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)): + vitest@4.1.5(@types/node@24.12.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.0.2)(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)): dependencies: '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)) + '@vitest/mocker': 4.1.5(msw@2.13.6(@types/node@24.12.2)(typescript@6.0.2))(vite@8.0.8(@types/node@24.12.2)(jiti@2.6.1)) '@vitest/pretty-format': 4.1.5 '@vitest/runner': 4.1.5 '@vitest/snapshot': 4.1.5 @@ -5451,6 +5866,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.2 + '@vitest/coverage-v8': 4.1.5(vitest@4.1.5) jsdom: 29.0.2 transitivePeerDependencies: - msw @@ -5484,12 +5900,32 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + xml-name-validator@5.0.0: {} xmlchars@2.2.0: {} + y18n@5.0.8: {} + yallist@3.1.1: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} zod-validation-error@4.0.2(zod@4.3.6): diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 5c19eb4..38c7ce1 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,4 +1,4 @@ -import { useEffect, lazy, Suspense } from 'react'; +import { useEffect, lazy, Suspense, useMemo } from 'react'; import { HashRouter, Routes, Route, Navigate } from 'react-router-dom'; import { ConfigProvider, theme as antdTheme, Spin } from 'antd'; import zhCN from 'antd/locale/zh_CN'; @@ -7,6 +7,7 @@ import Login from './pages/Login'; import { ErrorBoundary } from './components/ErrorBoundary'; import { useAuthStore } from './stores/auth'; import { useAppStore } from './stores/app'; +import type { ThemeName } from './stores/app'; const Home = lazy(() => import('./pages/Home')); const Users = lazy(() => import('./pages/Users')); @@ -68,93 +69,129 @@ function PrivateRoute({ children }: { children: React.ReactNode }) { return <>{children}; } -const themeConfig = { - token: { - colorPrimary: '#2563eb', - colorSuccess: '#059669', - colorWarning: '#d97706', - colorError: '#dc2626', - colorInfo: '#0284c7', - colorBgLayout: '#f8fafc', - colorBgContainer: '#ffffff', - colorBgElevated: '#ffffff', - colorBorder: '#e2e8f0', - colorBorderSecondary: '#f1f5f9', - borderRadius: 10, - borderRadiusLG: 12, - borderRadiusSM: 6, - fontFamily: "'Noto Sans SC', -apple-system, system-ui, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif", - fontSize: 14, - fontSizeHeading4: 20, - controlHeight: 40, - controlHeightLG: 44, - controlHeightSM: 32, - boxShadow: 'none', - boxShadowSecondary: '0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)', - }, - components: { - Button: { - primaryShadow: 'none', - fontWeight: 500, - }, - Card: { - paddingLG: 20, - }, - Table: { - headerBg: '#f1f5f9', - headerColor: '#475569', - rowHoverBg: '#f1f5f9', - fontSize: 14, - }, - Menu: { - itemBorderRadius: 10, - itemMarginInline: 8, - itemHeight: 40, - }, - Modal: { - borderRadiusLG: 16, - }, - Tag: { - borderRadiusSM: 6, - }, - }, +const baseToken = { + borderRadius: 10, + borderRadiusLG: 12, + borderRadiusSM: 6, + fontFamily: "'Noto Sans SC', -apple-system, system-ui, 'Segoe UI', Roboto, 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif", + fontSize: 14, + fontSizeHeading4: 20, + controlHeight: 40, + controlHeightLG: 44, + controlHeightSM: 32, + boxShadow: 'none', + boxShadowSecondary: '0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)', }; -const darkThemeConfig = { - ...themeConfig, - token: { - ...themeConfig.token, - colorBgLayout: '#0f172a', - colorBgContainer: '#1e293b', - colorBgElevated: '#334155', - colorBorder: '#334155', - colorBorderSecondary: 'rgba(255, 255, 255, 0.06)', - boxShadow: 'none', - boxShadowSecondary: '0 2px 8px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.2)', +const baseComponents = { + Button: { primaryShadow: 'none', fontWeight: 500 }, + Card: { paddingLG: 20 }, + Menu: { itemBorderRadius: 10, itemMarginInline: 8, itemHeight: 40 }, + Modal: { borderRadiusLG: 16 }, + Tag: { borderRadiusSM: 6 }, +}; + +const themeConfigs: Record; components: Record> }> = { + blue: { + token: { + ...baseToken, + colorPrimary: '#2563eb', + colorSuccess: '#059669', + colorWarning: '#d97706', + colorError: '#dc2626', + colorInfo: '#0284c7', + colorBgLayout: '#f8fafc', + colorBgContainer: '#ffffff', + colorBgElevated: '#ffffff', + colorBorder: '#e2e8f0', + colorBorderSecondary: '#f1f5f9', + }, + components: { + ...baseComponents, + Table: { headerBg: '#f1f5f9', headerColor: '#475569', rowHoverBg: '#f1f5f9', fontSize: 14 }, + }, }, - components: { - ...themeConfig.components, - Table: { - headerBg: '#1e293b', - headerColor: '#94a3b8', - rowHoverBg: '#1e293b', + warm: { + token: { + ...baseToken, + borderRadius: 12, + borderRadiusLG: 14, + borderRadiusSM: 8, + colorPrimary: '#C4623A', + colorSuccess: '#5B7A5E', + colorWarning: '#C4873A', + colorError: '#B54A4A', + colorInfo: '#8B7A5E', + colorBgLayout: '#F5F0EB', + colorBgContainer: '#ffffff', + colorBgElevated: '#ffffff', + colorBorder: '#E8E2DC', + colorBorderSecondary: '#F0EBE5', + }, + components: { + ...baseComponents, + Table: { headerBg: '#EDE8E2', headerColor: '#7A756E', rowHoverBg: '#F5F0EB', fontSize: 14 }, + }, + }, + dark: { + token: { + ...baseToken, + colorPrimary: '#60A5FA', + colorSuccess: '#34D399', + colorWarning: '#FBBF24', + colorError: '#F87171', + colorInfo: '#38BDF8', + colorBgLayout: '#0F172A', + colorBgContainer: '#1E293B', + colorBgElevated: '#334155', + colorBorder: '#334155', + colorBorderSecondary: 'rgba(255,255,255,0.06)', + boxShadow: 'none', + boxShadowSecondary: '0 2px 8px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.2)', + }, + components: { + ...baseComponents, + Table: { headerBg: '#1E293B', headerColor: '#94A3B8', rowHoverBg: '#1E293B', fontSize: 14 }, + }, + }, + emerald: { + token: { + ...baseToken, + borderRadius: 10, + borderRadiusLG: 14, + borderRadiusSM: 8, + colorPrimary: '#5B7A5E', + colorSuccess: '#3D7A42', + colorWarning: '#B8863A', + colorError: '#A54A4A', + colorInfo: '#4A7A8B', + colorBgLayout: '#F4F7F4', + colorBgContainer: '#ffffff', + colorBgElevated: '#ffffff', + colorBorder: '#D5DED5', + colorBorderSecondary: '#E5ECE5', + }, + components: { + ...baseComponents, + Table: { headerBg: '#EDF2ED', headerColor: '#5A6E5A', rowHoverBg: '#F4F7F4', fontSize: 14 }, }, }, }; export default function App() { const loadFromStorage = useAuthStore((s) => s.loadFromStorage); - const themeMode = useAppStore((s) => s.theme); + const themeName = useAppStore((s) => s.theme); useEffect(() => { loadFromStorage(); }, [loadFromStorage]); useEffect(() => { - document.documentElement.setAttribute('data-theme', themeMode); - }, [themeMode]); + document.documentElement.setAttribute('data-theme', themeName); + }, [themeName]); - const isDark = themeMode === 'dark'; + const isDark = themeName === 'dark'; + const antTheme = useMemo(() => themeConfigs[themeName] ?? themeConfigs.blue, [themeName]); return ( <> @@ -162,7 +199,7 @@ export default function App() { diff --git a/apps/web/src/components/ThemeSwitcher.tsx b/apps/web/src/components/ThemeSwitcher.tsx new file mode 100644 index 0000000..4f9b1ad --- /dev/null +++ b/apps/web/src/components/ThemeSwitcher.tsx @@ -0,0 +1,64 @@ +import { Dropdown } from 'antd'; +import { BgColorsOutlined } from '@ant-design/icons'; +import { useAppStore, THEME_OPTIONS } from '../stores/app'; + +export default function ThemeSwitcher() { + const theme = useAppStore((s) => s.theme); + const setTheme = useAppStore((s) => s.setTheme); + + const content = ( +
+ {THEME_OPTIONS.map((opt) => { + const active = theme === opt.key; + return ( +
setTheme(opt.key)} + style={{ + display: 'flex', + alignItems: 'center', + gap: 12, + padding: '10px 12px', + borderRadius: 8, + cursor: 'pointer', + border: `2px solid ${active ? opt.preview.primary : 'transparent'}`, + background: active ? `${opt.preview.primary}08` : 'transparent', + transition: 'all 0.15s ease', + }} + > + {/* 色块预览 */} +
+
+
+
+
+
+
{opt.label}
+
{opt.desc}
+
+ {active && ( +
+ )} +
+ ); + })} +
+ ); + + return ( + content} trigger={['click']} placement="bottomRight"> +
+ +
+
+ ); +} diff --git a/apps/web/src/hooks/useThemeMode.ts b/apps/web/src/hooks/useThemeMode.ts index d10eab9..36bde12 100644 --- a/apps/web/src/hooks/useThemeMode.ts +++ b/apps/web/src/hooks/useThemeMode.ts @@ -1,15 +1,11 @@ -import { theme } from 'antd'; +import { useAppStore } from '../stores/app'; /** * 判断当前是否处于暗色主题模式。 * - * 通过 antd design token 的 colorBgContainer 色值检测, - * 统一替代各页面中重复的 `token.colorBgContainer === '#111827'` 内联判断。 + * 通过 store 的主题名称判断,替代旧的 token 色值检测, + * 支持多主题系统(blue / warm / dark / emerald)。 */ export function useThemeMode(): boolean { - const { token } = theme.useToken(); - return ( - token.colorBgContainer === '#111827' || - token.colorBgContainer === 'rgb(17, 24, 39)' - ); + return useAppStore((s) => s.theme) === 'dark'; } diff --git a/apps/web/src/index.css b/apps/web/src/index.css index fc6a67b..3ca859c 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -96,54 +96,175 @@ --erp-line-height-normal: 1.5; --erp-line-height-relaxed: 1.625; + /* Heading font — override per theme */ + --erp-font-heading: 'Noto Sans SC', -apple-system, system-ui, sans-serif; + /* Layout */ --erp-sidebar-width: 240px; --erp-sidebar-collapsed-width: 72px; --erp-header-height: 56px; } -/* --- Dark Mode Tokens --- */ -[data-theme='dark'] { - --erp-primary-light: rgba(37, 99, 235, 0.15); - --erp-primary-light-hover: rgba(37, 99, 235, 0.22); - --erp-primary-bg-subtle: rgba(37, 99, 235, 0.1); +/* ─── Theme: 温润东方 (warm) ─── */ +[data-theme='warm'] { + --erp-primary: #C4623A; + --erp-primary-hover: #B55A33; + --erp-primary-active: #8B3E1F; + --erp-primary-light: #F0DDD4; + --erp-primary-light-hover: #E8CEBF; + --erp-primary-bg-subtle: #FAF5F0; - --erp-bg-page: #0f172a; - --erp-bg-container: #1e293b; - --erp-bg-elevated: #334155; - --erp-bg-spotlight: #1e293b; - --erp-bg-sidebar: #0f172a; - --erp-bg-sidebar-hover: #1e293b; + --erp-success: #5B7A5E; + --erp-success-bg: #E8F0E8; + --erp-warning: #C4873A; + --erp-warning-bg: #FFF3E0; + --erp-error: #B54A4A; + --erp-error-bg: #FDEAEA; + --erp-info: #8B7A5E; + --erp-info-bg: #F5F0E8; - --erp-text-primary: rgba(255, 255, 255, 0.95); - --erp-text-secondary: #94a3b8; - --erp-text-tertiary: #64748b; - --erp-text-sidebar: #94a3b8; - --erp-text-sidebar-active: #60a5fa; + --erp-bg-page: #F5F0EB; + --erp-bg-container: #FFFFFF; + --erp-bg-elevated: #FFFFFF; + --erp-bg-spotlight: #EDE8E2; + --erp-bg-sidebar: #FFFFFF; + --erp-bg-sidebar-hover: #F5F0EB; + --erp-bg-sidebar-active: #F0DDD4; - --erp-border: #334155; - --erp-border-light: rgba(255, 255, 255, 0.06); - --erp-border-dark: rgba(255, 255, 255, 0.12); + --erp-text-primary: #2D2A26; + --erp-text-secondary: #7A756E; + --erp-text-tertiary: #A8A29E; + --erp-text-inverse: #FFFFFF; + --erp-text-sidebar: #7A756E; + --erp-text-sidebar-active: #C4623A; - --erp-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3); - --erp-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2); - --erp-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.3), 0 2px 6px rgba(0, 0, 0, 0.2); - --erp-shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.4); + --erp-border: #E8E2DC; + --erp-border-light: #F0EBE5; + --erp-border-dark: #D5CFC8; - --erp-trend-up: #34d399; - --erp-trend-down: #f87171; - --erp-trend-neutral: #94a3b8; + --erp-shadow-xs: 0 1px 2px rgba(45,42,38,0.04); + --erp-shadow-sm: 0 1px 3px rgba(45,42,38,0.06), 0 1px 2px rgba(45,42,38,0.03); + --erp-shadow-md: 0 4px 6px rgba(45,42,38,0.07), 0 2px 4px rgba(45,42,38,0.04); + --erp-shadow-lg: 0 8px 30px rgba(45,42,38,0.10); + --erp-shadow-xl: 0 12px 40px rgba(45,42,38,0.14); - --erp-success-bg: rgba(5, 150, 105, 0.15); - --erp-warning-bg: rgba(217, 119, 6, 0.15); - --erp-error-bg: rgba(220, 38, 38, 0.15); - --erp-info-bg: rgba(2, 132, 199, 0.15); + --erp-radius-sm: 8px; + --erp-radius-md: 12px; + --erp-radius-lg: 14px; + --erp-radius-xl: 18px; + + --erp-trend-up: #5B7A5E; + --erp-trend-down: #B54A4A; + --erp-trend-neutral: #7A756E; + + --erp-font-heading: 'Noto Serif SC', Georgia, serif; +} + +/* ─── Theme: 深邃夜色 (dark) ─── */ +[data-theme='dark'] { + --erp-primary: #60A5FA; + --erp-primary-hover: #93C5FD; + --erp-primary-active: #3B82F6; + --erp-primary-light: rgba(96,165,250,0.15); + --erp-primary-light-hover: rgba(96,165,250,0.22); + --erp-primary-bg-subtle: rgba(96,165,250,0.10); + + --erp-success: #34D399; + --erp-success-bg: rgba(5,150,105,0.15); + --erp-warning: #FBBF24; + --erp-warning-bg: rgba(217,119,6,0.15); + --erp-error: #F87171; + --erp-error-bg: rgba(220,38,38,0.15); + --erp-info: #38BDF8; + --erp-info-bg: rgba(2,132,199,0.15); + + --erp-bg-page: #0F172A; + --erp-bg-container: #1E293B; + --erp-bg-elevated: #334155; + --erp-bg-spotlight: #1E293B; + --erp-bg-sidebar: #0F172A; + --erp-bg-sidebar-hover: #1E293B; + --erp-bg-sidebar-active: rgba(96,165,250,0.15); + + --erp-text-primary: rgba(255,255,255,0.95); + --erp-text-secondary: #94A3B8; + --erp-text-tertiary: #64748B; + --erp-text-inverse: #0F172A; + --erp-text-sidebar: #94A3B8; + --erp-text-sidebar-active: #60A5FA; + + --erp-border: #334155; + --erp-border-light: rgba(255,255,255,0.06); + --erp-border-dark: rgba(255,255,255,0.12); + + --erp-shadow-xs: 0 1px 2px rgba(0,0,0,0.3); + --erp-shadow-sm: 0 2px 8px rgba(0,0,0,0.3), 0 1px 3px rgba(0,0,0,0.2); + --erp-shadow-md: 0 4px 12px rgba(0,0,0,0.3), 0 2px 6px rgba(0,0,0,0.2); + --erp-shadow-lg: 0 8px 30px rgba(0,0,0,0.4); + --erp-shadow-xl: 0 12px 40px rgba(0,0,0,0.5); + + --erp-trend-up: #34D399; + --erp-trend-down: #F87171; + --erp-trend-neutral: #94A3B8; + + --erp-font-heading: 'Noto Sans SC', -apple-system, system-ui, sans-serif; +} + +/* ─── Theme: 翡翠清雅 (emerald) ─── */ +[data-theme='emerald'] { + --erp-primary: #5B7A5E; + --erp-primary-hover: #4D6B50; + --erp-primary-active: #3E5C41; + --erp-primary-light: #E0EBE1; + --erp-primary-light-hover: #D1E0D3; + --erp-primary-bg-subtle: #F0F5F0; + + --erp-success: #3D7A42; + --erp-success-bg: #E0F0E2; + --erp-warning: #B8863A; + --erp-warning-bg: #FFF3E0; + --erp-error: #A54A4A; + --erp-error-bg: #FDEAEA; + --erp-info: #4A7A8B; + --erp-info-bg: #E0F0F5; + + --erp-bg-page: #F4F7F4; + --erp-bg-container: #FFFFFF; + --erp-bg-elevated: #FFFFFF; + --erp-bg-spotlight: #EDF2ED; + --erp-bg-sidebar: #FFFFFF; + --erp-bg-sidebar-hover: #F4F7F4; + --erp-bg-sidebar-active: #E0EBE1; + + --erp-text-primary: #1A2E1A; + --erp-text-secondary: #5A6E5A; + --erp-text-tertiary: #8FA08F; + --erp-text-inverse: #FFFFFF; + --erp-text-sidebar: #5A6E5A; + --erp-text-sidebar-active: #5B7A5E; + + --erp-border: #D5DED5; + --erp-border-light: #E5ECE5; + --erp-border-dark: #B8C5B8; + + --erp-shadow-xs: 0 1px 2px rgba(30,60,30,0.04); + --erp-shadow-sm: 0 1px 3px rgba(30,60,30,0.06), 0 1px 2px rgba(30,60,30,0.03); + --erp-shadow-md: 0 4px 6px rgba(30,60,30,0.07), 0 2px 4px rgba(30,60,30,0.04); + --erp-shadow-lg: 0 8px 30px rgba(30,60,30,0.10); + --erp-shadow-xl: 0 12px 40px rgba(30,60,30,0.14); + + --erp-radius-sm: 8px; + --erp-radius-md: 10px; + --erp-radius-lg: 14px; + --erp-radius-xl: 18px; + + --erp-trend-up: #3D7A42; + --erp-trend-down: #A54A4A; + --erp-trend-neutral: #5A6E5A; + + --erp-font-heading: 'Noto Sans SC', -apple-system, system-ui, sans-serif; } -[data-theme='dark'] .erp-stat-card-trend-up { color: #34d399; } -[data-theme='dark'] .erp-stat-card-trend-down { color: #f87171; } -[data-theme='dark'] .erp-stat-card-trend-neutral { color: #94a3b8; } -[data-theme='dark'] .erp-stat-card-trend-label { color: #94a3b8; } /* --- Global Reset & Base --- */ body { @@ -156,6 +277,23 @@ body { -moz-osx-font-smoothing: grayscale; } +/* Force Ant Design Layout backgrounds to follow theme */ +.ant-layout { + background: var(--erp-bg-page) !important; +} +.ant-layout-content { + background: transparent !important; +} +.ant-layout-sider { + background: var(--erp-bg-sidebar) !important; +} +.ant-layout-header { + background: var(--erp-bg-container) !important; +} +.ant-layout-footer { + background: transparent !important; +} + /* --- Smooth Scrolling --- */ * { scroll-behavior: smooth; @@ -182,7 +320,7 @@ body { /* --- Selection --- */ ::selection { - background-color: rgba(37, 99, 235, 0.15); + background-color: var(--erp-primary-bg-subtle); color: var(--erp-text-primary); } @@ -546,16 +684,16 @@ body { } .erp-sidebar-menu .ant-menu-item-selected { - background: #eff6ff !important; - color: #2563eb !important; + background: var(--erp-bg-sidebar-active) !important; + color: var(--erp-text-sidebar-active) !important; } .erp-sidebar-menu .ant-menu-item-selected .anticon { - color: #2563eb !important; + color: var(--erp-text-sidebar-active) !important; } .erp-sidebar-menu .ant-menu-item:not(.ant-menu-item-selected):hover { - background: #f1f5f9 !important; + background: var(--erp-bg-sidebar-hover) !important; } /* Sidebar group label */ @@ -565,17 +703,17 @@ body { font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; - color: #94a3b8; + color: var(--erp-text-tertiary); } /* ==================================================================== * MainLayout — CSS classes replacing inline styles * ==================================================================== */ -/* Sider — White sidebar, Soft UI style */ +/* Sider */ .erp-sider-dark { - background: #ffffff !important; - border-right: 1px solid #e2e8f0 !important; + background: var(--erp-bg-sidebar) !important; + border-right: 1px solid var(--erp-border) !important; position: fixed !important; left: 0; top: 0; @@ -584,25 +722,16 @@ body { overflow: auto; } -[data-theme='dark'] .erp-sider-dark { - background: #0f172a !important; - border-right: 1px solid #334155 !important; -} - /* Logo */ .erp-sidebar-logo { height: 56px; display: flex; align-items: center; padding: 0 20px; - border-bottom: 1px solid #e2e8f0; + border-bottom: 1px solid var(--erp-border); cursor: pointer; } -[data-theme='dark'] .erp-sidebar-logo { - border-bottom: 1px solid #334155; -} - .ant-layout-sider-collapsed .erp-sidebar-logo { justify-content: center; padding: 0; @@ -612,7 +741,7 @@ body { width: 28px; height: 28px; border-radius: var(--erp-radius-sm); - background: #2563eb; + background: var(--erp-primary); display: flex; align-items: center; justify-content: center; @@ -624,17 +753,13 @@ body { .erp-sidebar-logo-text { margin-left: 10px; - color: #0f172a; + color: var(--erp-text-primary); font-size: 15px; font-weight: 700; letter-spacing: -0.3px; white-space: nowrap; } -[data-theme='dark'] .erp-sidebar-logo-text { - color: rgba(255, 255, 255, 0.95); -} - /* Sidebar menu item */ .erp-sidebar-item { display: flex; @@ -644,7 +769,7 @@ body { padding: 0 12px; border-radius: var(--erp-radius-md); cursor: pointer; - color: #475569; + color: var(--erp-text-sidebar); font-size: 14px; font-weight: 400; transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1); @@ -657,30 +782,16 @@ body { } .erp-sidebar-item:hover:not(.erp-sidebar-item-active) { - background: #f1f5f9; - color: #0f172a; -} - -[data-theme='dark'] .erp-sidebar-item { - color: #94a3b8; -} - -[data-theme='dark'] .erp-sidebar-item:hover:not(.erp-sidebar-item-active) { - background: #1e293b; - color: rgba(255, 255, 255, 0.95); + background: var(--erp-bg-sidebar-hover); + color: var(--erp-text-primary); } .erp-sidebar-item-active { - background: #eff6ff; - color: #2563eb; + background: var(--erp-bg-sidebar-active); + color: var(--erp-text-sidebar-active); font-weight: 500; } -[data-theme='dark'] .erp-sidebar-item-active { - background: rgba(37, 99, 235, 0.15); - color: #60a5fa; -} - .erp-sidebar-item-icon { font-size: 16px; display: flex; @@ -700,7 +811,7 @@ body { padding: 0 12px; border-radius: var(--erp-radius-md); cursor: pointer; - color: #94a3b8; + color: var(--erp-text-tertiary); font-size: 11px; font-weight: 600; text-transform: uppercase; @@ -710,25 +821,12 @@ body { } .erp-sidebar-submenu-title:hover { - background: #f1f5f9; - color: #475569; -} - -[data-theme='dark'] .erp-sidebar-submenu-title { - color: #64748b; -} - -[data-theme='dark'] .erp-sidebar-submenu-title:hover { - background: #1e293b; - color: #94a3b8; + background: var(--erp-bg-sidebar-hover); + color: var(--erp-text-secondary); } .erp-sidebar-submenu-title-active { - color: #2563eb; -} - -[data-theme='dark'] .erp-sidebar-submenu-title-active { - color: #60a5fa; + color: var(--erp-text-sidebar-active); } .erp-sidebar-submenu-arrow { @@ -750,12 +848,10 @@ body { /* Main layout */ .erp-main-layout { + background: var(--erp-bg-page) !important; transition: margin-left 0.2s cubic-bezier(0.4, 0, 0.2, 1); } -.erp-main-layout-light { background: #f8fafc; } -.erp-main-layout-dark { background: #0f172a; } - /* Header */ .erp-header { height: 56px !important; @@ -767,17 +863,8 @@ body { top: 0; z-index: 99; line-height: 56px !important; -} - -.erp-header-light { - background: #ffffff !important; - border-bottom: 1px solid #e2e8f0; - box-shadow: none; -} - -.erp-header-dark { - background: #1e293b !important; - border-bottom: 1px solid #334155; + background: var(--erp-bg-container) !important; + border-bottom: 1px solid var(--erp-border) !important; box-shadow: none; } @@ -790,24 +877,20 @@ body { justify-content: center; cursor: pointer; transition: all 0.15s ease; - color: #475569; + color: var(--erp-text-secondary); will-change: background; } -.erp-header-light .erp-header-btn { color: #475569; } -.erp-header-dark .erp-header-btn { color: #94a3b8; } -.erp-header-btn:hover { background: #f1f5f9; } -.erp-header-dark .erp-header-btn:hover { background: #334155; } +.erp-header-btn:hover { background: var(--erp-bg-spotlight); } -.erp-header-title { font-size: 15px; font-weight: 600; } -.erp-text-light { color: #0f172a; } -.erp-text-dark { color: rgba(255, 255, 255, 0.95); } -.erp-text-light-secondary { color: #475569; } -.erp-text-dark-secondary { color: #94a3b8; } +.erp-header-title { + font-size: 15px; + font-weight: 600; + color: var(--erp-text-primary); + font-family: var(--erp-font-heading); +} -.erp-header-divider { width: 1px; height: 24px; margin: 0 8px; } -.erp-header-divider-light { background: rgba(0, 0, 0, 0.06); } -.erp-header-divider-dark { background: rgba(255, 255, 255, 0.06); } +.erp-header-divider { width: 1px; height: 24px; margin: 0 8px; background: var(--erp-border-light); } /* User avatar */ .erp-header-user { @@ -820,20 +903,17 @@ body { transition: all 0.15s ease; } -.erp-header-user:hover { background: #f1f5f9; } -.erp-header-dark .erp-header-user:hover { background: #334155; } +.erp-header-user:hover { background: var(--erp-bg-spotlight); } .erp-user-avatar { - background: #2563eb !important; + background: var(--erp-primary) !important; font-size: 13px !important; } -.erp-user-name { font-size: 13px; font-weight: 500; } +.erp-user-name { font-size: 13px; font-weight: 500; color: var(--erp-text-secondary); } /* Footer */ -.erp-footer { text-align: center; padding: 12px 24px !important; background: transparent !important; font-size: 12px; } -.erp-footer-light { color: #94a3b8; } -.erp-footer-dark { color: #64748b; } +.erp-footer { text-align: center; padding: 12px 24px !important; background: transparent !important; font-size: 12px; color: var(--erp-text-tertiary); } /* ==================================================================== * Dashboard — Stat Cards & Quick Actions @@ -864,7 +944,7 @@ body { left: 0; right: 0; height: 3px; - background: var(--card-gradient, linear-gradient(135deg, #2563eb, #60a5fa)); + background: var(--card-gradient, linear-gradient(135deg, var(--erp-primary), var(--erp-primary-hover))); } .erp-stat-card-body { @@ -895,7 +975,7 @@ body { width: 48px; height: 48px; border-radius: var(--erp-radius-lg); - background: var(--card-icon-bg, rgba(37, 99, 235, 0.08)); + background: var(--card-icon-bg, var(--erp-primary-bg-subtle)); display: flex; align-items: center; justify-content: center; @@ -913,7 +993,7 @@ body { .erp-section-icon { font-size: 16px; - color: #2563eb; + color: var(--erp-primary); } .erp-section-title { @@ -936,17 +1016,8 @@ body { } .erp-quick-action:hover { - background: #eff6ff; - border-color: var(--action-color, #2563eb); -} - -[data-theme='dark'] .erp-quick-action { - background: #0f172a; -} - -[data-theme='dark'] .erp-quick-action:hover { - background: #1e293b; - border-color: var(--action-color, #2563eb); + background: var(--erp-primary-bg-subtle); + border-color: var(--action-color, var(--erp-primary)); } .erp-quick-action-icon { @@ -956,8 +1027,8 @@ body { display: flex; align-items: center; justify-content: center; - background: color-mix(in srgb, var(--action-color, #2563eb) 8%, transparent); - color: var(--action-color, #2563eb); + background: color-mix(in srgb, var(--action-color, var(--erp-primary)) 8%, transparent); + color: var(--action-color, var(--erp-primary)); font-size: 16px; flex-shrink: 0; } @@ -1008,12 +1079,12 @@ body { font-weight: 500; } -.erp-stat-card-trend-up { color: #059669; } -.erp-stat-card-trend-down { color: #dc2626; } -.erp-stat-card-trend-neutral { color: #475569; } +.erp-stat-card-trend-up { color: var(--erp-trend-up); } +.erp-stat-card-trend-down { color: var(--erp-trend-down); } +.erp-stat-card-trend-neutral { color: var(--erp-trend-neutral); } .erp-stat-card-trend-label { - color: #475569; + color: var(--erp-text-secondary); font-weight: 400; } @@ -1046,8 +1117,8 @@ body { display: flex; align-items: center; justify-content: center; - background: color-mix(in srgb, var(--action-color, #2563eb) 8%, transparent); - color: var(--action-color, #2563eb); + background: color-mix(in srgb, var(--action-color, var(--erp-primary)) 8%, transparent); + color: var(--action-color, var(--erp-primary)); font-size: 18px; flex-shrink: 0; transition: transform 0.15s ease; @@ -1075,7 +1146,7 @@ body { padding: 12px 16px; border-radius: var(--erp-radius-md); background: var(--erp-bg-spotlight); - border-left: 3px solid var(--task-color, #2563eb); + border-left: 3px solid var(--task-color, var(--erp-primary)); cursor: pointer; transition: all 0.15s ease; } @@ -1093,7 +1164,7 @@ body { align-items: center; justify-content: center; background: color-mix(in srgb, var(--task-color, #2563eb) 8%, transparent); - color: var(--task-color, #2563eb); + color: var(--task-color, var(--erp-primary)); font-size: 14px; flex-shrink: 0; } @@ -1115,7 +1186,7 @@ body { gap: 12px; margin-top: 2px; font-size: var(--erp-font-size-xs); - color: #94a3b8; + color: var(--erp-text-tertiary); } .erp-task-priority { @@ -1127,13 +1198,9 @@ body { font-weight: 600; } -.erp-task-priority-high { background: #fef2f2; color: #dc2626; } -.erp-task-priority-medium { background: #fffbeb; color: #d97706; } -.erp-task-priority-low { background: #ecfdf5; color: #059669; } - -[data-theme='dark'] .erp-task-priority-high { background: rgba(220, 38, 38, 0.15); color: #f87171; } -[data-theme='dark'] .erp-task-priority-medium { background: rgba(217, 119, 6, 0.15); color: #fbbf24; } -[data-theme='dark'] .erp-task-priority-low { background: rgba(5, 150, 105, 0.15); color: #34d399; } +.erp-task-priority-high { background: var(--erp-error-bg); color: var(--erp-error); } +.erp-task-priority-medium { background: var(--erp-warning-bg); color: var(--erp-warning); } +.erp-task-priority-low { background: var(--erp-success-bg); color: var(--erp-success); } /* Activity Timeline */ .erp-activity-list { @@ -1189,14 +1256,10 @@ body { .erp-activity-time { font-size: 11px; - color: #94a3b8; + color: var(--erp-text-tertiary); margin-top: 2px; } -[data-theme='dark'] .erp-activity-time { - color: #64748b; -} - /* Empty State */ .erp-empty-state { display: flex; diff --git a/apps/web/src/layouts/MainLayout.tsx b/apps/web/src/layouts/MainLayout.tsx index 40155eb..5f13c29 100644 --- a/apps/web/src/layouts/MainLayout.tsx +++ b/apps/web/src/layouts/MainLayout.tsx @@ -12,8 +12,6 @@ import { LogoutOutlined, MessageOutlined, SearchOutlined, - BulbOutlined, - BulbFilled, AppstoreOutlined, TeamOutlined, TableOutlined, @@ -39,6 +37,7 @@ import { usePluginStore } from '../stores/plugin'; import type { PluginMenuGroup } from '../stores/plugin'; import { getMenusForUser, type MenuInfo } from '../api/menus'; import NotificationPanel from '../components/NotificationPanel'; +import ThemeSwitcher from '../components/ThemeSwitcher'; const { Header, Sider, Content, Footer } = Layout; @@ -345,7 +344,7 @@ const DynamicMenuSection = memo(function DynamicMenuSection({ }); export default function MainLayout({ children }: { children: React.ReactNode }) { - const { sidebarCollapsed, toggleSidebar, theme: themeMode, setTheme } = useAppStore(); + const { sidebarCollapsed, toggleSidebar } = useAppStore(); const { user, logout } = useAuthStore(); const pluginMenuItems = usePluginStore((s) => s.pluginMenuItems); const pluginMenuGroups = usePluginStore((s) => s.pluginMenuGroups); @@ -413,24 +412,23 @@ export default function MainLayout({ children }: { children: React.ReactNode }) ]; const sidebarWidth = sidebarCollapsed ? 72 : 240; - const isDark = themeMode === 'dark'; return ( - {/* 现代深色侧边栏 */} + {/* 侧边栏 */} {/* Logo 区域 */}
navigate('/')}> -
E
+
H
{!sidebarCollapsed && ( - ERP Platform + HMS 健康 )}
@@ -469,22 +467,22 @@ export default function MainLayout({ children }: { children: React.ReactNode }) {/* 右侧主区域 */} {/* 顶部导航栏 */} -
+
{/* 左侧:折叠按钮 + 标题 */}
{sidebarCollapsed ? : }
- + {headerTitle}
- {/* 右侧:搜索 + 通知 + 主题切换 + 用户 */} + {/* 右侧:搜索 + 主题切换 + 通知 + 用户 */}
@@ -492,15 +490,11 @@ export default function MainLayout({ children }: { children: React.ReactNode })
- -
setTheme(isDark ? 'blue' : 'dark')}> - {isDark ? : } -
-
+ -
+
@@ -511,7 +505,7 @@ export default function MainLayout({ children }: { children: React.ReactNode }) {(user?.display_name?.[0] || user?.username?.[0] || 'U').toUpperCase()} {!sidebarCollapsed && ( - + {user?.display_name || user?.username || 'User'} )} @@ -526,7 +520,7 @@ export default function MainLayout({ children }: { children: React.ReactNode }) {/* 底部 */} -