From aed83f2ec57f65b5a85250d904a5af2b36603c46 Mon Sep 17 00:00:00 2001 From: dreamhunter2333 Date: Mon, 23 Jun 2025 01:00:53 +0800 Subject: [PATCH] feature: update ux --- package.json | 6 +- pnpm-lock.yaml | 385 ++++++----- public/index.html | 1652 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 1597 insertions(+), 446 deletions(-) diff --git a/package.json b/package.json index 8742052..1025a71 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,12 @@ "cf-typegen": "wrangler types --include-env=false" }, "dependencies": { - "chanfana": "^2.8.0", + "chanfana": "^2.8.1", "hono": "^4.8.2", - "zod": "^3.24.4" + "zod": "^3.25.67" }, "devDependencies": { - "wrangler": "^4.14.2" + "wrangler": "^4.20.5" }, "packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 830e4cd..380d651 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,23 +9,23 @@ importers: .: dependencies: chanfana: - specifier: ^2.8.0 - version: 2.8.0 + specifier: ^2.8.1 + version: 2.8.1 hono: specifier: ^4.8.2 version: 4.8.2 zod: - specifier: ^3.24.4 - version: 3.24.4 + specifier: ^3.25.67 + version: 3.25.67 devDependencies: wrangler: - specifier: ^4.14.2 - version: 4.14.2 + specifier: ^4.20.5 + version: 4.20.5 packages: - '@asteasolutions/zod-to-openapi@7.3.0': - resolution: {integrity: sha512-7tE/r1gXwMIvGnXVUdIqUhCU1RevEFC4Jk6Bussa0fk1ecbnnINkZzj1EOAJyE/M3AI25DnHT/zKQL1/FPFi8Q==} + '@asteasolutions/zod-to-openapi@7.3.4': + resolution: {integrity: sha512-/2rThQ5zPi9OzVwes6U7lK1+Yvug0iXu25olp7S0XsYmOqnyMfxH7gdSQjn/+DSOHRg7wnotwGJSyL+fBKdnEA==} peerDependencies: zod: ^3.20.2 @@ -33,41 +33,41 @@ packages: resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} engines: {node: '>=18.0.0'} - '@cloudflare/unenv-preset@2.3.1': - resolution: {integrity: sha512-Xq57Qd+ADpt6hibcVBO0uLG9zzRgyRhfCUgBT9s+g3+3Ivg5zDyVgLFy40ES1VdNcu8rPNSivm9A+kGP5IVaPg==} + '@cloudflare/unenv-preset@2.3.3': + resolution: {integrity: sha512-/M3MEcj3V2WHIRSW1eAQBPRJ6JnGQHc6JKMAPLkDb7pLs3m6X9ES/+K3ceGqxI6TKeF32AWAi7ls0AYzVxCP0A==} peerDependencies: - unenv: 2.0.0-rc.15 - workerd: ^1.20250320.0 + unenv: 2.0.0-rc.17 + workerd: ^1.20250508.0 peerDependenciesMeta: workerd: optional: true - '@cloudflare/workerd-darwin-64@1.20250428.0': - resolution: {integrity: sha512-6nVe9oV4Hdec6ctzMtW80TiDvNTd2oFPi3VsKqSDVaJSJbL+4b6seyJ7G/UEPI+si6JhHBSLV2/9lNXNGLjClA==} + '@cloudflare/workerd-darwin-64@1.20250617.0': + resolution: {integrity: sha512-toG8JUKVLIks4oOJLe9FeuixE84pDpMZ32ip7mCpE7JaFc5BqGFvevk0YC/db3T71AQlialjRwioH3jS/dzItA==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20250428.0': - resolution: {integrity: sha512-/TB7bh7SIJ5f+6r4PHsAz7+9Qal/TK1cJuKFkUno1kqGlZbdrMwH0ATYwlWC/nBFeu2FB3NUolsTntEuy23hnQ==} + '@cloudflare/workerd-darwin-arm64@1.20250617.0': + resolution: {integrity: sha512-JTX0exbC9/ZtMmQQA8tDZEZFMXZrxOpTUj2hHnsUkErWYkr5SSZH04RBhPg6dU4VL8bXuB5/eJAh7+P9cZAp7g==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20250428.0': - resolution: {integrity: sha512-9eCbj+R3CKqpiXP6DfAA20DxKge+OTj7Hyw3ZewiEhWH9INIHiJwJQYybu4iq9kJEGjnGvxgguLFjSCWm26hgg==} + '@cloudflare/workerd-linux-64@1.20250617.0': + resolution: {integrity: sha512-8jkSoVRJ+1bOx3tuWlZCGaGCV2ew7/jFMl6V3CPXOoEtERUHsZBQLVkQIGKcmC/LKSj7f/mpyBUeu2EPTo2HEg==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20250428.0': - resolution: {integrity: sha512-D9NRBnW46nl1EQsP13qfkYb5lbt4C6nxl38SBKY/NOcZAUoHzNB5K0GaK8LxvpkM7X/97ySojlMfR5jh5DNXYQ==} + '@cloudflare/workerd-linux-arm64@1.20250617.0': + resolution: {integrity: sha512-YAzcOyu897z5dQKFzme1oujGWMGEJCR7/Wrrm1nSP6dqutxFPTubRADM8BHn2CV3ij//vaPnAeLmZE3jVwOwig==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20250428.0': - resolution: {integrity: sha512-RQCRj28eitjKD0tmei6iFOuWqMuHMHdNGEigRmbkmuTlpbWHNAoHikgCzZQ/dkKDdatA76TmcpbyECNf31oaTA==} + '@cloudflare/workerd-windows-64@1.20250617.0': + resolution: {integrity: sha512-XWM/6sagDrO0CYDKhXhPjM23qusvIN1ju9ZEml6gOQs8tNOFnq6Cn6X9FAmnyapRFCGUSEC3HZYJAm7zwVKaMA==} engines: {node: '>=16'} cpu: [x64] os: [win32] @@ -79,152 +79,152 @@ packages: '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} - '@esbuild/aix-ppc64@0.25.2': - resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} + '@esbuild/aix-ppc64@0.25.4': + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.2': - resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} + '@esbuild/android-arm64@0.25.4': + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.2': - resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} + '@esbuild/android-arm@0.25.4': + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.2': - resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} + '@esbuild/android-x64@0.25.4': + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.2': - resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} + '@esbuild/darwin-arm64@0.25.4': + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.2': - resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} + '@esbuild/darwin-x64@0.25.4': + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.2': - resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} + '@esbuild/freebsd-arm64@0.25.4': + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.2': - resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} + '@esbuild/freebsd-x64@0.25.4': + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.2': - resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} + '@esbuild/linux-arm64@0.25.4': + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.2': - resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} + '@esbuild/linux-arm@0.25.4': + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.2': - resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} + '@esbuild/linux-ia32@0.25.4': + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.2': - resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} + '@esbuild/linux-loong64@0.25.4': + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.2': - resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} + '@esbuild/linux-mips64el@0.25.4': + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.2': - resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} + '@esbuild/linux-ppc64@0.25.4': + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.2': - resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} + '@esbuild/linux-riscv64@0.25.4': + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.2': - resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} + '@esbuild/linux-s390x@0.25.4': + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.2': - resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} + '@esbuild/linux-x64@0.25.4': + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.2': - resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} + '@esbuild/netbsd-arm64@0.25.4': + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.2': - resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} + '@esbuild/netbsd-x64@0.25.4': + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.2': - resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} + '@esbuild/openbsd-arm64@0.25.4': + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.2': - resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} + '@esbuild/openbsd-x64@0.25.4': + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.2': - resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} + '@esbuild/sunos-x64@0.25.4': + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.2': - resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} + '@esbuild/win32-arm64@0.25.4': + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.2': - resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} + '@esbuild/win32-ia32@0.25.4': + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.2': - resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} + '@esbuild/win32-x64@0.25.4': + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -366,8 +366,9 @@ packages: blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - chanfana@2.8.0: - resolution: {integrity: sha512-R0lY+c4lBVO8jnop9J5hY6W2Vq5YS3sb9NwI4nY2oJU65E38rC6LCNNhEVEITVmcn+EhuKIQK4FLJLW93gFG4g==} + chanfana@2.8.1: + resolution: {integrity: sha512-iYNlH+pA2yXAV5YksIe/Wewr0b935+jot+cTDqdkyFAae2QzJ2t1t2/ShEMtUjHc8RdDb7IvPCDjZgtMl3Py8A==} + hasBin: true color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -397,8 +398,8 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} - esbuild@0.25.2: - resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} + esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} engines: {node: '>=18'} hasBin: true @@ -406,8 +407,8 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} - exsolve@1.0.5: - resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==} + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} @@ -436,8 +437,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - miniflare@4.20250428.1: - resolution: {integrity: sha512-M3qcJXjeAEimHrEeWXEhrJiC3YHB5M3QSqqK67pOTI+lHn0QyVG/2iFUjVJ/nv+i10uxeAEva8GRGeu+tKRCmQ==} + miniflare@4.20250617.3: + resolution: {integrity: sha512-j+LZycT11UdlVeNdaqD0XdNnYnqAL+wXmboz+tNPFgTq6zhD489Ujj3BfSDyEHDCA9UFBLbkc5ByGWBh+pYZ5Q==} engines: {node: '>=18.0.0'} hasBin: true @@ -460,8 +461,8 @@ packages: printable-characters@1.0.42: resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} hasBin: true @@ -493,20 +494,20 @@ packages: resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} - unenv@2.0.0-rc.15: - resolution: {integrity: sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==} + unenv@2.0.0-rc.17: + resolution: {integrity: sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg==} - workerd@1.20250428.0: - resolution: {integrity: sha512-JJNWkHkwPQKQdvtM9UORijgYdcdJsihA4SfYjwh02IUQsdMyZ9jizV1sX9yWi9B9ptlohTW8UNHJEATuphGgdg==} + workerd@1.20250617.0: + resolution: {integrity: sha512-Uv6p0PYUHp/W/aWfUPLkZVAoAjapisM27JJlwcX9wCPTfCfnuegGOxFMvvlYpmNaX4YCwEdLCwuNn3xkpSkuZw==} engines: {node: '>=16'} hasBin: true - wrangler@4.14.2: - resolution: {integrity: sha512-kD0ilA7WXwhDt1lfyPwppZ2/lT9uwDLp93tfqnqrUENmP/uj+5tErzfZY51emtgXZoU1HFK6HytBEYLRCvCiPg==} + wrangler@4.20.5: + resolution: {integrity: sha512-tmiyt2vBHszhdzJEDbCpFLU2RiV7/QzvGMV07Zaz4ptqiU2h/lTojyNJAugPpSFNiOuY+k0g3ENNTDQqoUkMFA==} engines: {node: '>=18.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20250428.0 + '@cloudflare/workers-types': ^4.20250617.0 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -523,50 +524,54 @@ packages: utf-8-validate: optional: true - yaml@2.7.1: - resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} - engines: {node: '>= 14'} + yaml@2.8.0: + resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + engines: {node: '>= 14.6'} hasBin: true + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + youch@3.3.4: resolution: {integrity: sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==} zod@3.22.3: resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} - zod@3.24.4: - resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} + zod@3.25.67: + resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==} snapshots: - '@asteasolutions/zod-to-openapi@7.3.0(zod@3.24.4)': + '@asteasolutions/zod-to-openapi@7.3.4(zod@3.25.67)': dependencies: openapi3-ts: 4.4.0 - zod: 3.24.4 + zod: 3.25.67 '@cloudflare/kv-asset-handler@0.4.0': dependencies: mime: 3.0.0 - '@cloudflare/unenv-preset@2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250428.0)': + '@cloudflare/unenv-preset@2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250617.0)': dependencies: - unenv: 2.0.0-rc.15 + unenv: 2.0.0-rc.17 optionalDependencies: - workerd: 1.20250428.0 + workerd: 1.20250617.0 - '@cloudflare/workerd-darwin-64@1.20250428.0': + '@cloudflare/workerd-darwin-64@1.20250617.0': optional: true - '@cloudflare/workerd-darwin-arm64@1.20250428.0': + '@cloudflare/workerd-darwin-arm64@1.20250617.0': optional: true - '@cloudflare/workerd-linux-64@1.20250428.0': + '@cloudflare/workerd-linux-64@1.20250617.0': optional: true - '@cloudflare/workerd-linux-arm64@1.20250428.0': + '@cloudflare/workerd-linux-arm64@1.20250617.0': optional: true - '@cloudflare/workerd-windows-64@1.20250428.0': + '@cloudflare/workerd-windows-64@1.20250617.0': optional: true '@cspotcode/source-map-support@0.8.1': @@ -578,79 +583,79 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.2': + '@esbuild/aix-ppc64@0.25.4': optional: true - '@esbuild/android-arm64@0.25.2': + '@esbuild/android-arm64@0.25.4': optional: true - '@esbuild/android-arm@0.25.2': + '@esbuild/android-arm@0.25.4': optional: true - '@esbuild/android-x64@0.25.2': + '@esbuild/android-x64@0.25.4': optional: true - '@esbuild/darwin-arm64@0.25.2': + '@esbuild/darwin-arm64@0.25.4': optional: true - '@esbuild/darwin-x64@0.25.2': + '@esbuild/darwin-x64@0.25.4': optional: true - '@esbuild/freebsd-arm64@0.25.2': + '@esbuild/freebsd-arm64@0.25.4': optional: true - '@esbuild/freebsd-x64@0.25.2': + '@esbuild/freebsd-x64@0.25.4': optional: true - '@esbuild/linux-arm64@0.25.2': + '@esbuild/linux-arm64@0.25.4': optional: true - '@esbuild/linux-arm@0.25.2': + '@esbuild/linux-arm@0.25.4': optional: true - '@esbuild/linux-ia32@0.25.2': + '@esbuild/linux-ia32@0.25.4': optional: true - '@esbuild/linux-loong64@0.25.2': + '@esbuild/linux-loong64@0.25.4': optional: true - '@esbuild/linux-mips64el@0.25.2': + '@esbuild/linux-mips64el@0.25.4': optional: true - '@esbuild/linux-ppc64@0.25.2': + '@esbuild/linux-ppc64@0.25.4': optional: true - '@esbuild/linux-riscv64@0.25.2': + '@esbuild/linux-riscv64@0.25.4': optional: true - '@esbuild/linux-s390x@0.25.2': + '@esbuild/linux-s390x@0.25.4': optional: true - '@esbuild/linux-x64@0.25.2': + '@esbuild/linux-x64@0.25.4': optional: true - '@esbuild/netbsd-arm64@0.25.2': + '@esbuild/netbsd-arm64@0.25.4': optional: true - '@esbuild/netbsd-x64@0.25.2': + '@esbuild/netbsd-x64@0.25.4': optional: true - '@esbuild/openbsd-arm64@0.25.2': + '@esbuild/openbsd-arm64@0.25.4': optional: true - '@esbuild/openbsd-x64@0.25.2': + '@esbuild/openbsd-x64@0.25.4': optional: true - '@esbuild/sunos-x64@0.25.2': + '@esbuild/sunos-x64@0.25.4': optional: true - '@esbuild/win32-arm64@0.25.2': + '@esbuild/win32-arm64@0.25.4': optional: true - '@esbuild/win32-ia32@0.25.2': + '@esbuild/win32-ia32@0.25.4': optional: true - '@esbuild/win32-x64@0.25.2': + '@esbuild/win32-x64@0.25.4': optional: true '@fastify/busboy@2.1.1': {} @@ -751,32 +756,29 @@ snapshots: blake3-wasm@2.1.5: {} - chanfana@2.8.0: + chanfana@2.8.1: dependencies: - '@asteasolutions/zod-to-openapi': 7.3.0(zod@3.24.4) + '@asteasolutions/zod-to-openapi': 7.3.4(zod@3.25.67) js-yaml: 4.1.0 openapi3-ts: 4.4.0 - zod: 3.24.4 + yargs-parser: 22.0.0 + zod: 3.25.67 color-convert@2.0.1: dependencies: color-name: 1.1.4 - optional: true - color-name@1.1.4: - optional: true + color-name@1.1.4: {} color-string@1.9.1: dependencies: color-name: 1.1.4 simple-swizzle: 0.2.2 - optional: true color@4.2.3: dependencies: color-convert: 2.0.1 color-string: 1.9.1 - optional: true cookie@0.7.2: {} @@ -784,40 +786,39 @@ snapshots: defu@6.1.4: {} - detect-libc@2.0.4: - optional: true + detect-libc@2.0.4: {} - esbuild@0.25.2: + esbuild@0.25.4: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.2 - '@esbuild/android-arm': 0.25.2 - '@esbuild/android-arm64': 0.25.2 - '@esbuild/android-x64': 0.25.2 - '@esbuild/darwin-arm64': 0.25.2 - '@esbuild/darwin-x64': 0.25.2 - '@esbuild/freebsd-arm64': 0.25.2 - '@esbuild/freebsd-x64': 0.25.2 - '@esbuild/linux-arm': 0.25.2 - '@esbuild/linux-arm64': 0.25.2 - '@esbuild/linux-ia32': 0.25.2 - '@esbuild/linux-loong64': 0.25.2 - '@esbuild/linux-mips64el': 0.25.2 - '@esbuild/linux-ppc64': 0.25.2 - '@esbuild/linux-riscv64': 0.25.2 - '@esbuild/linux-s390x': 0.25.2 - '@esbuild/linux-x64': 0.25.2 - '@esbuild/netbsd-arm64': 0.25.2 - '@esbuild/netbsd-x64': 0.25.2 - '@esbuild/openbsd-arm64': 0.25.2 - '@esbuild/openbsd-x64': 0.25.2 - '@esbuild/sunos-x64': 0.25.2 - '@esbuild/win32-arm64': 0.25.2 - '@esbuild/win32-ia32': 0.25.2 - '@esbuild/win32-x64': 0.25.2 + '@esbuild/aix-ppc64': 0.25.4 + '@esbuild/android-arm': 0.25.4 + '@esbuild/android-arm64': 0.25.4 + '@esbuild/android-x64': 0.25.4 + '@esbuild/darwin-arm64': 0.25.4 + '@esbuild/darwin-x64': 0.25.4 + '@esbuild/freebsd-arm64': 0.25.4 + '@esbuild/freebsd-x64': 0.25.4 + '@esbuild/linux-arm': 0.25.4 + '@esbuild/linux-arm64': 0.25.4 + '@esbuild/linux-ia32': 0.25.4 + '@esbuild/linux-loong64': 0.25.4 + '@esbuild/linux-mips64el': 0.25.4 + '@esbuild/linux-ppc64': 0.25.4 + '@esbuild/linux-riscv64': 0.25.4 + '@esbuild/linux-s390x': 0.25.4 + '@esbuild/linux-x64': 0.25.4 + '@esbuild/netbsd-arm64': 0.25.4 + '@esbuild/netbsd-x64': 0.25.4 + '@esbuild/openbsd-arm64': 0.25.4 + '@esbuild/openbsd-x64': 0.25.4 + '@esbuild/sunos-x64': 0.25.4 + '@esbuild/win32-arm64': 0.25.4 + '@esbuild/win32-ia32': 0.25.4 + '@esbuild/win32-x64': 0.25.4 exit-hook@2.2.1: {} - exsolve@1.0.5: {} + exsolve@1.0.7: {} fsevents@2.3.3: optional: true @@ -831,8 +832,7 @@ snapshots: hono@4.8.2: {} - is-arrayish@0.3.2: - optional: true + is-arrayish@0.3.2: {} js-yaml@4.1.0: dependencies: @@ -840,16 +840,17 @@ snapshots: mime@3.0.0: {} - miniflare@4.20250428.1: + miniflare@4.20250617.3: dependencies: '@cspotcode/source-map-support': 0.8.1 acorn: 8.14.0 acorn-walk: 8.3.2 exit-hook: 2.2.1 glob-to-regexp: 0.4.1 + sharp: 0.33.5 stoppable: 1.1.0 undici: 5.29.0 - workerd: 1.20250428.0 + workerd: 1.20250617.0 ws: 8.18.0 youch: 3.3.4 zod: 3.22.3 @@ -863,7 +864,7 @@ snapshots: openapi3-ts@4.4.0: dependencies: - yaml: 2.7.1 + yaml: 2.8.0 path-to-regexp@6.3.0: {} @@ -871,14 +872,13 @@ snapshots: printable-characters@1.0.42: {} - semver@7.7.1: - optional: true + semver@7.7.2: {} sharp@0.33.5: dependencies: color: 4.2.3 detect-libc: 2.0.4 - semver: 7.7.1 + semver: 7.7.2 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.5 '@img/sharp-darwin-x64': 0.33.5 @@ -899,12 +899,10 @@ snapshots: '@img/sharp-wasm32': 0.33.5 '@img/sharp-win32-ia32': 0.33.5 '@img/sharp-win32-x64': 0.33.5 - optional: true simple-swizzle@0.2.2: dependencies: is-arrayish: 0.3.2 - optional: true source-map@0.6.1: {} @@ -924,42 +922,43 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 - unenv@2.0.0-rc.15: + unenv@2.0.0-rc.17: dependencies: defu: 6.1.4 - exsolve: 1.0.5 + exsolve: 1.0.7 ohash: 2.0.11 pathe: 2.0.3 ufo: 1.6.1 - workerd@1.20250428.0: + workerd@1.20250617.0: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20250428.0 - '@cloudflare/workerd-darwin-arm64': 1.20250428.0 - '@cloudflare/workerd-linux-64': 1.20250428.0 - '@cloudflare/workerd-linux-arm64': 1.20250428.0 - '@cloudflare/workerd-windows-64': 1.20250428.0 + '@cloudflare/workerd-darwin-64': 1.20250617.0 + '@cloudflare/workerd-darwin-arm64': 1.20250617.0 + '@cloudflare/workerd-linux-64': 1.20250617.0 + '@cloudflare/workerd-linux-arm64': 1.20250617.0 + '@cloudflare/workerd-windows-64': 1.20250617.0 - wrangler@4.14.2: + wrangler@4.20.5: dependencies: '@cloudflare/kv-asset-handler': 0.4.0 - '@cloudflare/unenv-preset': 2.3.1(unenv@2.0.0-rc.15)(workerd@1.20250428.0) + '@cloudflare/unenv-preset': 2.3.3(unenv@2.0.0-rc.17)(workerd@1.20250617.0) blake3-wasm: 2.1.5 - esbuild: 0.25.2 - miniflare: 4.20250428.1 + esbuild: 0.25.4 + miniflare: 4.20250617.3 path-to-regexp: 6.3.0 - unenv: 2.0.0-rc.15 - workerd: 1.20250428.0 + unenv: 2.0.0-rc.17 + workerd: 1.20250617.0 optionalDependencies: fsevents: 2.3.3 - sharp: 0.33.5 transitivePeerDependencies: - bufferutil - utf-8-validate ws@8.18.0: {} - yaml@2.7.1: {} + yaml@2.8.0: {} + + yargs-parser@22.0.0: {} youch@3.3.4: dependencies: @@ -969,4 +968,4 @@ snapshots: zod@3.22.3: {} - zod@3.24.4: {} + zod@3.25.67: {} diff --git a/public/index.html b/public/index.html index 4633772..fcdbccb 100644 --- a/public/index.html +++ b/public/index.html @@ -43,12 +43,12 @@ } .header h1 { - font-size: 2.5rem; + font-size: 1.8rem; margin-bottom: 10px; } .header.compact h1 { - font-size: 1.8rem; + font-size: 1.4rem; margin-bottom: 5px; } @@ -143,12 +143,12 @@ .tab { flex: 1; - padding: 15px 20px; + padding: 12px 16px; text-align: center; cursor: pointer; border: none; background: none; - font-size: 16px; + font-size: 14px; transition: all 0.3s; } @@ -175,13 +175,13 @@ .btn { background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%); color: white; - border: none; - padding: 12px 24px; + border: 2px solid transparent; + padding: 8px 16px; border-radius: 6px; cursor: pointer; - font-size: 14px; + font-size: 13px; transition: all 0.3s; - margin: 5px; + margin: 4px; } .btn:hover { @@ -189,14 +189,48 @@ box-shadow: 0 5px 15px rgba(76, 81, 191, 0.4); } + .btn-secondary { + background: transparent; + color: #4c51bf; + border: 2px solid #4c51bf; + } + + .btn-secondary:hover { + background: rgba(76, 81, 191, 0.1); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(76, 81, 191, 0.2); + } + + .btn-secondary.btn-warning { + background: transparent; + color: #ed8936; + border: 2px solid #ed8936; + } + + .btn-secondary.btn-warning:hover { + background: rgba(237, 137, 54, 0.1); + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(237, 137, 54, 0.2); + } + .btn-danger { background: linear-gradient(135deg, #e53e3e 0%, #c53030 100%); + border: 2px solid transparent; } .btn-danger:hover { box-shadow: 0 5px 15px rgba(229, 62, 62, 0.4); } + .btn-warning { + background: linear-gradient(135deg, #ed8936 0%, #dd6b20 100%); + border: 2px solid transparent; + } + + .btn-warning:hover { + box-shadow: 0 5px 15px rgba(237, 137, 54, 0.4); + } + .form-group { margin-bottom: 20px; } @@ -206,6 +240,7 @@ margin-bottom: 8px; font-weight: 600; color: #2d3748; + font-size: 14px; } .form-control { @@ -222,6 +257,11 @@ border-color: #4c51bf; } + select.form-control { + cursor: pointer; + background-color: white; + } + textarea.form-control { resize: vertical; min-height: 100px; @@ -253,7 +293,7 @@ } .card-title { - font-size: 1.25rem; + font-size: 1.1rem; font-weight: 600; color: #2d3748; } @@ -339,6 +379,7 @@ border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); animation: slideInDown 0.3s ease-out; + text-align: center; } @keyframes slideInDown { @@ -371,6 +412,66 @@ color: #718096; } + /* mainContent loading 覆盖层样式 */ + #loadingOverlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(4px); + z-index: 10002; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: white; + opacity: 0; + transition: opacity 0.3s ease-in-out; + pointer-events: auto; + cursor: wait; + } + + /* 当 loading 显示时,禁用 mainContent 交互 */ + #mainContent.loading-active { + position: relative; + pointer-events: none; + } + + #mainContent.loading-active #loadingOverlay { + pointer-events: auto; + } + + #loadingOverlay .spinner { + border: 4px solid rgba(255, 255, 255, 0.3); + border-top: 4px solid #ffffff; + border-radius: 50%; + width: 40px; + height: 40px; + animation: spin 1s linear infinite; + margin: 0 auto 20px; + } + + #loadingOverlay p { + margin-top: 20px; + font-size: 16px; + font-weight: 500; + animation: pulse 2s ease-in-out infinite; + } + + @keyframes pulse { + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.7; + } + } + .spinner { border: 4px solid #f3f3f3; border-top: 4px solid #4c51bf; @@ -397,6 +498,106 @@ gap: 20px; } + .pricing-table { + overflow-x: auto; + } + + .pricing-table table { + min-width: 600px; + } + + .pricing-table input[type="text"], + .pricing-table input[type="number"] { + width: 100%; + border: none; + background: transparent; + padding: 8px; + font-size: 14px; + } + + .pricing-table input[type="text"]:focus, + .pricing-table input[type="number"]:focus { + outline: 2px solid #4c51bf; + outline-offset: -2px; + border-radius: 4px; + background: white; + } + + .pricing-table tr:hover { + background-color: #f8f9fa; + } + + /* 模态框样式 */ + .modal { + display: none; + position: fixed; + z-index: 10000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(4px); + } + + .modal-content { + background-color: white; + margin: 10% auto; + padding: 0; + border-radius: 12px; + width: 90%; + max-width: 500px; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); + animation: modalSlideIn 0.3s ease-out; + } + + @keyframes modalSlideIn { + from { + opacity: 0; + transform: translateY(-50px); + } + + to { + opacity: 1; + transform: translateY(0); + } + } + + .modal-header { + background: linear-gradient(135deg, #4c51bf 0%, #553c9a 100%); + color: white; + padding: 20px; + border-radius: 12px 12px 0 0; + position: relative; + } + + .modal-title { + font-size: 1.5rem; + font-weight: 600; + margin: 0; + } + + .modal-close { + position: absolute; + top: 15px; + right: 20px; + background: none; + border: none; + color: white; + font-size: 24px; + cursor: pointer; + opacity: 0.8; + transition: opacity 0.3s; + } + + .modal-close:hover { + opacity: 1; + } + + .modal-body { + padding: 30px; + } + @media (max-width: 768px) { .grid { grid-template-columns: 1fr; @@ -428,16 +629,34 @@ } .header h1 { - font-size: 2rem; + font-size: 1.6rem; } .header.compact h1 { - font-size: 1.5rem; + font-size: 1.2rem; } .auth-section { padding: 40px 20px; } + + /* 登录提示在移动端的样式优化 */ + #loginPrompt>div { + flex-direction: column !important; + gap: 10px !important; + } + + #loginPrompt>div>div:last-child { + margin-top: 0 !important; + width: 100%; + text-align: center; + flex-shrink: 1 !important; + } + + #loginPrompt>div>div:first-child { + min-width: auto !important; + text-align: center; + } } @@ -452,12 +671,14 @@

🚀 Awsl One API

管理面板 - 频道、令牌、定价管理

-
+ - @@ -1208,64 +2019,289 @@ // === PRICING FUNCTIONS === - // Pricing functions - async function loadPricing() { - try { - const pricing = await apiRequest('/api/admin/pricing'); - // 成功时显示表单 - document.getElementById('pricingContent').innerHTML = ` -
- - - - 配置格式:模型名称 -> {input: 输入倍率, output: 输出倍率}。倍率基于1百万token=$1.00计算 - -
- `; - document.getElementById('pricingConfig').value = JSON.stringify(pricing, null, 2); - } catch (error) { - // 失败时显示错误信息,参考频道管理的方式 - document.getElementById('pricingContent').innerHTML = `
加载定价配置失败: ${error.message}
`; + // 切换定价编辑模式 + function togglePricingEditMode() { + const tableMode = document.getElementById('pricingTableMode'); + const jsonMode = document.getElementById('pricingJsonMode'); + const toggleBtn = document.getElementById('pricingModeToggle'); + const addBtn = document.getElementById('addPricingModelBtn'); + + if (pricingEditMode === 'table') { + // 切换到JSON模式 + const config = collectPricingTableData(); + document.getElementById('pricingConfigJson').value = JSON.stringify(config, null, 2); + + tableMode.style.display = 'none'; + jsonMode.style.display = 'block'; + if (addBtn) addBtn.style.display = 'none'; // 隐藏添加模型按钮 + toggleBtn.textContent = '📊 切换到表格模式'; + pricingEditMode = 'json'; + } else { + // 切换到表格模式 + try { + const jsonValue = document.getElementById('pricingConfigJson').value; + if (jsonValue) { + const parsed = JSON.parse(jsonValue); + displayPricingTable(parsed); + } + } catch (error) { + console.warn('JSON格式错误,无法转换到表格模式:', error); + } + + tableMode.style.display = 'block'; + jsonMode.style.display = 'none'; + if (addBtn) addBtn.style.display = 'inline-block'; // 显示添加模型按钮 + toggleBtn.textContent = '📝 切换到JSON模式'; + pricingEditMode = 'table'; } } - async function updatePricing() { - const pricingConfigElement = document.getElementById('pricingConfig'); + // 收集定价表格数据 + function collectPricingTableData() { + const tbody = document.getElementById('pricingTableBody'); + const config = {}; - // 如果因为加载失败导致textarea不存在,先重新创建表单 - if (!pricingConfigElement) { - document.getElementById('pricingContent').innerHTML = ` -
- - - - 配置格式:模型名称 -> {input: 输入倍率, output: 输出倍率}。倍率基于1百万token=$1.00计算 - -
- `; + if (!tbody) return config; + + Array.from(tbody.children).forEach((row) => { + const inputs = row.querySelectorAll('input'); + if (inputs.length < 3) return; + + const modelName = inputs[0].value.trim(); + const inputPrice = parseFloat(inputs[1].value) || 0; + const outputPrice = parseFloat(inputs[2].value) || 0; + + if (modelName) { + config[modelName] = { + input: inputPrice, + output: outputPrice + }; + } + }); + + return config; + } + + // 添加新的定价模型行 + function addPricingModel() { + const tbody = document.getElementById('pricingTableBody'); + const rowIndex = tbody.children.length; + + const row = document.createElement('tr'); + row.style.borderBottom = '1px solid #e9ecef'; + row.innerHTML = ` + + + + + + + + + + + + + `; + tbody.appendChild(row); + } + + // 删除定价模型行 + function removePricingRow(button) { + const row = button.closest('tr'); + row.remove(); + } + + // 验证定价行数据 + function validatePricingRow(rowIndex) { + // 这里可以添加验证逻辑,比如检查模型名称是否重复等 + } + + // Pricing functions + async function loadPricing() { + try { + const pricing = await apiRequest('/api/admin/pricing', 'GET', null, true); + const addBtn = document.getElementById('addPricingModelBtn'); + + if (pricingEditMode === 'table') { + displayPricingTable(pricing); + if (addBtn) addBtn.style.display = 'inline-block'; + } else { + document.getElementById('pricingConfigJson').value = JSON.stringify(pricing, null, 2); + if (addBtn) addBtn.style.display = 'none'; + } + } catch (error) { + // 失败时显示错误信息 + if (pricingEditMode === 'table') { + document.getElementById('pricingContent').innerHTML = ` +
加载定价配置失败: ${error.message}
+
+ + + + + + + + + + + + +
模型名称输入倍率输出倍率操作
+
+ + `; + } else { + showAlert(`加载定价配置失败: ${error.message}`, 'error'); + } } + } - const configText = document.getElementById('pricingConfig').value; + // 显示定价配置表格 + function displayPricingTable(pricing) { + const tbody = document.getElementById('pricingTableBody'); + if (!tbody) return; - if (!configText) { - showAlert('请填写定价配置', 'error'); + tbody.innerHTML = ''; + + // 如果没有定价数据,添加一行空白行 + if (!pricing || Object.keys(pricing).length === 0) { + addPricingModel(); return; } + // 为每个模型创建一行 + Object.entries(pricing).forEach(([modelName, modelPricing]) => { + const row = document.createElement('tr'); + row.style.borderBottom = '1px solid #e9ecef'; + + const inputPrice = modelPricing.input || 0; + const outputPrice = modelPricing.output || 0; + + row.innerHTML = ` + + + + + + + + + + + + + `; + tbody.appendChild(row); + }); + } + + async function updatePricing() { + let config; + + if (pricingEditMode === 'table') { + // 表格模式 + const tbody = document.getElementById('pricingTableBody'); + + if (!tbody) { + showAlert('定价表格未找到,请刷新页面重试', 'error'); + return; + } + + config = {}; + let hasError = false; + let errorMessage = ''; + + // 遍历所有行收集数据 + Array.from(tbody.children).forEach((row, index) => { + const inputs = row.querySelectorAll('input'); + if (inputs.length < 3) return; + + const modelName = inputs[0].value.trim(); + const inputPrice = parseFloat(inputs[1].value); + const outputPrice = parseFloat(inputs[2].value); + + // 验证数据 + if (!modelName) { + hasError = true; + errorMessage = `第 ${index + 1} 行:模型名称不能为空`; + return; + } + + if (isNaN(inputPrice) || inputPrice < 0) { + hasError = true; + errorMessage = `第 ${index + 1} 行:输入倍率必须是有效的非负数`; + return; + } + + if (isNaN(outputPrice) || outputPrice < 0) { + hasError = true; + errorMessage = `第 ${index + 1} 行:输出倍率必须是有效的非负数`; + return; + } + + // 检查模型名称是否重复 + if (config[modelName]) { + hasError = true; + errorMessage = `模型名称 "${modelName}" 重复`; + return; + } + + config[modelName] = { + input: inputPrice, + output: outputPrice + }; + }); + + if (hasError) { + showAlert(errorMessage, 'error'); + return; + } + + if (Object.keys(config).length === 0) { + showAlert('请至少添加一个模型的定价配置', 'error'); + return; + } + } else { + // JSON模式 + const configText = document.getElementById('pricingConfigJson').value.trim(); + + if (!configText) { + showAlert('请填写定价配置', 'error'); + return; + } + + try { + config = JSON.parse(configText); + } catch (error) { + showAlert('配置格式错误,请检查JSON格式', 'error'); + return; + } + } + try { - const config = JSON.parse(configText); - await apiRequest('/api/admin/pricing', 'POST', config); + await apiRequest('/api/admin/pricing', 'POST', config, true, '正在更新定价配置...'); showAlert('定价配置更新成功!', 'success'); // 更新成功后重新加载配置 loadPricing(); } catch (error) { - if (error.message.includes('JSON')) { - showAlert('配置格式错误,请检查JSON格式', 'error'); - } else { - showAlert(`更新定价配置失败: ${error.message}`, 'error'); - } + showAlert(`更新定价配置失败: ${error.message}`, 'error'); } } @@ -1366,6 +2402,7 @@ } // === UTILITY FUNCTIONS === + function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { showAlert('已复制到剪贴板', 'success', 2000); @@ -1399,32 +2436,129 @@ }, duration); } - function showLoading(message) { - const loadingDiv = document.createElement('div'); - loadingDiv.id = 'loadingOverlay'; - loadingDiv.className = 'loading'; - loadingDiv.innerHTML = ` -
-

${message}

- `; + // Loading 管理对象 + const LoadingManager = { + delayTimer: null, + minShowTimer: null, + loadingElement: null, + showStartTime: null, + showDelay: 200, // 延迟 200ms 显示,避免快速请求的闪烁 + minShowDuration: 500, // 最小显示时长 500ms,避免一闪而过 - document.body.appendChild(loadingDiv); + show(message) { + // 如果已存在 loading,先清理 + this.hide(); + + // 设置延迟显示 + this.delayTimer = setTimeout(() => { + this._showLoading(message); + }, this.showDelay); + }, + + _showLoading(message) { + const mainContent = document.getElementById('mainContent'); + if (!mainContent) return; + + // 记录显示开始时间 + this.showStartTime = Date.now(); + + // 添加 loading 状态类 + mainContent.classList.add('loading-active'); + + // 创建 loading 元素 + const loadingDiv = document.createElement('div'); + loadingDiv.id = 'loadingOverlay'; + loadingDiv.innerHTML = ` +
+

${message}

+ `; + + // 初始设置为透明,准备淡入动画 + loadingDiv.style.opacity = '0'; + mainContent.appendChild(loadingDiv); + + this.loadingElement = loadingDiv; + + // 触发淡入动画 + requestAnimationFrame(() => { + loadingDiv.style.opacity = '1'; + }); + }, + + hide() { + // 清除延迟显示定时器 + if (this.delayTimer) { + clearTimeout(this.delayTimer); + this.delayTimer = null; + } + + // 如果 loading 还没有显示,直接返回 + if (!this.loadingElement) { + return; + } + + // 计算已显示时长 + const showDuration = Date.now() - this.showStartTime; + const remainingMinShowTime = Math.max(0, this.minShowDuration - showDuration); + + // 如果还没达到最小显示时长,延迟隐藏 + if (remainingMinShowTime > 0) { + this.minShowTimer = setTimeout(() => { + this._hideLoading(); + }, remainingMinShowTime); + } else { + this._hideLoading(); + } + }, + + _hideLoading() { + // 清除最小显示定时器 + if (this.minShowTimer) { + clearTimeout(this.minShowTimer); + this.minShowTimer = null; + } + + if (this.loadingElement) { + // 淡出动画 + this.loadingElement.style.opacity = '0'; + + // 等待动画完成后移除元素 + setTimeout(() => { + if (this.loadingElement) { + this.loadingElement.remove(); + this.loadingElement = null; + } + + // 移除 loading 状态类 + const mainContent = document.getElementById('mainContent'); + if (mainContent) { + mainContent.classList.remove('loading-active'); + } + }, 300); // 与 CSS transition 时间匹配 + } + + this.showStartTime = null; + } + }; + + // 保持原有的函数接口,以兼容现有代码 + function showLoading(message) { + LoadingManager.show(message); } function hideLoading() { - const loadingDiv = document.getElementById('loadingOverlay'); - if (loadingDiv) { - loadingDiv.remove(); - } + LoadingManager.hide(); } // Initialize on page load document.addEventListener('DOMContentLoaded', function () { - console.log('Awsl One API 管理面板已加载'); const savedToken = localStorage.getItem('adminToken'); if (savedToken) { adminToken = savedToken; showMainContent(); + } else { + // 默认显示首页(未登录状态) + showHomePage(); } // 为登录输入框添加回车键监听 @@ -1437,6 +2571,24 @@ }); } }); + + // 点击模态框外部关闭 + window.onclick = function (event) { + const modal = document.getElementById('loginModal'); + if (event.target == modal) { + closeLoginModal(); + } + } + + // 添加ESC键关闭模态框 + document.addEventListener('keydown', function (event) { + if (event.key === 'Escape') { + const modal = document.getElementById('loginModal'); + if (modal.style.display === 'block') { + closeLoginModal(); + } + } + });