ai-agent-router 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +4 -1
- package/.next/build/chunks/{[root-of-the-server]__6d51cb5d._.js → [root-of-the-server]__0iv9ksq._.js} +1 -1
- package/.next/build/chunks/[root-of-the-server]__0iv9ksq._.js.map +8 -0
- package/.next/build/chunks/{[root-of-the-server]__44695d76._.js → [root-of-the-server]__0rua-~2._.js} +30 -30
- package/.next/build/chunks/[root-of-the-server]__0rua-~2._.js.map +11 -0
- package/.next/build/chunks/{[turbopack-node]_transforms_postcss_ts_df7a5b11._.js → [turbopack-node]_transforms_postcss_ts_0nnejqq._.js} +2 -2
- package/.next/build/chunks/[turbopack]_runtime.js +155 -60
- package/.next/build/chunks/[turbopack]_runtime.js.map +6 -5
- package/.next/build/chunks/{node_modules_fe693df6._.js → node_modules_13sb.px._.js} +1 -1
- package/.next/build/chunks/{node_modules_fe693df6._.js.map → node_modules_13sb.px._.js.map} +42 -42
- package/.next/build/postcss.js +5 -5
- package/.next/build-manifest.json +8 -7
- package/.next/diagnostics/framework.json +1 -1
- package/.next/diagnostics/route-bundle-stats.json +93 -0
- package/.next/fallback-build-manifest.json +3 -2
- package/.next/images-manifest.json +1 -0
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +33 -9
- package/.next/required-server-files.js +18 -6
- package/.next/required-server-files.json +18 -6
- package/.next/routes-manifest.json +19 -0
- package/.next/server/app/_global-error/page/build-manifest.json +5 -5
- package/.next/server/app/_global-error/page.js +8 -9
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error/page_client-reference-manifest.js +2 -1
- package/.next/server/app/_global-error.html +1 -2
- package/.next/server/app/_global-error.rsc +11 -9
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_global-error.segments/_full.segment.rsc +11 -9
- package/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/server/app/_global-error.segments/_index.segment.rsc +4 -3
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page/build-manifest.json +5 -5
- package/.next/server/app/_not-found/page.js +11 -12
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +2 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +13 -11
- package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -11
- package/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +4 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/config/route/build-manifest.json +1 -3
- package/.next/server/app/api/config/route.js +4 -4
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/config/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/gateway/[...path]/route/build-manifest.json +1 -3
- package/.next/server/app/api/gateway/[...path]/route.js +5 -5
- package/.next/server/app/api/gateway/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/gateway/[...path]/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/gateway/models/route/build-manifest.json +1 -3
- package/.next/server/app/api/gateway/models/route.js +4 -4
- package/.next/server/app/api/gateway/models/route.js.nft.json +1 -1
- package/.next/server/app/api/gateway/models/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/gateway/route/build-manifest.json +1 -3
- package/.next/server/app/api/gateway/route.js +5 -5
- package/.next/server/app/api/gateway/route.js.nft.json +1 -1
- package/.next/server/app/api/gateway/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/claude/apply/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/claude/apply/route.js +4 -4
- package/.next/server/app/api/ide/claude/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/claude/apply/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/claude/available-models/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/claude/available-models/route.js +4 -4
- package/.next/server/app/api/ide/claude/available-models/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/claude/available-models/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/claude/restore/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/claude/restore/route.js +3 -3
- package/.next/server/app/api/ide/claude/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/claude/restore/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/claude/save/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/claude/save/route.js +4 -4
- package/.next/server/app/api/ide/claude/save/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/claude/save/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/claude/status/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/claude/status/route.js +4 -4
- package/.next/server/app/api/ide/claude/status/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/claude/status/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/claude/test/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/claude/test/route.js +5 -5
- package/.next/server/app/api/ide/claude/test/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/claude/test/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/apply/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/apply/route.js +4 -4
- package/.next/server/app/api/ide/openclaw/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/apply/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/available-models/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/available-models/route.js +4 -4
- package/.next/server/app/api/ide/openclaw/available-models/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/available-models/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/preview/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/preview/route.js +4 -4
- package/.next/server/app/api/ide/openclaw/preview/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/preview/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/restore/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/restore/route.js +3 -3
- package/.next/server/app/api/ide/openclaw/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/restore/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/save/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/save/route.js +4 -4
- package/.next/server/app/api/ide/openclaw/save/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/save/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/status/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/status/route.js +4 -4
- package/.next/server/app/api/ide/openclaw/status/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/status/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/openclaw/test/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/openclaw/test/route.js +3 -3
- package/.next/server/app/api/ide/openclaw/test/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/openclaw/test/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/apply/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/apply/route.js +4 -4
- package/.next/server/app/api/ide/opencode/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/apply/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/available-models/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/available-models/route.js +4 -4
- package/.next/server/app/api/ide/opencode/available-models/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/available-models/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/preview/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/preview/route.js +4 -4
- package/.next/server/app/api/ide/opencode/preview/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/preview/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/restore/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/restore/route.js +3 -3
- package/.next/server/app/api/ide/opencode/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/restore/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/save/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/save/route.js +4 -4
- package/.next/server/app/api/ide/opencode/save/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/save/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/status/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/status/route.js +4 -4
- package/.next/server/app/api/ide/opencode/status/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/status/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/ide/opencode/test/route/build-manifest.json +1 -3
- package/.next/server/app/api/ide/opencode/test/route.js +3 -3
- package/.next/server/app/api/ide/opencode/test/route.js.nft.json +1 -1
- package/.next/server/app/api/ide/opencode/test/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/logs/route/build-manifest.json +1 -3
- package/.next/server/app/api/logs/route.js +4 -4
- package/.next/server/app/api/logs/route.js.nft.json +1 -1
- package/.next/server/app/api/logs/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/models/route/build-manifest.json +1 -3
- package/.next/server/app/api/models/route.js +5 -5
- package/.next/server/app/api/models/route.js.nft.json +1 -1
- package/.next/server/app/api/models/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/providers/route/build-manifest.json +1 -3
- package/.next/server/app/api/providers/route.js +5 -5
- package/.next/server/app/api/providers/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/providers/test/route/build-manifest.json +1 -3
- package/.next/server/app/api/providers/test/route.js +5 -5
- package/.next/server/app/api/providers/test/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/test/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/service/force-stop/route/build-manifest.json +1 -3
- package/.next/server/app/api/service/force-stop/route.js +4 -4
- package/.next/server/app/api/service/force-stop/route.js.nft.json +1 -1
- package/.next/server/app/api/service/force-stop/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/service/start/route/build-manifest.json +1 -3
- package/.next/server/app/api/service/start/route.js +4 -4
- package/.next/server/app/api/service/start/route.js.nft.json +1 -1
- package/.next/server/app/api/service/start/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/service/status/route/build-manifest.json +1 -3
- package/.next/server/app/api/service/status/route.js +4 -4
- package/.next/server/app/api/service/status/route.js.nft.json +1 -1
- package/.next/server/app/api/service/status/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/service/stop/route/build-manifest.json +1 -3
- package/.next/server/app/api/service/stop/route.js +4 -4
- package/.next/server/app/api/service/stop/route.js.nft.json +1 -1
- package/.next/server/app/api/service/stop/route_client-reference-manifest.js +2 -1
- package/.next/server/app/api/tokenizer/history/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/tokenizer/history/route/build-manifest.json +9 -0
- package/.next/server/app/api/tokenizer/history/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/tokenizer/history/route.js +7 -0
- package/.next/server/app/api/tokenizer/history/route.js.map +5 -0
- package/.next/server/app/api/tokenizer/history/route.js.nft.json +1 -0
- package/.next/server/app/api/tokenizer/history/route_client-reference-manifest.js +3 -0
- package/.next/server/app/api/tokenizer/test/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/tokenizer/test/route/build-manifest.json +9 -0
- package/.next/server/app/api/tokenizer/test/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/tokenizer/test/route.js +8 -0
- package/.next/server/app/api/tokenizer/test/route.js.map +5 -0
- package/.next/server/app/api/tokenizer/test/route.js.nft.json +1 -0
- package/.next/server/app/api/tokenizer/test/route_client-reference-manifest.js +3 -0
- package/.next/server/app/ide/page/build-manifest.json +5 -5
- package/.next/server/app/ide/page.js +12 -14
- package/.next/server/app/ide/page.js.nft.json +1 -1
- package/.next/server/app/ide/page_client-reference-manifest.js +2 -1
- package/.next/server/app/ide.html +1 -1
- package/.next/server/app/ide.rsc +15 -13
- package/.next/server/app/ide.segments/_full.segment.rsc +15 -13
- package/.next/server/app/ide.segments/_head.segment.rsc +3 -3
- package/.next/server/app/ide.segments/_index.segment.rsc +5 -5
- package/.next/server/app/ide.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/ide.segments/ide/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/ide.segments/ide.segment.rsc +4 -3
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +11 -11
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/index.segments/_full.segment.rsc +11 -11
- package/.next/server/app/index.segments/_head.segment.rsc +3 -3
- package/.next/server/app/index.segments/_index.segment.rsc +5 -5
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs/page/build-manifest.json +5 -5
- package/.next/server/app/logs/page.js +12 -14
- package/.next/server/app/logs/page.js.nft.json +1 -1
- package/.next/server/app/logs/page_client-reference-manifest.js +2 -1
- package/.next/server/app/logs.html +1 -1
- package/.next/server/app/logs.rsc +15 -13
- package/.next/server/app/logs.segments/_full.segment.rsc +15 -13
- package/.next/server/app/logs.segments/_head.segment.rsc +3 -3
- package/.next/server/app/logs.segments/_index.segment.rsc +5 -5
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/logs.segments/logs.segment.rsc +4 -3
- package/.next/server/app/models/page/build-manifest.json +5 -5
- package/.next/server/app/models/page.js +12 -14
- package/.next/server/app/models/page.js.nft.json +1 -1
- package/.next/server/app/models/page_client-reference-manifest.js +2 -1
- package/.next/server/app/models.html +1 -1
- package/.next/server/app/models.rsc +15 -13
- package/.next/server/app/models.segments/_full.segment.rsc +15 -13
- package/.next/server/app/models.segments/_head.segment.rsc +3 -3
- package/.next/server/app/models.segments/_index.segment.rsc +5 -5
- package/.next/server/app/models.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/models.segments/models/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/models.segments/models.segment.rsc +4 -3
- package/.next/server/app/page/build-manifest.json +5 -5
- package/.next/server/app/page.js +12 -14
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +2 -1
- package/.next/server/app/providers/page/build-manifest.json +5 -5
- package/.next/server/app/providers/page.js +12 -14
- package/.next/server/app/providers/page.js.nft.json +1 -1
- package/.next/server/app/providers/page_client-reference-manifest.js +2 -1
- package/.next/server/app/providers.html +1 -1
- package/.next/server/app/providers.rsc +15 -13
- package/.next/server/app/providers.segments/_full.segment.rsc +15 -13
- package/.next/server/app/providers.segments/_head.segment.rsc +3 -3
- package/.next/server/app/providers.segments/_index.segment.rsc +5 -5
- package/.next/server/app/providers.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/providers.segments/providers/__PAGE__.segment.rsc +4 -4
- package/.next/server/app/providers.segments/providers.segment.rsc +4 -3
- package/.next/server/app/tokenizer/page/app-paths-manifest.json +3 -0
- package/.next/server/app/tokenizer/page/build-manifest.json +16 -0
- package/.next/server/app/tokenizer/page/next-font-manifest.json +6 -0
- package/.next/server/app/tokenizer/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/tokenizer/page/server-reference-manifest.json +4 -0
- package/.next/server/app/tokenizer/page.js +13 -0
- package/.next/server/app/tokenizer/page.js.map +5 -0
- package/.next/server/app/tokenizer/page.js.nft.json +1 -0
- package/.next/server/app/tokenizer/page_client-reference-manifest.js +3 -0
- package/.next/server/app/tokenizer.html +1 -0
- package/.next/server/app/tokenizer.meta +15 -0
- package/.next/server/app/tokenizer.rsc +20 -0
- package/.next/server/app/tokenizer.segments/_full.segment.rsc +20 -0
- package/.next/server/app/tokenizer.segments/_head.segment.rsc +5 -0
- package/.next/server/app/tokenizer.segments/_index.segment.rsc +6 -0
- package/.next/server/app/tokenizer.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/tokenizer.segments/tokenizer/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/tokenizer.segments/tokenizer.segment.rsc +5 -0
- package/.next/server/app-paths-manifest.json +4 -1
- package/.next/server/chunks/0zjb_server_app_api_ide_openclaw_available-models_route_actions_0.gjr6a.js +3 -0
- package/.next/server/chunks/0zjb_server_app_api_ide_opencode_available-models_route_actions_0poyhyk.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0-_5z3v._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0-_5z3v._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__012ucp~._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__012ucp~._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__01atdgx._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__01atdgx._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__01~ft76._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__01~ft76._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__04sfkei._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__04sfkei._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__065r.wp._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__065r.wp._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__07pm7px._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__07pm7px._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__07vosna._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__07vosna._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__083j1v0._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__083j1v0._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__08_ekvs._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__08_ekvs._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__08ftz8n._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__08ftz8n._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__08oq8ma._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__08oq8ma._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__099b1my._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__099b1my._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0aw-~h8._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0aw-~h8._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0dj43ut._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0dj43ut._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0efv_yh._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0efv_yh._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0el37wu._.js +7 -0
- package/.next/server/chunks/[root-of-the-server]__0el37wu._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0g.1w-q._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0g.1w-q._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0im~-m7._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0im~-m7._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0jf1q27._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0jf1q27._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0kldv62._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0kldv62._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0lr16iw._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0lr16iw._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0m62mql._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0m62mql._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0qp1t_m._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0qp1t_m._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0qz-m.u._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0qz-m.u._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0r235yd._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0r235yd._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0rjkw2y._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0rjkw2y._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0uaqs.r._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0uaqs.r._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0vktxod._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0vktxod._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0vlh9um._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0vlh9um._.js.map +1 -0
- package/.next/server/chunks/{[root-of-the-server]__c1b4b601._.js → [root-of-the-server]__0xb5i_t._.js} +21 -9
- package/.next/server/chunks/[root-of-the-server]__0xb5i_t._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0xsal5d._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0xsal5d._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0yo.c6n._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0yo.c6n._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0yz0y4l._.js +13 -0
- package/.next/server/chunks/[root-of-the-server]__0yz0y4l._.js.map +1 -0
- package/.next/server/chunks/{[root-of-the-server]__e7623a6c._.js → [root-of-the-server]__11srlmi._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__e7623a6c._.js.map → [root-of-the-server]__11srlmi._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__12d44rt._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__12d44rt._.js.map +1 -0
- package/.next/server/chunks/[turbopack]_runtime.js +168 -60
- package/.next/server/chunks/[turbopack]_runtime.js.map +6 -5
- package/.next/server/chunks/_0v0oe6c._.js +3 -0
- package/.next/server/chunks/{_b48847f5._.js.map → _0v0oe6c._.js.map} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_config_route_actions_308a9f33.js → _next-internal_server_app_api_config_route_actions_08dm.dx.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_gateway_[___path]_route_actions_835b2379.js → _next-internal_server_app_api_gateway_[___path]_route_actions_0mmqyo7.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_gateway_models_route_actions_302c9983.js → _next-internal_server_app_api_gateway_models_route_actions_08b214z.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_gateway_route_actions_e5e7405d.js → _next-internal_server_app_api_gateway_route_actions_0.jzdw1.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_apply_route_actions_5056516c.js → _next-internal_server_app_api_ide_claude_apply_route_actions_0dw2_pf.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_available-models_route_actions_94d710a0.js → _next-internal_server_app_api_ide_claude_available-models_route_actions_0pmwy75.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_restore_route_actions_f37acc94.js → _next-internal_server_app_api_ide_claude_restore_route_actions_11x77hl.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_save_route_actions_407c55f5.js → _next-internal_server_app_api_ide_claude_save_route_actions_0b35ro_.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_status_route_actions_5ac73db8.js → _next-internal_server_app_api_ide_claude_status_route_actions_0fnw-w7.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_test_route_actions_70587902.js → _next-internal_server_app_api_ide_claude_test_route_actions_0jc1czy.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_apply_route_actions_2cb9e4b4.js → _next-internal_server_app_api_ide_openclaw_apply_route_actions_07re971.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_preview_route_actions_9814a8e4.js → _next-internal_server_app_api_ide_openclaw_preview_route_actions_0q53p05.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_restore_route_actions_10ad8f9d.js → _next-internal_server_app_api_ide_openclaw_restore_route_actions_02yog9-.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_save_route_actions_044ad081.js → _next-internal_server_app_api_ide_openclaw_save_route_actions_00tjxsz.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_status_route_actions_ed9786d2.js → _next-internal_server_app_api_ide_openclaw_status_route_actions_10wsun4.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_test_route_actions_ce2cb808.js → _next-internal_server_app_api_ide_openclaw_test_route_actions_0zgwyon.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_apply_route_actions_6c422244.js → _next-internal_server_app_api_ide_opencode_apply_route_actions_0in-w.g.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_preview_route_actions_256c82e0.js → _next-internal_server_app_api_ide_opencode_preview_route_actions_06h6.w~.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_restore_route_actions_371993d3.js → _next-internal_server_app_api_ide_opencode_restore_route_actions_09ipt-l.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_save_route_actions_6e4c9c41.js → _next-internal_server_app_api_ide_opencode_save_route_actions_0i-~x79.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_status_route_actions_498ad77b.js → _next-internal_server_app_api_ide_opencode_status_route_actions_0cpf6rv.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_test_route_actions_c71be510.js → _next-internal_server_app_api_ide_opencode_test_route_actions_0y8aq8h.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_logs_route_actions_30a87f47.js → _next-internal_server_app_api_logs_route_actions_08ef2j7.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_models_route_actions_b6abdc83.js → _next-internal_server_app_api_models_route_actions_0vfccm4.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_providers_route_actions_5388b373.js → _next-internal_server_app_api_providers_route_actions_0ee1p_m.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_providers_test_route_actions_b97ab15a.js → _next-internal_server_app_api_providers_test_route_actions_0vyo652.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_service_force-stop_route_actions_95eba80b.js → _next-internal_server_app_api_service_force-stop_route_actions_0pu9xrq.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_service_start_route_actions_d50efb77.js → _next-internal_server_app_api_service_start_route_actions_0_o53a2.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_service_status_route_actions_30149042.js → _next-internal_server_app_api_service_status_route_actions_08ag8v4.js} +1 -1
- package/.next/server/chunks/{_next-internal_server_app_api_service_stop_route_actions_19443941.js → _next-internal_server_app_api_service_stop_route_actions_04dp83p.js} +1 -1
- package/.next/server/chunks/_next-internal_server_app_api_tokenizer_history_route_actions_09~nqtd.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_tokenizer_test_route_actions_0t2swp-.js +3 -0
- package/.next/server/chunks/{node_modules_next_dist_esm_build_templates_app-route_4be65264.js → node_modules_next_dist_esm_build_templates_app-route_0d1n5~u.js} +6 -6
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0d1n5~u.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0.zquoa._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0.zquoa._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__01dqyhh._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__01dqyhh._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__04qwc64._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__04qwc64._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__06r_ug4._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__06r_ug4._.js.map +1 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__f92001a5._.js → [root-of-the-server]__0814l01._.js} +2 -2
- package/.next/server/chunks/ssr/[root-of-the-server]__0814l01._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0gb1hlj._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0gb1hlj._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0p8tmu2._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0p8tmu2._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0rf3.7n._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0rf3.7n._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0~6rwng._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0~6rwng._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__11i~7lq._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__11i~7lq._.js.map +1 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js +168 -60
- package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +6 -5
- package/.next/server/chunks/ssr/_0k83omg._.js +6 -0
- package/.next/server/chunks/ssr/_0k83omg._.js.map +1 -0
- package/.next/server/chunks/ssr/_0yyi5po._.js +3 -0
- package/.next/server/chunks/ssr/_0yyi5po._.js.map +1 -0
- package/.next/server/chunks/ssr/{_next-internal_server_app__global-error_page_actions_75761787.js → _next-internal_server_app__global-error_page_actions_0k77kol.js} +1 -1
- package/.next/server/chunks/ssr/{_next-internal_server_app__not-found_page_actions_554ec2bf.js → _next-internal_server_app__not-found_page_actions_0eq97pa.js} +1 -1
- package/.next/server/chunks/ssr/{_next-internal_server_app_ide_page_actions_d521d6ae.js → _next-internal_server_app_ide_page_actions_0_opd4~.js} +1 -1
- package/.next/server/chunks/ssr/{_next-internal_server_app_logs_page_actions_a1c69041.js → _next-internal_server_app_logs_page_actions_0rvsl~d.js} +1 -1
- package/.next/server/chunks/ssr/{_next-internal_server_app_models_page_actions_543cf22f.js → _next-internal_server_app_models_page_actions_0eiz7f7.js} +1 -1
- package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_09-gtaw.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_09-gtaw.js.map +1 -0
- package/.next/server/chunks/ssr/{_next-internal_server_app_providers_page_actions_c75f6cb3.js → _next-internal_server_app_providers_page_actions_0ya36nw.js} +1 -1
- package/.next/server/chunks/ssr/_next-internal_server_app_providers_page_actions_0ya36nw.js.map +1 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_tokenizer_page_actions_0imc_ya.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app_tokenizer_page_actions_0imc_ya.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_09w7yel._.js +33 -0
- package/.next/server/chunks/ssr/node_modules_09w7yel._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_06hehg4._.js +19 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_06hehg4._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js +6 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_0e1izl_._.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_9774470f._.js → node_modules_next_dist_client_components_0inhx6q._.js} +2 -2
- package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_forbidden_45780354.js → node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js} +2 -2
- package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_global-error_ece394eb.js → node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js} +2 -2
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_unauthorized_15817684.js → node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js} +2 -2
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_05u.ff5.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_05u.ff5.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_06a5k-w.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_06a5k-w.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0_rrdx6.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0_rrdx6.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a7b~p7.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a7b~p7.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0bj8dkg.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0cvrgh7.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0nkcfme.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0nkcfme.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +4 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js.map +1 -0
- package/.next/server/chunks/ssr/src_app_components_ConfirmDialog_tsx_0mm3plr._.js +3 -0
- package/.next/server/chunks/ssr/src_app_components_ConfirmDialog_tsx_0mm3plr._.js.map +1 -0
- package/.next/server/chunks/ssr/src_app_ide_page_tsx_0no40dj._.js +3 -0
- package/.next/server/chunks/ssr/{src_app_ide_page_tsx_8962793b._.js.map → src_app_ide_page_tsx_0no40dj._.js.map} +1 -1
- package/.next/server/chunks/ssr/src_app_logs_page_tsx_0l8mmxe._.js +3 -0
- package/.next/server/chunks/ssr/{src_app_logs_page_tsx_7b7b7b83._.js.map → src_app_logs_page_tsx_0l8mmxe._.js.map} +1 -1
- package/.next/server/chunks/ssr/src_app_models_page_tsx_10vsbc1._.js +3 -0
- package/.next/server/chunks/ssr/{src_app_models_page_tsx_ed71d32e._.js.map → src_app_models_page_tsx_10vsbc1._.js.map} +1 -1
- package/.next/server/chunks/ssr/src_app_page_tsx_0ss2.w7._.js +3 -0
- package/.next/server/chunks/ssr/src_app_page_tsx_0ss2.w7._.js.map +1 -0
- package/.next/server/chunks/ssr/src_app_providers_page_tsx_10ipz~8._.js +3 -0
- package/.next/server/chunks/ssr/{src_app_providers_page_tsx_eb8b5137._.js.map → src_app_providers_page_tsx_10ipz~8._.js.map} +1 -1
- package/.next/server/chunks/ssr/src_app_tokenizer_page_tsx_0eqhpbs._.js +3 -0
- package/.next/server/chunks/ssr/src_app_tokenizer_page_tsx_0eqhpbs._.js.map +1 -0
- package/.next/server/functions-config-manifest.json +3 -1
- package/.next/server/middleware-build-manifest.js +10 -10
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -2
- package/.next/server/prefetch-hints.json +1 -0
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/XHnu7Z1vWSrgmneps8rX4/_clientMiddlewareManifest.js +1 -0
- package/.next/static/chunks/01xlw8hd842-c.js +1 -0
- package/.next/static/chunks/0bzupvr5gt3k9.js +31 -0
- package/.next/static/chunks/0d3shmwh5_nmn.js +1 -0
- package/.next/static/chunks/0h7-_zr5_nt.5.js +1 -0
- package/.next/static/chunks/0mjx90nkvhsot.js +1 -0
- package/.next/static/chunks/0ntp1qkrtsgn0.js +1 -0
- package/.next/static/chunks/0tc5l6c1zalyc.css +1 -0
- package/.next/static/chunks/0v7.1nc4jyaet.js +1 -0
- package/.next/static/chunks/0vlwn301rv7dw.js +1 -0
- package/.next/static/chunks/0y3~cortx~or~.js +5 -0
- package/.next/static/chunks/0~c9fm3-3-f41.js +1 -0
- package/.next/static/chunks/11-7_fybhp2~y.js +1 -0
- package/.next/static/chunks/121-ofr4.6_5t.js +1 -0
- package/.next/static/chunks/16g.ca89g7fib.js +1 -0
- package/.next/static/chunks/turbopack-0griofc2i3wvs.js +1 -0
- package/.next/types/routes.d.ts +5 -2
- package/.next/types/validator.ts +27 -0
- package/CHANGELOG.md +15 -0
- package/README.md +6 -0
- package/dist/.next/dev/types/validator.js +12 -0
- package/dist/.next/types/validator.js +12 -0
- package/dist/package.json +3 -2
- package/dist/src/app/api/tokenizer/history/route.js +60 -0
- package/dist/src/app/api/tokenizer/test/route.js +97 -0
- package/dist/src/app/components/Nav.js +2 -1
- package/dist/src/app/tokenizer/page.js +318 -0
- package/dist/src/cli/index.js +3 -3
- package/dist/src/db/database.js +19 -21
- package/dist/src/db/queries.js +21 -0
- package/dist/src/server/tokenizer.js +215 -0
- package/package.json +3 -2
- package/src/app/api/tokenizer/history/route.ts +63 -0
- package/src/app/api/tokenizer/test/route.ts +151 -0
- package/src/app/components/Nav.tsx +2 -2
- package/src/app/tokenizer/page.tsx +813 -0
- package/src/cli/index.ts +4 -4
- package/src/db/database.ts +18 -25
- package/src/db/queries.ts +22 -0
- package/src/server/tokenizer.ts +285 -0
- package/.next/build/chunks/[root-of-the-server]__44695d76._.js.map +0 -11
- package/.next/build/chunks/[root-of-the-server]__6d51cb5d._.js.map +0 -8
- package/.next/server/chunks/[root-of-the-server]__001d5756._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__001d5756._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__05f8578b._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__05f8578b._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__1480f018._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1480f018._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__1909f3aa._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1909f3aa._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__1d4b7fc5._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1d4b7fc5._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__33fec899._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__33fec899._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__372ef2bf._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__372ef2bf._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__3a204d25._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__3a204d25._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__3aaf963c._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__3aaf963c._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__43810962._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__43810962._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__4a8f9bc7._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__4a8f9bc7._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__55cd88b8._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__55cd88b8._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__59aacd30._.js +0 -21
- package/.next/server/chunks/[root-of-the-server]__59aacd30._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__5e8276bc._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__5e8276bc._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__64356cb2._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__64356cb2._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__6ce199d2._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__6ce199d2._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__760eaa16._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__760eaa16._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__772134c6._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__772134c6._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__7b77f523._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__7b77f523._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__7c298a19._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__7c298a19._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__85540228._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__85540228._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__94fe8d3c._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__94fe8d3c._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__97622908._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__97622908._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__a02e6618._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__a02e6618._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__a32a20a7._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__a32a20a7._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__a719d045._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__a719d045._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__af5b556a._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__af5b556a._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__c1b4b601._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__cafe113e._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__cafe113e._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__ccfc7f1d._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__ccfc7f1d._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__dc8b0bed._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__dc8b0bed._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__f0461b8d._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__f0461b8d._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__f8949f88._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__f8949f88._.js.map +0 -1
- package/.next/server/chunks/_b48847f5._.js +0 -3
- package/.next/server/chunks/ce889_server_app_api_ide_openclaw_available-models_route_actions_e568e70b.js +0 -3
- package/.next/server/chunks/ce889_server_app_api_ide_opencode_available-models_route_actions_95230db3.js +0 -3
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_4be65264.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__083d944d._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__083d944d._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__15600e29._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__15600e29._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1836f866._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1836f866._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__256a03fe._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__256a03fe._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__31fde618._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__31fde618._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__523c120c._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__523c120c._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__70a81394._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__70a81394._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__81937253._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__81937253._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__976ad963._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__976ad963._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__af2ad6aa._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__af2ad6aa._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__b9356576._.js +0 -4
- package/.next/server/chunks/ssr/[root-of-the-server]__b9356576._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__ccb6a4da._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__ccb6a4da._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__cfa2d991._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__cfa2d991._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__f437da88._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__f437da88._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__f92001a5._.js.map +0 -1
- package/.next/server/chunks/ssr/_06262cbd._.js +0 -4
- package/.next/server/chunks/ssr/_06262cbd._.js.map +0 -1
- package/.next/server/chunks/ssr/_0cd72da5._.js +0 -4
- package/.next/server/chunks/ssr/_0cd72da5._.js.map +0 -1
- package/.next/server/chunks/ssr/_4828a6d2._.js +0 -4
- package/.next/server/chunks/ssr/_4828a6d2._.js.map +0 -1
- package/.next/server/chunks/ssr/_69468f4c._.js +0 -3
- package/.next/server/chunks/ssr/_69468f4c._.js.map +0 -1
- package/.next/server/chunks/ssr/_93850476._.js +0 -6
- package/.next/server/chunks/ssr/_93850476._.js.map +0 -1
- package/.next/server/chunks/ssr/_c1309523._.js +0 -4
- package/.next/server/chunks/ssr/_c1309523._.js.map +0 -1
- package/.next/server/chunks/ssr/_f7d273e3._.js +0 -4
- package/.next/server/chunks/ssr/_f7d273e3._.js.map +0 -1
- package/.next/server/chunks/ssr/_next-internal_server_app_page_actions_39d4fc33.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_08570d7f._.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_08570d7f._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_174ae28d._.js +0 -10
- package/.next/server/chunks/ssr/node_modules_next_dist_174ae28d._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_27457240._.js +0 -6
- package/.next/server/chunks/ssr/node_modules_next_dist_27457240._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_4b63a0e1._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_4b63a0e1._.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_ece394eb.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_65a7265e.js +0 -4
- package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_65a7265e.js.map +0 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_f9713a08._.js +0 -3
- package/.next/server/chunks/ssr/node_modules_next_dist_f9713a08._.js.map +0 -1
- package/.next/server/chunks/ssr/src_app_ide_page_tsx_8962793b._.js +0 -3
- package/.next/server/chunks/ssr/src_app_logs_page_tsx_7b7b7b83._.js +0 -3
- package/.next/server/chunks/ssr/src_app_models_page_tsx_ed71d32e._.js +0 -3
- package/.next/server/chunks/ssr/src_app_providers_page_tsx_eb8b5137._.js +0 -3
- package/.next/static/cf2SWIkI5HVbnDjLExI42/_clientMiddlewareManifest.json +0 -1
- package/.next/static/chunks/5663c8696095f277.js +0 -1
- package/.next/static/chunks/64f547b3bcd3aef4.js +0 -1
- package/.next/static/chunks/6992685fe009e8fd.css +0 -1
- package/.next/static/chunks/6e0dee5b6681763c.js +0 -1
- package/.next/static/chunks/6f7efe5271343778.js +0 -1
- package/.next/static/chunks/75f76753fd97c8fd.js +0 -1
- package/.next/static/chunks/7c8b7cbb3339f139.js +0 -1
- package/.next/static/chunks/8ccc14e022ff6de3.js +0 -1
- package/.next/static/chunks/8cf1e5f00ebaea52.js +0 -1
- package/.next/static/chunks/a6dad97d9634a72d.js.map +0 -1
- package/.next/static/chunks/a7f539bf6487f4ff.js +0 -5
- package/.next/static/chunks/a89fdf03c5b0dfbd.js +0 -1
- package/.next/static/chunks/d2be314c3ece3fbe.js +0 -1
- package/.next/static/chunks/f2f58a7e93290fbb.js +0 -1
- package/.next/static/chunks/ff1a16fafef87110.js +0 -1
- package/.next/static/chunks/turbopack-fdb839c72e10c2ea.js +0 -4
- /package/.next/build/chunks/{[turbopack-node]_transforms_postcss_ts_df7a5b11._.js.map → [turbopack-node]_transforms_postcss_ts_0nnejqq._.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_config_route_actions_308a9f33.js.map → 0zjb_server_app_api_ide_openclaw_available-models_route_actions_0.gjr6a.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_gateway_[___path]_route_actions_835b2379.js.map → 0zjb_server_app_api_ide_opencode_available-models_route_actions_0poyhyk.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_gateway_models_route_actions_302c9983.js.map → _next-internal_server_app_api_config_route_actions_08dm.dx.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_gateway_route_actions_e5e7405d.js.map → _next-internal_server_app_api_gateway_[___path]_route_actions_0mmqyo7.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_apply_route_actions_5056516c.js.map → _next-internal_server_app_api_gateway_models_route_actions_08b214z.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_available-models_route_actions_94d710a0.js.map → _next-internal_server_app_api_gateway_route_actions_0.jzdw1.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_restore_route_actions_f37acc94.js.map → _next-internal_server_app_api_ide_claude_apply_route_actions_0dw2_pf.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_save_route_actions_407c55f5.js.map → _next-internal_server_app_api_ide_claude_available-models_route_actions_0pmwy75.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_status_route_actions_5ac73db8.js.map → _next-internal_server_app_api_ide_claude_restore_route_actions_11x77hl.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_claude_test_route_actions_70587902.js.map → _next-internal_server_app_api_ide_claude_save_route_actions_0b35ro_.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_apply_route_actions_2cb9e4b4.js.map → _next-internal_server_app_api_ide_claude_status_route_actions_0fnw-w7.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_preview_route_actions_9814a8e4.js.map → _next-internal_server_app_api_ide_claude_test_route_actions_0jc1czy.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_restore_route_actions_10ad8f9d.js.map → _next-internal_server_app_api_ide_openclaw_apply_route_actions_07re971.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_save_route_actions_044ad081.js.map → _next-internal_server_app_api_ide_openclaw_preview_route_actions_0q53p05.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_status_route_actions_ed9786d2.js.map → _next-internal_server_app_api_ide_openclaw_restore_route_actions_02yog9-.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_openclaw_test_route_actions_ce2cb808.js.map → _next-internal_server_app_api_ide_openclaw_save_route_actions_00tjxsz.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_apply_route_actions_6c422244.js.map → _next-internal_server_app_api_ide_openclaw_status_route_actions_10wsun4.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_preview_route_actions_256c82e0.js.map → _next-internal_server_app_api_ide_openclaw_test_route_actions_0zgwyon.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_restore_route_actions_371993d3.js.map → _next-internal_server_app_api_ide_opencode_apply_route_actions_0in-w.g.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_save_route_actions_6e4c9c41.js.map → _next-internal_server_app_api_ide_opencode_preview_route_actions_06h6.w~.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_status_route_actions_498ad77b.js.map → _next-internal_server_app_api_ide_opencode_restore_route_actions_09ipt-l.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_ide_opencode_test_route_actions_c71be510.js.map → _next-internal_server_app_api_ide_opencode_save_route_actions_0i-~x79.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_logs_route_actions_30a87f47.js.map → _next-internal_server_app_api_ide_opencode_status_route_actions_0cpf6rv.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_models_route_actions_b6abdc83.js.map → _next-internal_server_app_api_ide_opencode_test_route_actions_0y8aq8h.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_providers_route_actions_5388b373.js.map → _next-internal_server_app_api_logs_route_actions_08ef2j7.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_providers_test_route_actions_b97ab15a.js.map → _next-internal_server_app_api_models_route_actions_0vfccm4.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_service_force-stop_route_actions_95eba80b.js.map → _next-internal_server_app_api_providers_route_actions_0ee1p_m.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_service_start_route_actions_d50efb77.js.map → _next-internal_server_app_api_providers_test_route_actions_0vyo652.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_service_status_route_actions_30149042.js.map → _next-internal_server_app_api_service_force-stop_route_actions_0pu9xrq.js.map} +0 -0
- /package/.next/server/chunks/{_next-internal_server_app_api_service_stop_route_actions_19443941.js.map → _next-internal_server_app_api_service_start_route_actions_0_o53a2.js.map} +0 -0
- /package/.next/server/chunks/{ce889_server_app_api_ide_openclaw_available-models_route_actions_e568e70b.js.map → _next-internal_server_app_api_service_status_route_actions_08ag8v4.js.map} +0 -0
- /package/.next/server/chunks/{ce889_server_app_api_ide_opencode_available-models_route_actions_95230db3.js.map → _next-internal_server_app_api_service_stop_route_actions_04dp83p.js.map} +0 -0
- /package/.next/server/chunks/{ssr/_next-internal_server_app__global-error_page_actions_75761787.js.map → _next-internal_server_app_api_tokenizer_history_route_actions_09~nqtd.js.map} +0 -0
- /package/.next/server/chunks/{ssr/_next-internal_server_app__not-found_page_actions_554ec2bf.js.map → _next-internal_server_app_api_tokenizer_test_route_actions_0t2swp-.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_ide_page_actions_d521d6ae.js.map → _next-internal_server_app__global-error_page_actions_0k77kol.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_logs_page_actions_a1c69041.js.map → _next-internal_server_app__not-found_page_actions_0eq97pa.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_models_page_actions_543cf22f.js.map → _next-internal_server_app_ide_page_actions_0_opd4~.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_page_actions_39d4fc33.js.map → _next-internal_server_app_logs_page_actions_0rvsl~d.js.map} +0 -0
- /package/.next/server/chunks/ssr/{_next-internal_server_app_providers_page_actions_c75f6cb3.js.map → _next-internal_server_app_models_page_actions_0eiz7f7.js.map} +0 -0
- /package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_9774470f._.js.map → node_modules_next_dist_client_components_0inhx6q._.js.map} +0 -0
- /package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_forbidden_45780354.js.map → node_modules_next_dist_client_components_builtin_forbidden_0ghu-f7.js.map} +0 -0
- /package/.next/server/chunks/ssr/{node_modules_next_dist_client_components_builtin_unauthorized_15817684.js.map → node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js.map} +0 -0
- /package/.next/static/{cf2SWIkI5HVbnDjLExI42 → XHnu7Z1vWSrgmneps8rX4}/_buildManifest.js +0 -0
- /package/.next/static/{cf2SWIkI5HVbnDjLExI42 → XHnu7Z1vWSrgmneps8rX4}/_ssgManifest.js +0 -0
- /package/.next/static/chunks/{a6dad97d9634a72d.js → 03~yq9q893hmn.js} +0 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
module.exports=[82602,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(81844),e=a.i(21215),f=a.i(71862);a.s(["default",0,function(){let[a,g]=(0,c.useState)([]),[h,i]=(0,c.useState)(null),[j,k]=(0,c.useState)(!0),[l,m]=(0,c.useState)(0),[n,o]=(0,c.useState)(0),[p,q]=(0,c.useState)([]),[r,s]=(0,c.useState)(!1),[t,u]=(0,c.useState)(null),[v,w]=(0,c.useState)(""),[x,y]=(0,c.useState)(""),{showToast:z}=(0,e.useToast)(),A=async a=>{try{await navigator.clipboard.writeText(a),z("已复制到剪贴板","success")}catch{z("复制失败,请手动复制","error")}},B=async()=>{0!==p.length&&u({open:!0,title:"删除确认",message:`确定要删除选中的 ${p.length} 条日志吗?`,onConfirm:async()=>{try{let a=await fetch(`/api/logs?ids=${p.join(",")}`,{method:"DELETE"}),b=await a.json();a.ok?(q([]),s(!1),D(),z("删除成功","success"),u(null)):z("删除失败:"+(b.error||"未知错误"),"error")}catch(a){console.error("Failed to delete logs:",a),z("删除失败","error")}}})},C=async()=>{u({open:!0,title:"清空日志",message:"确定要清空所有日志吗?此操作不可恢复!",onConfirm:async()=>{try{let a=await fetch("/api/logs?clear_all=true",{method:"DELETE"}),b=await a.json();a.ok?(m(0),q([]),s(!1),D(),z("清空成功","success"),u(null)):z("清空失败:"+(b.error||"未知错误"),"error")}catch(a){console.error("Failed to clear logs:",a),z("清空失败","error")}}})},D=async a=>{try{k(!0);let b=new URLSearchParams({limit:"50",offset:(50*l).toString()});a&&b.set("search",a);let c=await fetch(`/api/logs?${b.toString()}`),d=await c.json();g(d.logs||[]),o(d.total||0)}catch(a){console.error("Failed to load logs:",a),z("加载日志失败","error")}finally{k(!1)}},E=()=>{w(x),m(0),D(x)};(0,c.useEffect)(()=>{D()},[l,50]);let F=a=>"string"==typeof a?a:JSON.stringify(a),G=a=>I(a)?H(a):F(a),H=a=>{let b;if(!a)return"";try{b=JSON.parse(a)}catch{b=a}if(!b.includes("data:")||!b.includes("\n\n"))try{let a=JSON.parse(b);return JSON.stringify(a)}catch{return String(b)}let c=b.split("\n\n").filter(a=>a.trim()),d=[];for(let a of c){let b=a.trim();b=b.split("\n").map(a=>a.startsWith("data: ")?a.substring(6):a).join("\n"),d.push(b)}return d.join("\n\n")},I=a=>{if(!a)return!1;let b=a.includes("data:"),c=a.includes("\n\n"),d=a.includes("event:");return b||c||d};return j?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(d.default,{}),(0,b.jsx)("div",{className:"min-h-screen flex items-center justify-center",children:(0,b.jsx)("div",{className:"text-lg",children:"加载中..."})})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(d.default,{}),(0,b.jsx)("main",{className:"max-w-6xl mx-auto py-6 sm:px-6 lg:px-8",children:(0,b.jsxs)("div",{className:"px-4 py-4 sm:px-0",children:[(0,b.jsxs)("div",{className:"mb-5 flex items-center justify-between",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-lg font-bold text-slate-800",children:"请求日志"}),(0,b.jsx)("p",{className:"text-xs text-slate-500 mt-1",children:"查看所有 API 请求记录和响应详情"})]}),(0,b.jsxs)("div",{className:"flex gap-2 items-center",children:[(0,b.jsxs)("div",{className:"relative group",children:[(0,b.jsx)("input",{type:"text",placeholder:"搜索日志...",value:x,onChange:a=>y(a.target.value),onKeyPress:a=>{"Enter"===a.key&&E()},className:"w-64 pl-9 pr-20 py-1.5 text-xs border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500/30 focus:border-emerald-500 transition-all"}),(0,b.jsx)("svg",{className:"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})}),(0,b.jsx)("div",{className:"absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1",children:x?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("button",{onClick:E,className:"p-0.5 text-emerald-500 hover:text-emerald-600 hover:bg-emerald-50 rounded transition-colors",title:"确认搜索",children:(0,b.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M5 13l4 4L19 7"})})}),(0,b.jsx)("button",{onClick:()=>{y(""),v&&(w(""),m(0),D())},className:"p-0.5 text-slate-400 hover:text-rose-500 hover:bg-rose-50 rounded transition-colors",title:"清除搜索",children:(0,b.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}):null})]}),p.length>0&&(0,b.jsxs)("button",{onClick:B,className:"px-3 py-1.5 bg-rose-600 hover:bg-rose-700 text-white text-xs font-semibold rounded-lg border border-rose-200 transition-all duration-300",children:["删除选中 (",p.length,")"]}),(0,b.jsx)("button",{onClick:C,className:"px-3 py-1.5 bg-slate-600 hover:bg-slate-700 text-white text-xs font-semibold rounded-lg border border-slate-200 transition-all duration-300",children:"清空所有"})]})]}),(0,b.jsx)("div",{className:"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 overflow-hidden",children:(0,b.jsxs)("table",{className:"min-w-full divide-y divide-slate-100",children:[(0,b.jsx)("thead",{className:"bg-emerald-50/30",children:(0,b.jsxs)("tr",{children:[(0,b.jsx)("th",{className:"px-4 py-3.5 w-10",children:(0,b.jsx)("input",{type:"checkbox",checked:r&&a.length>0,onChange:b=>{var c;s(c=b.target.checked),q(c?a.map(a=>a.id):[])},className:"w-4 h-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500"})}),(0,b.jsx)("th",{className:"px-4 py-2.5 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider",children:"时间"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"模型"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"方法"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"路径"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"状态"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"响应时间"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"操作"})]})}),(0,b.jsx)("tbody",{className:"bg-white divide-y divide-slate-100",children:0===a.length?(0,b.jsx)("tr",{children:(0,b.jsx)("td",{colSpan:8,className:"px-4 py-12 text-center",children:(0,b.jsxs)("div",{className:"text-slate-400",children:[(0,b.jsx)("svg",{className:"mx-auto h-10 w-10 mb-3 text-slate-300",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})}),(0,b.jsx)("p",{className:"text-xs text-slate-500",children:v?"未找到匹配的日志":"暂无日志记录"}),v&&(0,b.jsx)("button",{onClick:()=>{y(""),w("")},className:"mt-2 text-xs text-emerald-600 hover:text-emerald-700",children:"清除搜索"})]})})}):a.map(a=>{let c=((a,b)=>{try{let c=a?JSON.parse(a):{},d=(b?JSON.parse(b):{}).model||c.model;if(Array.isArray(d)){let a=d[d.length-1];if(a&&"object"==typeof a&&"model"in a)return a.model}return"string"==typeof d?d:null}catch{return null}})(a.request_query,a.request_body)||a.model_name||"Gateway";return(0,b.jsxs)("tr",{className:"hover:bg-emerald-50/20 transition-colors duration-300",children:[(0,b.jsx)("td",{className:"px-4 py-3",children:(0,b.jsx)("input",{type:"checkbox",checked:p.includes(a.id),onChange:b=>{var c;return c=a.id,void(b.target.checked?q([...p,c]):(q(p.filter(a=>a!==c)),s(!1)))},className:"w-4 h-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500",onClick:a=>a.stopPropagation()})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsx)("div",{className:"text-xs text-slate-600",children:function(a){if(!a||"string"!=typeof a)return"";let b=a.trim();if(!b)return"";let c=new Date(/[Z+-]\d{2}:?\d{2}$/.test(b)?b:b.replace(" ","T"));return Number.isNaN(c.getTime())?b:c.toLocaleString("zh-CN")}(a.created_at)})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsxs)("div",{className:"text-xs",children:[(0,b.jsx)("div",{className:"font-medium text-slate-800",children:c}),a.provider_name&&(0,b.jsx)("div",{className:"text-[10px] text-slate-500",children:a.provider_name})]})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsx)("span",{className:`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-lg border ${"GET"===a.request_method?"bg-sky-50 text-sky-700 border-sky-200/50":"POST"===a.request_method?"bg-emerald-50 text-emerald-700 border-emerald-200/50":"bg-slate-50 text-slate-600 border-slate-200/50"}`,children:a.request_method})}),(0,b.jsx)("td",{className:"px-4 py-3",children:(0,b.jsx)("div",{className:"text-xs text-slate-600 font-mono max-w-xs truncate",children:a.request_path})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsx)("span",{className:`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-full border ${a.response_status>=200&&a.response_status<300?"bg-emerald-100/80 text-emerald-700 border-emerald-200/50":a.response_status>=400&&a.response_status<500?"bg-amber-100/80 text-amber-700 border-amber-200/50":a.response_status>=500?"bg-rose-100/80 text-rose-700 border-rose-200/50":"bg-slate-100/80 text-slate-600 border-slate-200/50"}`,children:a.response_status})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsxs)("div",{className:"text-xs text-slate-600",children:[a.response_time_ms,"ms"]})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap text-right text-xs font-medium",children:(0,b.jsx)("button",{onClick:()=>i(a),className:"text-emerald-600 hover:text-emerald-700 font-medium transition-colors duration-300",children:"查看详情"})})]},a.id)})})]})}),(0,b.jsxs)("div",{className:"mt-5 flex items-center justify-between",children:[(0,b.jsx)("div",{className:"text-xs text-slate-600",children:v?(0,b.jsxs)("span",{children:['搜索 "',(0,b.jsx)("span",{className:"font-semibold text-slate-800",children:v}),'" 找到 ',(0,b.jsx)("span",{className:"font-semibold text-slate-800",children:n})," 条结果"]}):(0,b.jsxs)("span",{children:["共 ",(0,b.jsx)("span",{className:"font-semibold text-slate-800",children:n})," 条记录"]})}),(0,b.jsxs)("div",{className:"flex space-x-2",children:[(0,b.jsx)("button",{onClick:()=>m(Math.max(0,l-1)),disabled:0===l,className:"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 bg-white hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300",children:"上一页"}),(0,b.jsx)("button",{onClick:()=>m(l+1),disabled:(l+1)*50>=n,className:"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 bg-white hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300",children:"下一页"})]})]})]})}),h&&(0,b.jsx)("div",{className:"fixed z-50 inset-0 overflow-y-auto",children:(0,b.jsxs)("div",{className:"flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0",children:[(0,b.jsx)("div",{className:"fixed inset-0 bg-slate-900/40 backdrop-blur-sm transition-opacity",onClick:()=>i(null)}),(0,b.jsx)("div",{className:"inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full border border-emerald-100/50",children:(0,b.jsxs)("div",{className:"bg-white px-6 pt-5 pb-4 sm:p-6",children:[(0,b.jsxs)("div",{className:"mb-5",children:[(0,b.jsx)("h3",{className:"text-base font-bold text-slate-800 mb-1",children:"请求详情"}),(0,b.jsx)("p",{className:"text-xs text-slate-500",children:"查看完整的请求和响应信息"})]}),(0,b.jsxs)("div",{className:"space-y-4 max-h-[60vh] overflow-y-auto",children:[(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between mb-2",children:[(0,b.jsx)("h4",{className:"text-xs font-semibold text-slate-700",children:"请求头"}),(0,b.jsx)("button",{onClick:()=>A(F(h.request_headers)),className:"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors",children:"复制"})]}),(0,b.jsx)("pre",{className:"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700",children:F(h.request_headers)})]}),(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between mb-2",children:[(0,b.jsx)("h4",{className:"text-xs font-semibold text-slate-700",children:"请求 Query"}),(0,b.jsx)("button",{onClick:()=>A(F(h.request_query)),className:"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors",children:"复制"})]}),(0,b.jsx)("pre",{className:"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700",children:F(h.request_query)})]}),(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between mb-2",children:[(0,b.jsx)("h4",{className:"text-xs font-semibold text-slate-700",children:"请求 Body"}),(0,b.jsx)("button",{onClick:()=>A(F(h.request_body)),className:"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors",children:"复制"})]}),(0,b.jsx)("pre",{className:"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700",children:F(h.request_body)})]}),(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between mb-2",children:[(0,b.jsx)("h4",{className:"text-xs font-semibold text-slate-700",children:"响应 Body"}),(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[h&&I(h.response_body)&&(0,b.jsx)("span",{className:"px-2 py-0.5 text-xs bg-indigo-100 text-indigo-700 rounded-full border border-indigo-200",children:"流式响应"}),(0,b.jsx)("button",{onClick:()=>A(G(h.response_body)),className:"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors",children:"复制"})]})]}),(0,b.jsx)("div",{className:"bg-slate-50/80 border border-slate-200 rounded-xl p-3 max-h-96 overflow-auto",children:(0,b.jsx)("pre",{className:"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700",children:G(h.response_body)})})]})]}),(0,b.jsx)("div",{className:"mt-5 flex justify-end",children:(0,b.jsx)("button",{type:"button",onClick:()=>i(null),className:"px-4 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-400/30 transition-all duration-300",children:"关闭"})})]})})]})}),t&&(0,b.jsx)(f.default,{open:t.open,title:t.title,message:t.message,onConfirm:t.onConfirm,onCancel:()=>u(null),type:"danger"})]})}])}];
|
|
2
|
+
|
|
3
|
+
//# sourceMappingURL=src_app_logs_page_tsx_0l8mmxe._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app/logs/page.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport Nav from '../components/Nav';\nimport { useToast } from '../components/ToastProvider';\nimport ConfirmDialog from '../components/ConfirmDialog';\n\ninterface RequestLog {\n id: number;\n model_id: number | null;\n model_name?: string | null;\n provider_name?: string | null;\n request_method: string;\n request_path: string;\n request_headers: string;\n request_query: string;\n request_body: string;\n response_status: number;\n response_body: string;\n response_time_ms: number;\n created_at: string;\n}\n\n/** 将服务端返回的 created_at 格式化为本地显示。数据库存储的是本地时间,无需追加 Z 后缀。 */\nfunction formatCreatedAt(createdAt: string): string {\n if (!createdAt || typeof createdAt !== 'string') return '';\n const s = createdAt.trim();\n if (!s) return '';\n // 数据库使用 datetime('now','localtime') 存储的已经是本地时间,\n // 不带时区后缀时直接按本地时间解析,不要追加 'Z'(否则会多偏移 8 小时)\n const hasTz = /[Z+-]\\d{2}:?\\d{2}$/.test(s);\n const iso = hasTz ? s : s.replace(' ', 'T');\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? s : date.toLocaleString('zh-CN');\n}\n\nexport default function LogsPage() {\n const [logs, setLogs] = useState<RequestLog[]>([]);\n const [selectedLog, setSelectedLog] = useState<RequestLog | null>(null);\n const [loading, setLoading] = useState(true);\n const [page, setPage] = useState(0);\n const [total, setTotal] = useState(0);\n const [selectedIds, setSelectedIds] = useState<number[]>([]);\n const [selectAll, setSelectAll] = useState(false);\n const [confirmDialog, setConfirmDialog] = useState<{ open: boolean; title: string; message: string; onConfirm: () => void } | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [searchInput, setSearchInput] = useState('');\n const limit = 50;\n const { showToast } = useToast();\n\n const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n showToast('已复制到剪贴板', 'success');\n } catch {\n showToast('复制失败,请手动复制', 'error');\n }\n };\n\n const handleDeleteSelected = async () => {\n if (selectedIds.length === 0) return;\n setConfirmDialog({\n open: true,\n title: '删除确认',\n message: `确定要删除选中的 ${selectedIds.length} 条日志吗?`,\n onConfirm: async () => {\n try {\n const res = await fetch(`/api/logs?ids=${selectedIds.join(',')}`, { method: 'DELETE' });\n const data = await res.json();\n if (res.ok) {\n setSelectedIds([]);\n setSelectAll(false);\n loadLogs();\n showToast('删除成功', 'success');\n setConfirmDialog(null);\n } else {\n showToast('删除失败:' + (data.error || '未知错误'), 'error');\n }\n } catch (error) {\n console.error('Failed to delete logs:', error);\n showToast('删除失败', 'error');\n }\n },\n });\n };\n\n const handleClearAll = async () => {\n setConfirmDialog({\n open: true,\n title: '清空日志',\n message: '确定要清空所有日志吗?此操作不可恢复!',\n onConfirm: async () => {\n try {\n const res = await fetch('/api/logs?clear_all=true', { method: 'DELETE' });\n const data = await res.json();\n if (res.ok) {\n setPage(0);\n setSelectedIds([]);\n setSelectAll(false);\n loadLogs();\n showToast('清空成功', 'success');\n setConfirmDialog(null);\n } else {\n showToast('清空失败:' + (data.error || '未知错误'), 'error');\n }\n } catch (error) {\n console.error('Failed to clear logs:', error);\n showToast('清空失败', 'error');\n }\n },\n });\n };\n\n const handleSelectAll = (checked: boolean) => {\n setSelectAll(checked);\n setSelectedIds(checked ? logs.map(log => log.id) : []);\n };\n\n const handleSelectLog = (id: number, checked: boolean) => {\n if (checked) {\n setSelectedIds([...selectedIds, id]);\n } else {\n setSelectedIds(selectedIds.filter(sid => sid !== id));\n setSelectAll(false);\n }\n };\n\n const loadLogs = async (search?: string) => {\n try {\n setLoading(true);\n const params = new URLSearchParams({\n limit: limit.toString(),\n offset: (page * limit).toString(),\n });\n if (search) {\n params.set('search', search);\n }\n const res = await fetch(`/api/logs?${params.toString()}`);\n const data = await res.json();\n setLogs(data.logs || []);\n setTotal(data.total || 0);\n } catch (error) {\n console.error('Failed to load logs:', error);\n showToast('加载日志失败', 'error');\n } finally {\n setLoading(false);\n }\n };\n\n // 手动触发搜索\n const handleSearch = () => {\n setSearchQuery(searchInput);\n setPage(0);\n loadLogs(searchInput);\n };\n\n // 清除搜索\n const clearSearch = () => {\n setSearchInput('');\n if (searchQuery) {\n setSearchQuery('');\n setPage(0);\n loadLogs();\n }\n };\n\n // 键盘搜索支持\n const handleKeyPress = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') {\n handleSearch();\n }\n };\n\n useEffect(() => {\n loadLogs();\n }, [page, limit]);\n\n const formatJSONSimple = (jsonString: string): string => {\n return typeof jsonString === 'string' ? jsonString : JSON.stringify(jsonString);\n }\n\n const formatRespon = (str: string): string => {\n if (isStreamingResponse(str)) {\n return formatSSEStream(str);\n }\n return formatJSONSimple(str);\n }\n\n const formatSSEStream = (responseBody: any): string => {\n if (!responseBody) return '';\n\n let sseData: string;\n try {\n sseData = JSON.parse(responseBody);\n } catch {\n sseData = responseBody;\n }\n\n if (!sseData.includes('data:') || !sseData.includes('\\n\\n')) {\n try {\n const parsed = JSON.parse(sseData);\n return JSON.stringify(parsed);\n } catch {\n return String(sseData);\n }\n }\n\n const chunks = sseData.split('\\n\\n').filter(chunk => chunk.trim());\n const formattedChunks: string[] = [];\n\n for (const chunk of chunks) {\n let content = chunk.trim();\n let tmp = content.split(\"\\n\").map((line) => {\n return line.startsWith(\"data: \") ? line.substring(6) : line;\n });\n content = tmp.join(\"\\n\");\n if (content === 'data: [DONE]' || content === '[DONE]') {\n formattedChunks.push(content);\n } else {\n // event: content_block_stop\n // data: {\"type\": \"content_block_stop\", \"index\": 0}\n formattedChunks.push(content);\n }\n }\n return formattedChunks.join('\\n\\n');\n };\n\n // 检测是否为流式响应\n const isStreamingResponse = (responseBody: any): boolean => {\n if (!responseBody) return false;\n const bodyStr = responseBody;\n // OpenAI格式: data: {...}\\n\\ndata: {...}\\n\\n\n // Anthropic格式: event: xxx\\ndata: {...}\\n\\nevent: xxx\\ndata: {...}\\n\\n\n const hasDataMarkers = bodyStr.includes('data:');\n const hasNewlinePairs = bodyStr.includes('\\n\\n');\n const hasEventMarkers = bodyStr.includes('event:');\n return (hasDataMarkers || hasNewlinePairs) || hasEventMarkers;\n };\n\n const parseModelFromRequest = (query: string, body: string): string | null => {\n try {\n const parsedQuery = query ? JSON.parse(query) : {};\n const parsedBody = body ? JSON.parse(body) : {};\n\n const model = parsedBody.model || parsedQuery.model;\n\n // 处理可能为数组的情况(如 message 格式)\n if (Array.isArray(model)) {\n const lastMessage = model[model.length - 1];\n if (lastMessage && typeof lastMessage === 'object' && 'model' in lastMessage) {\n return lastMessage.model;\n }\n }\n\n return typeof model === 'string' ? model : null;\n } catch {\n return null;\n }\n };\n\n const getStatusColor = (status: number) => {\n if (status >= 200 && status < 300) return 'text-green-600';\n if (status >= 400 && status < 500) return 'text-yellow-600';\n if (status >= 500) return 'text-red-600';\n return 'text-gray-600';\n };\n\n if (loading) {\n return (\n <>\n <Nav />\n <div className=\"min-h-screen flex items-center justify-center\">\n <div className=\"text-lg\">加载中...</div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <Nav />\n <main className=\"max-w-6xl mx-auto py-6 sm:px-6 lg:px-8\">\n <div className=\"px-4 py-4 sm:px-0\">\n <div className=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 className=\"text-lg font-bold text-slate-800\">请求日志</h1>\n <p className=\"text-xs text-slate-500 mt-1\">查看所有 API 请求记录和响应详情</p>\n </div>\n <div className=\"flex gap-2 items-center\">\n {/* 搜索框 */}\n <div className=\"relative group\">\n <input\n type=\"text\"\n placeholder=\"搜索日志...\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n onKeyPress={handleKeyPress}\n className=\"w-64 pl-9 pr-20 py-1.5 text-xs border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500/30 focus:border-emerald-500 transition-all\"\n />\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n {/* 操作按钮 */}\n <div className=\"absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1\">\n {searchInput ? (\n <>\n <button\n onClick={handleSearch}\n className=\"p-0.5 text-emerald-500 hover:text-emerald-600 hover:bg-emerald-50 rounded transition-colors\"\n title=\"确认搜索\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 13l4 4L19 7\" />\n </svg>\n </button>\n <button\n onClick={clearSearch}\n className=\"p-0.5 text-slate-400 hover:text-rose-500 hover:bg-rose-50 rounded transition-colors\"\n title=\"清除搜索\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </>\n ) : null}\n </div>\n </div>\n {selectedIds.length > 0 && (\n <button\n onClick={handleDeleteSelected}\n className=\"px-3 py-1.5 bg-rose-600 hover:bg-rose-700 text-white text-xs font-semibold rounded-lg border border-rose-200 transition-all duration-300\"\n >\n 删除选中 ({selectedIds.length})\n </button>\n )}\n <button\n onClick={handleClearAll}\n className=\"px-3 py-1.5 bg-slate-600 hover:bg-slate-700 text-white text-xs font-semibold rounded-lg border border-slate-200 transition-all duration-300\"\n >\n 清空所有\n </button>\n </div>\n </div>\n\n <div className=\"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 overflow-hidden\">\n <table className=\"min-w-full divide-y divide-slate-100\">\n <thead className=\"bg-emerald-50/30\">\n <tr>\n <th className=\"px-4 py-3.5 w-10\">\n <input\n type=\"checkbox\"\n checked={selectAll && logs.length > 0}\n onChange={(e) => handleSelectAll(e.target.checked)}\n className=\"w-4 h-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500\"\n />\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider\">\n 时间\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 模型\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 方法\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 路径\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 状态\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 响应时间\n </th>\n <th className=\"px-6 py-3.5 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 操作\n </th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-slate-100\">\n {logs.length === 0 ? (\n <tr>\n <td colSpan={8} className=\"px-4 py-12 text-center\">\n <div className=\"text-slate-400\">\n <svg className=\"mx-auto h-10 w-10 mb-3 text-slate-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n <p className=\"text-xs text-slate-500\">\n {searchQuery ? '未找到匹配的日志' : '暂无日志记录'}\n </p>\n {searchQuery && (\n <button\n onClick={() => {\n setSearchInput('');\n setSearchQuery('');\n }}\n className=\"mt-2 text-xs text-emerald-600 hover:text-emerald-700\"\n >\n 清除搜索\n </button>\n )}\n </div>\n </td>\n </tr>\n ) : (\n logs.map((log) => {\n const parsedModel = parseModelFromRequest(log.request_query, log.request_body);\n const displayModel = parsedModel || log.model_name || 'Gateway';\n\n return (\n <tr key={log.id} className=\"hover:bg-emerald-50/20 transition-colors duration-300\">\n <td className=\"px-4 py-3\">\n <input\n type=\"checkbox\"\n checked={selectedIds.includes(log.id)}\n onChange={(e) => handleSelectLog(log.id, e.target.checked)}\n className=\"w-4 h-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500\"\n onClick={(e) => e.stopPropagation()}\n />\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600\">\n {formatCreatedAt(log.created_at)}\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs\">\n <div className=\"font-medium text-slate-800\">{displayModel}</div>\n {log.provider_name && (\n <div className=\"text-[10px] text-slate-500\">{log.provider_name}</div>\n )}\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <span className={`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-lg border ${log.request_method === 'GET' ? 'bg-sky-50 text-sky-700 border-sky-200/50' :\n log.request_method === 'POST' ? 'bg-emerald-50 text-emerald-700 border-emerald-200/50' :\n 'bg-slate-50 text-slate-600 border-slate-200/50'\n }`}>\n {log.request_method}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"text-xs text-slate-600 font-mono max-w-xs truncate\">\n {log.request_path}\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <span className={`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-full border ${log.response_status >= 200 && log.response_status < 300 ? 'bg-emerald-100/80 text-emerald-700 border-emerald-200/50' :\n log.response_status >= 400 && log.response_status < 500 ? 'bg-amber-100/80 text-amber-700 border-amber-200/50' :\n log.response_status >= 500 ? 'bg-rose-100/80 text-rose-700 border-rose-200/50' :\n 'bg-slate-100/80 text-slate-600 border-slate-200/50'\n }`}>\n {log.response_status}\n </span>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600\">\n {log.response_time_ms}ms\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap text-right text-xs font-medium\">\n <button\n onClick={() => setSelectedLog(log)}\n className=\"text-emerald-600 hover:text-emerald-700 font-medium transition-colors duration-300\"\n >\n 查看详情\n </button>\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n\n <div className=\"mt-5 flex items-center justify-between\">\n <div className=\"text-xs text-slate-600\">\n {searchQuery ? (\n <span>\n 搜索 \"<span className=\"font-semibold text-slate-800\">{searchQuery}</span>\"\n 找到 <span className=\"font-semibold text-slate-800\">{total}</span> 条结果\n </span>\n ) : (\n <span>共 <span className=\"font-semibold text-slate-800\">{total}</span> 条记录</span>\n )}\n </div>\n <div className=\"flex space-x-2\">\n <button\n onClick={() => setPage(Math.max(0, page - 1))}\n disabled={page === 0}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 bg-white hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 上一页\n </button>\n <button\n onClick={() => setPage(page + 1)}\n disabled={(page + 1) * limit >= total}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 bg-white hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 下一页\n </button>\n </div>\n </div>\n </div>\n </main>\n\n {selectedLog && (\n <div className=\"fixed z-50 inset-0 overflow-y-auto\">\n <div className=\"flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\">\n <div className=\"fixed inset-0 bg-slate-900/40 backdrop-blur-sm transition-opacity\" onClick={() => setSelectedLog(null)}></div>\n <div className=\"inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full border border-emerald-100/50\">\n <div className=\"bg-white px-6 pt-5 pb-4 sm:p-6\">\n <div className=\"mb-5\">\n <h3 className=\"text-base font-bold text-slate-800 mb-1\">\n 请求详情\n </h3>\n <p className=\"text-xs text-slate-500\">查看完整的请求和响应信息</p>\n </div>\n <div className=\"space-y-4 max-h-[60vh] overflow-y-auto\">\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">请求头</h4>\n <button\n onClick={() => copyToClipboard(formatJSONSimple(selectedLog.request_headers))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatJSONSimple(selectedLog.request_headers)}\n </pre>\n </div>\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">请求 Query</h4>\n <button\n onClick={() => copyToClipboard(formatJSONSimple(selectedLog.request_query))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatJSONSimple(selectedLog.request_query)}\n </pre>\n </div>\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">请求 Body</h4>\n <button\n onClick={() => copyToClipboard(formatJSONSimple(selectedLog.request_body))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatJSONSimple(selectedLog.request_body)}\n </pre>\n </div>\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">响应 Body</h4>\n <div className=\"flex items-center gap-2\">\n {selectedLog && isStreamingResponse(selectedLog.response_body) && (\n <span className=\"px-2 py-0.5 text-xs bg-indigo-100 text-indigo-700 rounded-full border border-indigo-200\">\n 流式响应\n </span>\n )}\n <button\n onClick={() => copyToClipboard(formatRespon(selectedLog.response_body))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n </div>\n <div className=\"bg-slate-50/80 border border-slate-200 rounded-xl p-3 max-h-96 overflow-auto\">\n {(\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatRespon(selectedLog.response_body)}\n </pre>\n )}\n </div>\n </div>\n </div>\n <div className=\"mt-5 flex justify-end\">\n <button\n type=\"button\"\n onClick={() => setSelectedLog(null)}\n className=\"px-4 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-400/30 transition-all duration-300\"\n >\n 关闭\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {confirmDialog && (\n <ConfirmDialog\n open={confirmDialog.open}\n title={confirmDialog.title}\n message={confirmDialog.message}\n onConfirm={confirmDialog.onConfirm}\n onCancel={() => setConfirmDialog(null)}\n type=\"danger\"\n />\n )}\n </>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/app/logs/page.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport Nav from '../components/Nav';\nimport { useToast } from '../components/ToastProvider';\nimport ConfirmDialog from '../components/ConfirmDialog';\n\ninterface RequestLog {\n id: number;\n model_id: number | null;\n model_name?: string | null;\n provider_name?: string | null;\n request_method: string;\n request_path: string;\n request_headers: string;\n request_query: string;\n request_body: string;\n response_status: number;\n response_body: string;\n response_time_ms: number;\n created_at: string;\n}\n\n/** 将服务端返回的 created_at 格式化为本地显示。数据库存储的是本地时间,无需追加 Z 后缀。 */\nfunction formatCreatedAt(createdAt: string): string {\n if (!createdAt || typeof createdAt !== 'string') return '';\n const s = createdAt.trim();\n if (!s) return '';\n // 数据库使用 datetime('now','localtime') 存储的已经是本地时间,\n // 不带时区后缀时直接按本地时间解析,不要追加 'Z'(否则会多偏移 8 小时)\n const hasTz = /[Z+-]\\d{2}:?\\d{2}$/.test(s);\n const iso = hasTz ? s : s.replace(' ', 'T');\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? s : date.toLocaleString('zh-CN');\n}\n\nexport default function LogsPage() {\n const [logs, setLogs] = useState<RequestLog[]>([]);\n const [selectedLog, setSelectedLog] = useState<RequestLog | null>(null);\n const [loading, setLoading] = useState(true);\n const [page, setPage] = useState(0);\n const [total, setTotal] = useState(0);\n const [selectedIds, setSelectedIds] = useState<number[]>([]);\n const [selectAll, setSelectAll] = useState(false);\n const [confirmDialog, setConfirmDialog] = useState<{ open: boolean; title: string; message: string; onConfirm: () => void } | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [searchInput, setSearchInput] = useState('');\n const limit = 50;\n const { showToast } = useToast();\n\n const copyToClipboard = async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n showToast('已复制到剪贴板', 'success');\n } catch {\n showToast('复制失败,请手动复制', 'error');\n }\n };\n\n const handleDeleteSelected = async () => {\n if (selectedIds.length === 0) return;\n setConfirmDialog({\n open: true,\n title: '删除确认',\n message: `确定要删除选中的 ${selectedIds.length} 条日志吗?`,\n onConfirm: async () => {\n try {\n const res = await fetch(`/api/logs?ids=${selectedIds.join(',')}`, { method: 'DELETE' });\n const data = await res.json();\n if (res.ok) {\n setSelectedIds([]);\n setSelectAll(false);\n loadLogs();\n showToast('删除成功', 'success');\n setConfirmDialog(null);\n } else {\n showToast('删除失败:' + (data.error || '未知错误'), 'error');\n }\n } catch (error) {\n console.error('Failed to delete logs:', error);\n showToast('删除失败', 'error');\n }\n },\n });\n };\n\n const handleClearAll = async () => {\n setConfirmDialog({\n open: true,\n title: '清空日志',\n message: '确定要清空所有日志吗?此操作不可恢复!',\n onConfirm: async () => {\n try {\n const res = await fetch('/api/logs?clear_all=true', { method: 'DELETE' });\n const data = await res.json();\n if (res.ok) {\n setPage(0);\n setSelectedIds([]);\n setSelectAll(false);\n loadLogs();\n showToast('清空成功', 'success');\n setConfirmDialog(null);\n } else {\n showToast('清空失败:' + (data.error || '未知错误'), 'error');\n }\n } catch (error) {\n console.error('Failed to clear logs:', error);\n showToast('清空失败', 'error');\n }\n },\n });\n };\n\n const handleSelectAll = (checked: boolean) => {\n setSelectAll(checked);\n setSelectedIds(checked ? logs.map(log => log.id) : []);\n };\n\n const handleSelectLog = (id: number, checked: boolean) => {\n if (checked) {\n setSelectedIds([...selectedIds, id]);\n } else {\n setSelectedIds(selectedIds.filter(sid => sid !== id));\n setSelectAll(false);\n }\n };\n\n const loadLogs = async (search?: string) => {\n try {\n setLoading(true);\n const params = new URLSearchParams({\n limit: limit.toString(),\n offset: (page * limit).toString(),\n });\n if (search) {\n params.set('search', search);\n }\n const res = await fetch(`/api/logs?${params.toString()}`);\n const data = await res.json();\n setLogs(data.logs || []);\n setTotal(data.total || 0);\n } catch (error) {\n console.error('Failed to load logs:', error);\n showToast('加载日志失败', 'error');\n } finally {\n setLoading(false);\n }\n };\n\n // 手动触发搜索\n const handleSearch = () => {\n setSearchQuery(searchInput);\n setPage(0);\n loadLogs(searchInput);\n };\n\n // 清除搜索\n const clearSearch = () => {\n setSearchInput('');\n if (searchQuery) {\n setSearchQuery('');\n setPage(0);\n loadLogs();\n }\n };\n\n // 键盘搜索支持\n const handleKeyPress = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') {\n handleSearch();\n }\n };\n\n useEffect(() => {\n loadLogs();\n }, [page, limit]);\n\n const formatJSONSimple = (jsonString: string): string => {\n return typeof jsonString === 'string' ? jsonString : JSON.stringify(jsonString);\n }\n\n const formatRespon = (str: string): string => {\n if (isStreamingResponse(str)) {\n return formatSSEStream(str);\n }\n return formatJSONSimple(str);\n }\n\n const formatSSEStream = (responseBody: any): string => {\n if (!responseBody) return '';\n\n let sseData: string;\n try {\n sseData = JSON.parse(responseBody);\n } catch {\n sseData = responseBody;\n }\n\n if (!sseData.includes('data:') || !sseData.includes('\\n\\n')) {\n try {\n const parsed = JSON.parse(sseData);\n return JSON.stringify(parsed);\n } catch {\n return String(sseData);\n }\n }\n\n const chunks = sseData.split('\\n\\n').filter(chunk => chunk.trim());\n const formattedChunks: string[] = [];\n\n for (const chunk of chunks) {\n let content = chunk.trim();\n let tmp = content.split(\"\\n\").map((line) => {\n return line.startsWith(\"data: \") ? line.substring(6) : line;\n });\n content = tmp.join(\"\\n\");\n if (content === 'data: [DONE]' || content === '[DONE]') {\n formattedChunks.push(content);\n } else {\n // event: content_block_stop\n // data: {\"type\": \"content_block_stop\", \"index\": 0}\n formattedChunks.push(content);\n }\n }\n return formattedChunks.join('\\n\\n');\n };\n\n // 检测是否为流式响应\n const isStreamingResponse = (responseBody: any): boolean => {\n if (!responseBody) return false;\n const bodyStr = responseBody;\n // OpenAI格式: data: {...}\\n\\ndata: {...}\\n\\n\n // Anthropic格式: event: xxx\\ndata: {...}\\n\\nevent: xxx\\ndata: {...}\\n\\n\n const hasDataMarkers = bodyStr.includes('data:');\n const hasNewlinePairs = bodyStr.includes('\\n\\n');\n const hasEventMarkers = bodyStr.includes('event:');\n return (hasDataMarkers || hasNewlinePairs) || hasEventMarkers;\n };\n\n const parseModelFromRequest = (query: string, body: string): string | null => {\n try {\n const parsedQuery = query ? JSON.parse(query) : {};\n const parsedBody = body ? JSON.parse(body) : {};\n\n const model = parsedBody.model || parsedQuery.model;\n\n // 处理可能为数组的情况(如 message 格式)\n if (Array.isArray(model)) {\n const lastMessage = model[model.length - 1];\n if (lastMessage && typeof lastMessage === 'object' && 'model' in lastMessage) {\n return lastMessage.model;\n }\n }\n\n return typeof model === 'string' ? model : null;\n } catch {\n return null;\n }\n };\n\n const getStatusColor = (status: number) => {\n if (status >= 200 && status < 300) return 'text-green-600';\n if (status >= 400 && status < 500) return 'text-yellow-600';\n if (status >= 500) return 'text-red-600';\n return 'text-gray-600';\n };\n\n if (loading) {\n return (\n <>\n <Nav />\n <div className=\"min-h-screen flex items-center justify-center\">\n <div className=\"text-lg\">加载中...</div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <Nav />\n <main className=\"max-w-6xl mx-auto py-6 sm:px-6 lg:px-8\">\n <div className=\"px-4 py-4 sm:px-0\">\n <div className=\"mb-5 flex items-center justify-between\">\n <div>\n <h1 className=\"text-lg font-bold text-slate-800\">请求日志</h1>\n <p className=\"text-xs text-slate-500 mt-1\">查看所有 API 请求记录和响应详情</p>\n </div>\n <div className=\"flex gap-2 items-center\">\n {/* 搜索框 */}\n <div className=\"relative group\">\n <input\n type=\"text\"\n placeholder=\"搜索日志...\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n onKeyPress={handleKeyPress}\n className=\"w-64 pl-9 pr-20 py-1.5 text-xs border border-slate-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500/30 focus:border-emerald-500 transition-all\"\n />\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n {/* 操作按钮 */}\n <div className=\"absolute right-2 top-1/2 -translate-y-1/2 flex items-center gap-1\">\n {searchInput ? (\n <>\n <button\n onClick={handleSearch}\n className=\"p-0.5 text-emerald-500 hover:text-emerald-600 hover:bg-emerald-50 rounded transition-colors\"\n title=\"确认搜索\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 13l4 4L19 7\" />\n </svg>\n </button>\n <button\n onClick={clearSearch}\n className=\"p-0.5 text-slate-400 hover:text-rose-500 hover:bg-rose-50 rounded transition-colors\"\n title=\"清除搜索\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </>\n ) : null}\n </div>\n </div>\n {selectedIds.length > 0 && (\n <button\n onClick={handleDeleteSelected}\n className=\"px-3 py-1.5 bg-rose-600 hover:bg-rose-700 text-white text-xs font-semibold rounded-lg border border-rose-200 transition-all duration-300\"\n >\n 删除选中 ({selectedIds.length})\n </button>\n )}\n <button\n onClick={handleClearAll}\n className=\"px-3 py-1.5 bg-slate-600 hover:bg-slate-700 text-white text-xs font-semibold rounded-lg border border-slate-200 transition-all duration-300\"\n >\n 清空所有\n </button>\n </div>\n </div>\n\n <div className=\"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 overflow-hidden\">\n <table className=\"min-w-full divide-y divide-slate-100\">\n <thead className=\"bg-emerald-50/30\">\n <tr>\n <th className=\"px-4 py-3.5 w-10\">\n <input\n type=\"checkbox\"\n checked={selectAll && logs.length > 0}\n onChange={(e) => handleSelectAll(e.target.checked)}\n className=\"w-4 h-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500\"\n />\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider\">\n 时间\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 模型\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 方法\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 路径\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 状态\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 响应时间\n </th>\n <th className=\"px-6 py-3.5 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 操作\n </th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-slate-100\">\n {logs.length === 0 ? (\n <tr>\n <td colSpan={8} className=\"px-4 py-12 text-center\">\n <div className=\"text-slate-400\">\n <svg className=\"mx-auto h-10 w-10 mb-3 text-slate-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n <p className=\"text-xs text-slate-500\">\n {searchQuery ? '未找到匹配的日志' : '暂无日志记录'}\n </p>\n {searchQuery && (\n <button\n onClick={() => {\n setSearchInput('');\n setSearchQuery('');\n }}\n className=\"mt-2 text-xs text-emerald-600 hover:text-emerald-700\"\n >\n 清除搜索\n </button>\n )}\n </div>\n </td>\n </tr>\n ) : (\n logs.map((log) => {\n const parsedModel = parseModelFromRequest(log.request_query, log.request_body);\n const displayModel = parsedModel || log.model_name || 'Gateway';\n\n return (\n <tr key={log.id} className=\"hover:bg-emerald-50/20 transition-colors duration-300\">\n <td className=\"px-4 py-3\">\n <input\n type=\"checkbox\"\n checked={selectedIds.includes(log.id)}\n onChange={(e) => handleSelectLog(log.id, e.target.checked)}\n className=\"w-4 h-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500\"\n onClick={(e) => e.stopPropagation()}\n />\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600\">\n {formatCreatedAt(log.created_at)}\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs\">\n <div className=\"font-medium text-slate-800\">{displayModel}</div>\n {log.provider_name && (\n <div className=\"text-[10px] text-slate-500\">{log.provider_name}</div>\n )}\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <span className={`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-lg border ${log.request_method === 'GET' ? 'bg-sky-50 text-sky-700 border-sky-200/50' :\n log.request_method === 'POST' ? 'bg-emerald-50 text-emerald-700 border-emerald-200/50' :\n 'bg-slate-50 text-slate-600 border-slate-200/50'\n }`}>\n {log.request_method}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"text-xs text-slate-600 font-mono max-w-xs truncate\">\n {log.request_path}\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <span className={`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-full border ${log.response_status >= 200 && log.response_status < 300 ? 'bg-emerald-100/80 text-emerald-700 border-emerald-200/50' :\n log.response_status >= 400 && log.response_status < 500 ? 'bg-amber-100/80 text-amber-700 border-amber-200/50' :\n log.response_status >= 500 ? 'bg-rose-100/80 text-rose-700 border-rose-200/50' :\n 'bg-slate-100/80 text-slate-600 border-slate-200/50'\n }`}>\n {log.response_status}\n </span>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600\">\n {log.response_time_ms}ms\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap text-right text-xs font-medium\">\n <button\n onClick={() => setSelectedLog(log)}\n className=\"text-emerald-600 hover:text-emerald-700 font-medium transition-colors duration-300\"\n >\n 查看详情\n </button>\n </td>\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n\n <div className=\"mt-5 flex items-center justify-between\">\n <div className=\"text-xs text-slate-600\">\n {searchQuery ? (\n <span>\n 搜索 \"<span className=\"font-semibold text-slate-800\">{searchQuery}</span>\"\n 找到 <span className=\"font-semibold text-slate-800\">{total}</span> 条结果\n </span>\n ) : (\n <span>共 <span className=\"font-semibold text-slate-800\">{total}</span> 条记录</span>\n )}\n </div>\n <div className=\"flex space-x-2\">\n <button\n onClick={() => setPage(Math.max(0, page - 1))}\n disabled={page === 0}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 bg-white hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 上一页\n </button>\n <button\n onClick={() => setPage(page + 1)}\n disabled={(page + 1) * limit >= total}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-medium text-slate-600 bg-white hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 下一页\n </button>\n </div>\n </div>\n </div>\n </main>\n\n {selectedLog && (\n <div className=\"fixed z-50 inset-0 overflow-y-auto\">\n <div className=\"flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\">\n <div className=\"fixed inset-0 bg-slate-900/40 backdrop-blur-sm transition-opacity\" onClick={() => setSelectedLog(null)}></div>\n <div className=\"inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-3xl sm:w-full border border-emerald-100/50\">\n <div className=\"bg-white px-6 pt-5 pb-4 sm:p-6\">\n <div className=\"mb-5\">\n <h3 className=\"text-base font-bold text-slate-800 mb-1\">\n 请求详情\n </h3>\n <p className=\"text-xs text-slate-500\">查看完整的请求和响应信息</p>\n </div>\n <div className=\"space-y-4 max-h-[60vh] overflow-y-auto\">\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">请求头</h4>\n <button\n onClick={() => copyToClipboard(formatJSONSimple(selectedLog.request_headers))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatJSONSimple(selectedLog.request_headers)}\n </pre>\n </div>\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">请求 Query</h4>\n <button\n onClick={() => copyToClipboard(formatJSONSimple(selectedLog.request_query))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatJSONSimple(selectedLog.request_query)}\n </pre>\n </div>\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">请求 Body</h4>\n <button\n onClick={() => copyToClipboard(formatJSONSimple(selectedLog.request_body))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatJSONSimple(selectedLog.request_body)}\n </pre>\n </div>\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <h4 className=\"text-xs font-semibold text-slate-700\">响应 Body</h4>\n <div className=\"flex items-center gap-2\">\n {selectedLog && isStreamingResponse(selectedLog.response_body) && (\n <span className=\"px-2 py-0.5 text-xs bg-indigo-100 text-indigo-700 rounded-full border border-indigo-200\">\n 流式响应\n </span>\n )}\n <button\n onClick={() => copyToClipboard(formatRespon(selectedLog.response_body))}\n className=\"px-2 py-0.5 text-xs text-emerald-600 hover:text-emerald-700 font-medium transition-colors\"\n >\n 复制\n </button>\n </div>\n </div>\n <div className=\"bg-slate-50/80 border border-slate-200 rounded-xl p-3 max-h-96 overflow-auto\">\n {(\n <pre className=\"bg-slate-50/80 border border-slate-200 p-3 rounded-xl text-[10px] overflow-x-auto font-mono text-slate-700\">\n {formatRespon(selectedLog.response_body)}\n </pre>\n )}\n </div>\n </div>\n </div>\n <div className=\"mt-5 flex justify-end\">\n <button\n type=\"button\"\n onClick={() => setSelectedLog(null)}\n className=\"px-4 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-400/30 transition-all duration-300\"\n >\n 关闭\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {confirmDialog && (\n <ConfirmDialog\n open={confirmDialog.open}\n title={confirmDialog.title}\n message={confirmDialog.message}\n onConfirm={confirmDialog.onConfirm}\n onCancel={() => setConfirmDialog(null)}\n type=\"danger\"\n />\n )}\n </>\n );\n}\n"],"names":["formatCreatedAt","createdAt","s","trim","hasTz","test","iso","replace","date","Date","Number","isNaN","getTime","toLocaleString","LogsPage","logs","setLogs","selectedLog","setSelectedLog","loading","setLoading","page","setPage","total","setTotal","selectedIds","setSelectedIds","selectAll","setSelectAll","confirmDialog","setConfirmDialog","searchQuery","setSearchQuery","searchInput","setSearchInput","limit","showToast","copyToClipboard","text","navigator","clipboard","writeText","handleDeleteSelected","length","open","title","message","onConfirm","res","fetch","join","method","data","json","ok","loadLogs","error","console","handleClearAll","handleSelectAll","checked","map","log","id","handleSelectLog","filter","sid","search","params","URLSearchParams","toString","offset","set","handleSearch","clearSearch","handleKeyPress","e","key","formatJSONSimple","jsonString","JSON","stringify","formatRespon","str","isStreamingResponse","formatSSEStream","responseBody","sseData","parse","includes","parsed","String","chunks","split","chunk","formattedChunks","content","tmp","line","startsWith","substring","push","bodyStr","hasDataMarkers","hasNewlinePairs","hasEventMarkers","parseModelFromRequest","query","body","parsedQuery","parsedBody","model","Array","isArray","lastMessage","getStatusColor","status","className","type","placeholder","value","onChange","target","onKeyPress","fill","stroke","viewBox","strokeLinecap","strokeLinejoin","strokeWidth","d","onClick","colSpan","parsedModel","request_query","request_body","displayModel","model_name","stopPropagation","created_at","provider_name","request_method","request_path","response_status","response_time_ms","Math","max","disabled","request_headers","response_body","onCancel"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
module.exports=[17291,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(81844),e=a.i(21215),f=a.i(71862);a.s(["default",0,function(){let a,[g,h]=(0,c.useState)([]),[i,j]=(0,c.useState)([]),[k,l]=(0,c.useState)([]),[m,n]=(0,c.useState)(!0),[o,p]=(0,c.useState)(!1),[q,r]=(0,c.useState)(!1),[s,t]=(0,c.useState)(!1),[u,v]=(0,c.useState)(null),[w,x]=(0,c.useState)(null),[y,z]=(0,c.useState)(null),[A,B]=(0,c.useState)(""),[C,D]=(0,c.useState)(1),[E,F]=(0,c.useState)(!1),[G,H]=(0,c.useState)({provider_id:"",name:"",model_id:"",enabled:!0}),{showToast:I}=(0,e.useToast)();(0,c.useEffect)(()=>{M()},[]);let J=(a=(C-1)*20,i.slice(a,a+20)),K=Math.ceil(i.length/20),L=(0,c.useCallback)(()=>{let a=[...g];if(null!==y&&(a=a.filter(a=>a.provider_id===y)),E&&(a=a.filter(a=>a.enabled)),A.trim()){let b=A.toLowerCase().trim();a=a.filter(a=>a.name.toLowerCase().includes(b)||a.model_id.toLowerCase().includes(b)||a.provider_name?.toLowerCase().includes(b)||a.provider_protocol?.toLowerCase().includes(b))}j(a)},[g,y,E,A]);(0,c.useEffect)(()=>{D(1)},[y,E,A]),(0,c.useEffect)(()=>{L()},[L]);let M=async()=>{try{let[a,b]=await Promise.all([fetch("/api/models"),fetch("/api/providers")]),c=await a.json(),d=await b.json();h(c),l(d)}catch(a){console.error("Failed to load data:",a)}finally{n(!1)}},N=async a=>{a.preventDefault();try{await fetch("/api/models",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...G,provider_id:parseInt(G.provider_id)})}),p(!1),H({provider_id:"",name:"",model_id:"",enabled:!0}),M(),I("模型添加成功","success")}catch(a){console.error("Failed to save model:",a),I("保存失败","error")}},O=async(a,b)=>{try{await fetch("/api/models",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:a,enabled:!b})}),M()}catch(a){console.error("Failed to update model:",a)}},P=async()=>{if(u)try{await fetch(`/api/models?id=${u}`,{method:"DELETE"}),M(),I("模型已删除","success")}catch(a){console.error("Failed to delete model:",a),I("删除失败","error")}r(!1),v(null)},Q=async()=>{if(w)try{let a=await fetch("/api/models",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({provider_id:w})}),b=await a.json();if(!a.ok)return void I(b.error||"拉取失败","error");let c=b.count??0;I(`成功拉取 ${c} 个模型`,"success"),M()}catch(a){console.error("Failed to fetch models:",a),I("拉取失败: "+a.message,"error")}t(!1),x(null)};return m?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(d.default,{}),(0,b.jsx)("div",{className:"min-h-screen flex items-center justify-center",children:(0,b.jsx)("div",{className:"text-lg",children:"加载中..."})})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(d.default,{}),(0,b.jsx)("main",{className:"max-w-6xl mx-auto py-6 sm:px-6 lg:px-8",children:(0,b.jsxs)("div",{className:"px-4 py-4 sm:px-0",children:[(0,b.jsxs)("div",{className:"flex justify-between items-center mb-5",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-lg font-bold text-slate-800",children:"模型管理"}),(0,b.jsx)("p",{className:"text-xs text-slate-500 mt-1",children:"管理 AI 模型配置和状态"})]}),(0,b.jsxs)("button",{onClick:()=>{H({provider_id:"",name:"",model_id:"",enabled:!0}),p(!0)},className:"inline-flex items-center px-3.5 py-1.5 border border-transparent text-xs font-semibold rounded-lg shadow-sm text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 transition-all duration-300",children:[(0,b.jsx)("svg",{className:"w-3.5 h-3.5 mr-1.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 4v16m8-8H4"})}),"手动添加"]})]}),(0,b.jsxs)("div",{className:"mb-5 bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 p-5",children:[(0,b.jsx)("div",{className:"flex items-center justify-between mb-4",children:(0,b.jsxs)("div",{children:[(0,b.jsx)("h2",{className:"text-sm font-bold text-slate-800",children:"快捷拉取"}),(0,b.jsx)("p",{className:"text-xs text-slate-500 mt-0.5",children:"从供应商 API 自动拉取可用模型"})]})}),(0,b.jsx)("div",{className:"grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3",children:k.map(a=>(0,b.jsxs)("div",{className:"flex items-center justify-between p-3 border border-slate-200 rounded-xl hover:border-emerald-300 hover:shadow-sm transition-all duration-300 cursor-pointer bg-white/80 backdrop-blur-sm",children:[(0,b.jsxs)("div",{className:"flex-1",children:[(0,b.jsx)("div",{className:"font-semibold text-xs text-slate-800",children:a.name}),(0,b.jsx)("div",{className:"text-[10px] text-slate-500 mt-0.5",children:a.protocol})]}),(0,b.jsxs)("button",{onClick:()=>{x(a.id),t(!0)},className:"ml-3 inline-flex items-center px-2.5 py-1 border border-transparent text-[10px] font-semibold rounded-lg text-emerald-700 bg-emerald-50 hover:bg-emerald-100 transition-all duration-300",children:[(0,b.jsx)("svg",{className:"w-3 h-3 mr-1",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"})}),"拉取"]})]},a.id))})]}),(0,b.jsxs)("div",{className:"mb-5 bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 p-5",children:[(0,b.jsxs)("div",{className:"flex flex-col sm:flex-row gap-4",children:[(0,b.jsxs)("div",{className:"flex-1",children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"按供应商筛选"}),(0,b.jsxs)("select",{value:y??"",onChange:a=>z(a.target.value?parseInt(a.target.value):null),className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1",children:[(0,b.jsx)("option",{value:"",children:"全部供应商"}),k.map(a=>(0,b.jsxs)("option",{value:a.id,children:[a.name," (",a.protocol,")"]},a.id))]})]}),(0,b.jsxs)("div",{className:"flex-1",children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"搜索模型"}),(0,b.jsxs)("div",{className:"relative",children:[(0,b.jsx)("input",{type:"text",value:A,onChange:a=>B(a.target.value),placeholder:"搜索模型名称、ID、供应商...",className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 pl-9 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1"}),(0,b.jsx)("svg",{className:"absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})}),A&&(0,b.jsx)("button",{onClick:()=>B(""),className:"absolute right-2 top-1/2 -translate-y-1/2 p-1 text-slate-400 hover:text-slate-600 transition-colors",children:(0,b.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]})]}),(0,b.jsx)("div",{className:"flex items-center",children:(0,b.jsxs)("label",{className:"flex items-center cursor-pointer",children:[(0,b.jsx)("input",{type:"checkbox",checked:E,onChange:a=>F(a.target.checked),className:"w-4 h-4 text-emerald-600 border-slate-300 rounded focus:ring-emerald-500 transition-all duration-300"}),(0,b.jsx)("span",{className:"ml-2 text-xs font-semibold text-slate-700",children:"仅已启用"})]})})]}),(null!==y||A.trim()||E)&&(0,b.jsxs)("div",{className:"mt-3 text-xs text-slate-500",children:["显示 ",i.length," 个模型,第 ",(C-1)*20+1,"-",Math.min(20*C,i.length)," 个"]})]}),(0,b.jsxs)("div",{className:"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 overflow-hidden",children:[(0,b.jsx)("div",{className:"overflow-x-auto",children:(0,b.jsxs)("table",{className:"min-w-full divide-y divide-slate-100",children:[(0,b.jsx)("thead",{className:"bg-emerald-50/30",children:(0,b.jsxs)("tr",{children:[(0,b.jsx)("th",{className:"px-4 py-2.5 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider",children:"名称"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"模型 ID"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"供应商"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"状态"}),(0,b.jsx)("th",{className:"px-6 py-3.5 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider",children:"操作"})]})}),(0,b.jsx)("tbody",{className:"bg-white divide-y divide-slate-100",children:0===J.length?(0,b.jsx)("tr",{children:(0,b.jsx)("td",{colSpan:5,className:"px-4 py-12 text-center",children:(0,b.jsx)("div",{className:"text-slate-400",children:0===g.length?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("svg",{className:"mx-auto h-10 w-10 mb-3 text-slate-300",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"})}),(0,b.jsx)("p",{className:"text-xs text-slate-500",children:"暂无模型,请先添加或拉取模型"})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)("svg",{className:"mx-auto h-10 w-10 mb-3 text-slate-300",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:1.5,d:"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"})}),(0,b.jsx)("p",{className:"text-xs text-slate-500",children:"没有找到匹配的模型"}),(null!==y||A.trim()||E)&&(0,b.jsx)("button",{onClick:()=>{z(null),B(""),F(!1)},className:"mt-2 text-xs text-emerald-600 hover:text-emerald-700 underline",children:"清除筛选条件"})]})})})}):J.map(a=>(0,b.jsxs)("tr",{className:"hover:bg-emerald-50/20 transition-colors duration-300",children:[(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsx)("div",{className:"text-xs font-medium text-slate-800",children:a.name})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsx)("div",{className:"text-xs text-slate-600 font-mono",children:a.model_id})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsxs)("div",{className:"text-xs text-slate-600",children:[(0,b.jsx)("span",{className:"font-medium",children:a.provider_name}),(0,b.jsxs)("span",{className:"text-slate-400 ml-1",children:["(",a.provider_protocol,")"]})]})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap",children:(0,b.jsx)("span",{className:`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-full border ${a.enabled?"bg-emerald-100/80 text-emerald-700 border-emerald-200/50":"bg-slate-100/80 text-slate-600 border-slate-200/50"}`,children:a.enabled?"启用":"禁用"})}),(0,b.jsx)("td",{className:"px-4 py-3 whitespace-nowrap text-right text-xs font-medium",children:(0,b.jsxs)("div",{className:"flex items-center justify-end space-x-3",children:[(0,b.jsx)("button",{onClick:()=>O(a.id,a.enabled),className:"text-emerald-600 hover:text-emerald-700 font-medium transition-colors duration-300",children:a.enabled?"禁用":"启用"}),(0,b.jsx)("button",{onClick:()=>{v(a.id),r(!0)},className:"text-rose-500 hover:text-rose-600 font-medium transition-colors duration-300",children:"删除"})]})})]},a.id))})]})}),K>1&&(0,b.jsxs)("div",{className:"mt-4 flex items-center justify-between px-4 py-3 bg-emerald-50/20 border-t border-emerald-100/50",children:[(0,b.jsxs)("div",{className:"text-xs text-slate-600",children:["第 ",(0,b.jsx)("span",{className:"font-semibold text-slate-800",children:C})," / ",K," 页"]}),(0,b.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,b.jsx)("button",{onClick:()=>D(a=>Math.max(1,a-1)),disabled:1===C,className:"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-emerald-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300",children:"上一页"}),(0,b.jsx)("div",{className:"flex items-center space-x-1",children:Array.from({length:K},(a,b)=>b+1).filter(a=>2>Math.abs(a-C)||1===a||a===K).sort((a,b)=>a-b).map(a=>(0,b.jsx)("button",{onClick:()=>D(a),className:`w-8 h-8 font-semibold text-xs rounded-lg transition-all duration-300 ${C===a?"bg-emerald-600 text-white shadow-md":"bg-white text-slate-600 border border-slate-200 hover:bg-emerald-50 hover:border-emerald-300"}`,children:a},a))}),(0,b.jsx)("button",{onClick:()=>D(a=>Math.min(K,a+1)),disabled:C===K,className:"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-emerald-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300",children:"下一页"})]})]})]})]})}),o&&(0,b.jsx)("div",{className:"fixed z-50 inset-0 overflow-y-auto",children:(0,b.jsxs)("div",{className:"flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0",children:[(0,b.jsx)("div",{className:"fixed inset-0 bg-slate-900/40 backdrop-blur-sm transition-opacity",onClick:()=>p(!1)}),(0,b.jsx)("div",{className:"inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full border border-emerald-100/50",children:(0,b.jsxs)("form",{onSubmit:N,className:"bg-white px-6 pt-5 pb-4 sm:p-6",children:[(0,b.jsxs)("div",{className:"mb-5",children:[(0,b.jsx)("h3",{className:"text-base font-bold text-slate-800 mb-1",children:"添加模型"}),(0,b.jsx)("p",{className:"text-xs text-slate-500",children:"手动添加新的 AI 模型"})]}),(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"供应商"}),(0,b.jsxs)("select",{required:!0,value:G.provider_id,onChange:a=>H({...G,provider_id:a.target.value}),autoComplete:"off",className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1",children:[(0,b.jsx)("option",{value:"",children:"选择供应商"}),k.map(a=>(0,b.jsx)("option",{value:a.id,children:a.name},a.id))]})]}),(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"名称"}),(0,b.jsx)("input",{type:"text",required:!0,value:G.name,onChange:a=>H({...G,name:a.target.value}),autoComplete:"off",className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1",placeholder:"例如: GPT-4"})]}),(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"模型 ID"}),(0,b.jsx)("input",{type:"text",required:!0,value:G.model_id,onChange:a=>H({...G,model_id:a.target.value}),autoComplete:"off",className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1",placeholder:"例如: gpt-4"})]})]}),(0,b.jsxs)("div",{className:"mt-5 flex items-center justify-end space-x-2",children:[(0,b.jsx)("button",{type:"button",onClick:()=>p(!1),className:"px-3.5 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-400/30 transition-all duration-300",children:"取消"}),(0,b.jsx)("button",{type:"submit",className:"px-4 py-1.5 border border-transparent rounded-lg text-xs font-semibold text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 transition-all duration-300",children:"保存"})]})]})})]})}),(0,b.jsx)(f.default,{open:q,title:"确认删除",message:"确定要删除这个模型吗?此操作不可恢复。",onConfirm:P,onCancel:()=>{r(!1),v(null)},confirmText:"删除",cancelText:"取消",type:"danger"}),(0,b.jsx)(f.default,{open:s,title:"拉取模型列表",message:"确定要从供应商拉取模型列表吗?",onConfirm:Q,onCancel:()=>{t(!1),x(null)},confirmText:"拉取",cancelText:"取消",type:"info"})]})}])}];
|
|
2
|
+
|
|
3
|
+
//# sourceMappingURL=src_app_models_page_tsx_10vsbc1._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app/models/page.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport Nav from '../components/Nav';\nimport { useToast } from '../components/ToastProvider';\nimport ConfirmDialog from '../components/ConfirmDialog';\n\ninterface Model {\n id: number;\n provider_id: number;\n name: string;\n model_id: string;\n enabled: boolean;\n provider_name?: string;\n provider_protocol?: string;\n}\n\ninterface Provider {\n id: number;\n name: string;\n protocol: string;\n}\n\nexport default function ModelsPage() {\n const [models, setModels] = useState<Model[]>([]);\n const [filteredModels, setFilteredModels] = useState<Model[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [loading, setLoading] = useState(true);\n const [showModal, setShowModal] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [showFetchConfirm, setShowFetchConfirm] = useState(false);\n const [deleteId, setDeleteId] = useState<number | null>(null);\n const [fetchProviderId, setFetchProviderId] = useState<number | null>(null);\n const [selectedProviderId, setSelectedProviderId] = useState<number | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [currentPage, setCurrentPage] = useState(1);\n const [showEnabledOnly, setShowEnabledOnly] = useState(false);\n const pageSize = 20;\n const [formData, setFormData] = useState({\n provider_id: '',\n name: '',\n model_id: '',\n enabled: true,\n });\n const { showToast } = useToast();\n\n useEffect(() => {\n loadData();\n }, []);\n\n // 计算分页数据\n const paginatedModels = (() => {\n const startIndex = (currentPage - 1) * pageSize;\n const endIndex = startIndex + pageSize;\n return filteredModels.slice(startIndex, endIndex);\n })();\n\n const totalPages = Math.ceil(filteredModels.length / pageSize);\n\n const filterModels = useCallback(() => {\n let filtered = [...models];\n\n // 按供应商筛选\n if (selectedProviderId !== null) {\n filtered = filtered.filter(model => model.provider_id === selectedProviderId);\n }\n\n // 按启用状态筛选\n if (showEnabledOnly) {\n filtered = filtered.filter(model => model.enabled);\n }\n\n // 搜索筛选\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase().trim();\n filtered = filtered.filter(model =>\n model.name.toLowerCase().includes(query) ||\n model.model_id.toLowerCase().includes(query) ||\n model.provider_name?.toLowerCase().includes(query) ||\n model.provider_protocol?.toLowerCase().includes(query)\n );\n }\n\n setFilteredModels(filtered);\n }, [models, selectedProviderId, showEnabledOnly, searchQuery]);\n\n // 筛选或搜索时重置到第一页\n useEffect(() => {\n setCurrentPage(1);\n }, [selectedProviderId, showEnabledOnly, searchQuery]);\n\n useEffect(() => {\n filterModels();\n }, [filterModels]);\n\n const loadData = async () => {\n try {\n const [modelsRes, providersRes] = await Promise.all([\n fetch('/api/models'),\n fetch('/api/providers'),\n ]);\n const modelsData = await modelsRes.json();\n const providersData = await providersRes.json();\n setModels(modelsData);\n setProviders(providersData);\n } catch (error) {\n console.error('Failed to load data:', error);\n } finally {\n setLoading(false);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n try {\n await fetch('/api/models', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...formData,\n provider_id: parseInt(formData.provider_id),\n }),\n });\n setShowModal(false);\n setFormData({ provider_id: '', name: '', model_id: '', enabled: true });\n loadData();\n showToast('模型添加成功', 'success');\n } catch (error) {\n console.error('Failed to save model:', error);\n showToast('保存失败', 'error');\n }\n };\n\n const handleToggleEnabled = async (id: number, enabled: boolean) => {\n try {\n await fetch('/api/models', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id, enabled: !enabled }),\n });\n loadData();\n } catch (error) {\n console.error('Failed to update model:', error);\n }\n };\n\n const handleDelete = (id: number) => {\n setDeleteId(id);\n setShowDeleteConfirm(true);\n };\n\n const confirmDelete = async () => {\n if (deleteId) {\n try {\n await fetch(`/api/models?id=${deleteId}`, { method: 'DELETE' });\n loadData();\n showToast('模型已删除', 'success');\n } catch (error) {\n console.error('Failed to delete model:', error);\n showToast('删除失败', 'error');\n }\n }\n setShowDeleteConfirm(false);\n setDeleteId(null);\n };\n\n const handleFetchModels = (providerId: number) => {\n setFetchProviderId(providerId);\n setShowFetchConfirm(true);\n };\n\n const confirmFetch = async () => {\n if (fetchProviderId) {\n try {\n const res = await fetch('/api/models', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ provider_id: fetchProviderId }),\n });\n const data = await res.json();\n if (!res.ok) {\n showToast(data.error || '拉取失败', 'error');\n return;\n }\n const count = data.count ?? 0;\n showToast(`成功拉取 ${count} 个模型`, 'success');\n loadData();\n } catch (error: any) {\n console.error('Failed to fetch models:', error);\n showToast('拉取失败: ' + error.message, 'error');\n }\n }\n setShowFetchConfirm(false);\n setFetchProviderId(null);\n };\n\n if (loading) {\n return (\n <>\n <Nav />\n <div className=\"min-h-screen flex items-center justify-center\">\n <div className=\"text-lg\">加载中...</div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <Nav />\n <main className=\"max-w-6xl mx-auto py-6 sm:px-6 lg:px-8\">\n <div className=\"px-4 py-4 sm:px-0\">\n <div className=\"flex justify-between items-center mb-5\">\n <div>\n <h1 className=\"text-lg font-bold text-slate-800\">模型管理</h1>\n <p className=\"text-xs text-slate-500 mt-1\">管理 AI 模型配置和状态</p>\n </div>\n <button\n onClick={() => {\n setFormData({ provider_id: '', name: '', model_id: '', enabled: true });\n setShowModal(true);\n }}\n className=\"inline-flex items-center px-3.5 py-1.5 border border-transparent text-xs font-semibold rounded-lg shadow-sm text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 transition-all duration-300\"\n >\n <svg className=\"w-3.5 h-3.5 mr-1.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n 手动添加\n </button>\n </div>\n\n {/* 一键拉取模型列表 - 移到列表上方 */}\n <div className=\"mb-5 bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 p-5\">\n <div className=\"flex items-center justify-between mb-4\">\n <div>\n <h2 className=\"text-sm font-bold text-slate-800\">快捷拉取</h2>\n <p className=\"text-xs text-slate-500 mt-0.5\">从供应商 API 自动拉取可用模型</p>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3\">\n {providers.map((provider) => (\n <div key={provider.id} className=\"flex items-center justify-between p-3 border border-slate-200 rounded-xl hover:border-emerald-300 hover:shadow-sm transition-all duration-300 cursor-pointer bg-white/80 backdrop-blur-sm\">\n <div className=\"flex-1\">\n <div className=\"font-semibold text-xs text-slate-800\">{provider.name}</div>\n <div className=\"text-[10px] text-slate-500 mt-0.5\">{provider.protocol}</div>\n </div>\n <button\n onClick={() => handleFetchModels(provider.id)}\n className=\"ml-3 inline-flex items-center px-2.5 py-1 border border-transparent text-[10px] font-semibold rounded-lg text-emerald-700 bg-emerald-50 hover:bg-emerald-100 transition-all duration-300\"\n >\n <svg className=\"w-3 h-3 mr-1\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n 拉取\n </button>\n </div>\n ))}\n </div>\n </div>\n\n {/* 筛选和搜索栏 */}\n <div className=\"mb-5 bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 p-5\">\n <div className=\"flex flex-col sm:flex-row gap-4\">\n {/* 供应商筛选 */}\n <div className=\"flex-1\">\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">按供应商筛选</label>\n <select\n value={selectedProviderId ?? ''}\n onChange={(e) => setSelectedProviderId(e.target.value ? parseInt(e.target.value) : null)}\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n >\n <option value=\"\">全部供应商</option>\n {providers.map((provider) => (\n <option key={provider.id} value={provider.id}>\n {provider.name} ({provider.protocol})\n </option>\n ))}\n </select>\n </div>\n {/* 搜索框 */}\n <div className=\"flex-1\">\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">搜索模型</label>\n <div className=\"relative\">\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder=\"搜索模型名称、ID、供应商...\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 pl-9 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n />\n <svg className=\"absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n {searchQuery && (\n <button\n onClick={() => setSearchQuery('')}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 text-slate-400 hover:text-slate-600 transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n {/* 仅显示已启用 */}\n <div className=\"flex items-center\">\n <label className=\"flex items-center cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={showEnabledOnly}\n onChange={(e) => setShowEnabledOnly(e.target.checked)}\n className=\"w-4 h-4 text-emerald-600 border-slate-300 rounded focus:ring-emerald-500 transition-all duration-300\"\n />\n <span className=\"ml-2 text-xs font-semibold text-slate-700\">仅已启用</span>\n </label>\n </div>\n </div>\n {/* 结果统计 */}\n {(selectedProviderId !== null || searchQuery.trim() || showEnabledOnly) && (\n <div className=\"mt-3 text-xs text-slate-500\">\n 显示 {filteredModels.length} 个模型,第 {(currentPage - 1) * pageSize + 1}-{Math.min(currentPage * pageSize, filteredModels.length)} 个\n </div>\n )}\n </div>\n\n <div className=\"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full divide-y divide-slate-100\">\n <thead className=\"bg-emerald-50/30\">\n <tr>\n <th className=\"px-4 py-2.5 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider\">\n 名称\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 模型 ID\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 供应商\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 状态\n </th>\n <th className=\"px-6 py-3.5 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 操作\n </th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-slate-100\">\n {paginatedModels.length === 0 ? (\n <tr>\n <td colSpan={5} className=\"px-4 py-12 text-center\">\n <div className=\"text-slate-400\">\n {models.length === 0 ? (\n <>\n <svg className=\"mx-auto h-10 w-10 mb-3 text-slate-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4\" />\n </svg>\n <p className=\"text-xs text-slate-500\">暂无模型,请先添加或拉取模型</p>\n </>\n ) : (\n <>\n <svg className=\"mx-auto h-10 w-10 mb-3 text-slate-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <p className=\"text-xs text-slate-500\">没有找到匹配的模型</p>\n {(selectedProviderId !== null || searchQuery.trim() || showEnabledOnly) && (\n <button\n onClick={() => {\n setSelectedProviderId(null);\n setSearchQuery('');\n setShowEnabledOnly(false);\n }}\n className=\"mt-2 text-xs text-emerald-600 hover:text-emerald-700 underline\"\n >\n 清除筛选条件\n </button>\n )}\n </>\n )}\n </div>\n </td>\n </tr>\n ) : (\n paginatedModels.map((model) => (\n <tr key={model.id} className=\"hover:bg-emerald-50/20 transition-colors duration-300\">\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs font-medium text-slate-800\">{model.name}</div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600 font-mono\">{model.model_id}</div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600\">\n <span className=\"font-medium\">{model.provider_name}</span>\n <span className=\"text-slate-400 ml-1\">({model.provider_protocol})</span>\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <span className={`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-full border ${\n model.enabled \n ? 'bg-emerald-100/80 text-emerald-700 border-emerald-200/50' \n : 'bg-slate-100/80 text-slate-600 border-slate-200/50'\n }`}>\n {model.enabled ? '启用' : '禁用'}\n </span>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap text-right text-xs font-medium\">\n <div className=\"flex items-center justify-end space-x-3\">\n <button\n onClick={() => handleToggleEnabled(model.id, model.enabled)}\n className=\"text-emerald-600 hover:text-emerald-700 font-medium transition-colors duration-300\"\n >\n {model.enabled ? '禁用' : '启用'}\n </button>\n <button\n onClick={() => handleDelete(model.id)}\n className=\"text-rose-500 hover:text-rose-600 font-medium transition-colors duration-300\"\n >\n 删除\n </button>\n </div>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {/* 分页控件 */}\n {totalPages > 1 && (\n <div className=\"mt-4 flex items-center justify-between px-4 py-3 bg-emerald-50/20 border-t border-emerald-100/50\">\n <div className=\"text-xs text-slate-600\">\n 第 <span className=\"font-semibold text-slate-800\">{currentPage}</span> / {totalPages} 页\n </div>\n <div className=\"flex items-center space-x-2\">\n <button\n onClick={() => setCurrentPage(p => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-emerald-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 上一页\n </button>\n <div className=\"flex items-center space-x-1\">\n {Array.from({ length: totalPages }, (_, i) => i + 1)\n .filter(page => {\n // 只显示当前页附近的页码\n const offset = Math.abs(page - currentPage);\n return offset < 2 || page === 1 || page === totalPages;\n })\n .sort((a, b) => a - b)\n .map((page) => (\n <button\n key={page}\n onClick={() => setCurrentPage(page)}\n className={`w-8 h-8 font-semibold text-xs rounded-lg transition-all duration-300 ${\n currentPage === page\n ? 'bg-emerald-600 text-white shadow-md'\n : 'bg-white text-slate-600 border border-slate-200 hover:bg-emerald-50 hover:border-emerald-300'\n }`}\n >\n {page}\n </button>\n ))}\n </div>\n <button\n onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-emerald-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 下一页\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </main>\n\n {showModal && (\n <div className=\"fixed z-50 inset-0 overflow-y-auto\">\n <div className=\"flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\">\n <div className=\"fixed inset-0 bg-slate-900/40 backdrop-blur-sm transition-opacity\" onClick={() => setShowModal(false)}></div>\n <div className=\"inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full border border-emerald-100/50\">\n <form onSubmit={handleSubmit} className=\"bg-white px-6 pt-5 pb-4 sm:p-6\">\n <div className=\"mb-5\">\n <h3 className=\"text-base font-bold text-slate-800 mb-1\">添加模型</h3>\n <p className=\"text-xs text-slate-500\">手动添加新的 AI 模型</p>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">供应商</label>\n <select\n required\n value={formData.provider_id}\n onChange={(e) => setFormData({ ...formData, provider_id: e.target.value })}\n autoComplete=\"off\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n >\n <option value=\"\">选择供应商</option>\n {providers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">名称</label>\n <input\n type=\"text\"\n required\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n autoComplete=\"off\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n placeholder=\"例如: GPT-4\"\n />\n </div>\n <div>\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">模型 ID</label>\n <input\n type=\"text\"\n required\n value={formData.model_id}\n onChange={(e) => setFormData({ ...formData, model_id: e.target.value })}\n autoComplete=\"off\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n placeholder=\"例如: gpt-4\"\n />\n </div>\n </div>\n <div className=\"mt-5 flex items-center justify-end space-x-2\">\n <button\n type=\"button\"\n onClick={() => setShowModal(false)}\n className=\"px-3.5 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-400/30 transition-all duration-300\"\n >\n 取消\n </button>\n <button\n type=\"submit\"\n className=\"px-4 py-1.5 border border-transparent rounded-lg text-xs font-semibold text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 transition-all duration-300\"\n >\n 保存\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n )}\n\n <ConfirmDialog\n open={showDeleteConfirm}\n title=\"确认删除\"\n message=\"确定要删除这个模型吗?此操作不可恢复。\"\n onConfirm={confirmDelete}\n onCancel={() => {\n setShowDeleteConfirm(false);\n setDeleteId(null);\n }}\n confirmText=\"删除\"\n cancelText=\"取消\"\n type=\"danger\"\n />\n\n <ConfirmDialog\n open={showFetchConfirm}\n title=\"拉取模型列表\"\n message=\"确定要从供应商拉取模型列表吗?\"\n onConfirm={confirmFetch}\n onCancel={() => {\n setShowFetchConfirm(false);\n setFetchProviderId(null);\n }}\n confirmText=\"拉取\"\n cancelText=\"取消\"\n type=\"info\"\n />\n </>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/app/models/page.tsx"],"sourcesContent":["'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport Nav from '../components/Nav';\nimport { useToast } from '../components/ToastProvider';\nimport ConfirmDialog from '../components/ConfirmDialog';\n\ninterface Model {\n id: number;\n provider_id: number;\n name: string;\n model_id: string;\n enabled: boolean;\n provider_name?: string;\n provider_protocol?: string;\n}\n\ninterface Provider {\n id: number;\n name: string;\n protocol: string;\n}\n\nexport default function ModelsPage() {\n const [models, setModels] = useState<Model[]>([]);\n const [filteredModels, setFilteredModels] = useState<Model[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [loading, setLoading] = useState(true);\n const [showModal, setShowModal] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [showFetchConfirm, setShowFetchConfirm] = useState(false);\n const [deleteId, setDeleteId] = useState<number | null>(null);\n const [fetchProviderId, setFetchProviderId] = useState<number | null>(null);\n const [selectedProviderId, setSelectedProviderId] = useState<number | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [currentPage, setCurrentPage] = useState(1);\n const [showEnabledOnly, setShowEnabledOnly] = useState(false);\n const pageSize = 20;\n const [formData, setFormData] = useState({\n provider_id: '',\n name: '',\n model_id: '',\n enabled: true,\n });\n const { showToast } = useToast();\n\n useEffect(() => {\n loadData();\n }, []);\n\n // 计算分页数据\n const paginatedModels = (() => {\n const startIndex = (currentPage - 1) * pageSize;\n const endIndex = startIndex + pageSize;\n return filteredModels.slice(startIndex, endIndex);\n })();\n\n const totalPages = Math.ceil(filteredModels.length / pageSize);\n\n const filterModels = useCallback(() => {\n let filtered = [...models];\n\n // 按供应商筛选\n if (selectedProviderId !== null) {\n filtered = filtered.filter(model => model.provider_id === selectedProviderId);\n }\n\n // 按启用状态筛选\n if (showEnabledOnly) {\n filtered = filtered.filter(model => model.enabled);\n }\n\n // 搜索筛选\n if (searchQuery.trim()) {\n const query = searchQuery.toLowerCase().trim();\n filtered = filtered.filter(model =>\n model.name.toLowerCase().includes(query) ||\n model.model_id.toLowerCase().includes(query) ||\n model.provider_name?.toLowerCase().includes(query) ||\n model.provider_protocol?.toLowerCase().includes(query)\n );\n }\n\n setFilteredModels(filtered);\n }, [models, selectedProviderId, showEnabledOnly, searchQuery]);\n\n // 筛选或搜索时重置到第一页\n useEffect(() => {\n setCurrentPage(1);\n }, [selectedProviderId, showEnabledOnly, searchQuery]);\n\n useEffect(() => {\n filterModels();\n }, [filterModels]);\n\n const loadData = async () => {\n try {\n const [modelsRes, providersRes] = await Promise.all([\n fetch('/api/models'),\n fetch('/api/providers'),\n ]);\n const modelsData = await modelsRes.json();\n const providersData = await providersRes.json();\n setModels(modelsData);\n setProviders(providersData);\n } catch (error) {\n console.error('Failed to load data:', error);\n } finally {\n setLoading(false);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n try {\n await fetch('/api/models', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n ...formData,\n provider_id: parseInt(formData.provider_id),\n }),\n });\n setShowModal(false);\n setFormData({ provider_id: '', name: '', model_id: '', enabled: true });\n loadData();\n showToast('模型添加成功', 'success');\n } catch (error) {\n console.error('Failed to save model:', error);\n showToast('保存失败', 'error');\n }\n };\n\n const handleToggleEnabled = async (id: number, enabled: boolean) => {\n try {\n await fetch('/api/models', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id, enabled: !enabled }),\n });\n loadData();\n } catch (error) {\n console.error('Failed to update model:', error);\n }\n };\n\n const handleDelete = (id: number) => {\n setDeleteId(id);\n setShowDeleteConfirm(true);\n };\n\n const confirmDelete = async () => {\n if (deleteId) {\n try {\n await fetch(`/api/models?id=${deleteId}`, { method: 'DELETE' });\n loadData();\n showToast('模型已删除', 'success');\n } catch (error) {\n console.error('Failed to delete model:', error);\n showToast('删除失败', 'error');\n }\n }\n setShowDeleteConfirm(false);\n setDeleteId(null);\n };\n\n const handleFetchModels = (providerId: number) => {\n setFetchProviderId(providerId);\n setShowFetchConfirm(true);\n };\n\n const confirmFetch = async () => {\n if (fetchProviderId) {\n try {\n const res = await fetch('/api/models', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ provider_id: fetchProviderId }),\n });\n const data = await res.json();\n if (!res.ok) {\n showToast(data.error || '拉取失败', 'error');\n return;\n }\n const count = data.count ?? 0;\n showToast(`成功拉取 ${count} 个模型`, 'success');\n loadData();\n } catch (error: any) {\n console.error('Failed to fetch models:', error);\n showToast('拉取失败: ' + error.message, 'error');\n }\n }\n setShowFetchConfirm(false);\n setFetchProviderId(null);\n };\n\n if (loading) {\n return (\n <>\n <Nav />\n <div className=\"min-h-screen flex items-center justify-center\">\n <div className=\"text-lg\">加载中...</div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <Nav />\n <main className=\"max-w-6xl mx-auto py-6 sm:px-6 lg:px-8\">\n <div className=\"px-4 py-4 sm:px-0\">\n <div className=\"flex justify-between items-center mb-5\">\n <div>\n <h1 className=\"text-lg font-bold text-slate-800\">模型管理</h1>\n <p className=\"text-xs text-slate-500 mt-1\">管理 AI 模型配置和状态</p>\n </div>\n <button\n onClick={() => {\n setFormData({ provider_id: '', name: '', model_id: '', enabled: true });\n setShowModal(true);\n }}\n className=\"inline-flex items-center px-3.5 py-1.5 border border-transparent text-xs font-semibold rounded-lg shadow-sm text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 transition-all duration-300\"\n >\n <svg className=\"w-3.5 h-3.5 mr-1.5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 4v16m8-8H4\" />\n </svg>\n 手动添加\n </button>\n </div>\n\n {/* 一键拉取模型列表 - 移到列表上方 */}\n <div className=\"mb-5 bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 p-5\">\n <div className=\"flex items-center justify-between mb-4\">\n <div>\n <h2 className=\"text-sm font-bold text-slate-800\">快捷拉取</h2>\n <p className=\"text-xs text-slate-500 mt-0.5\">从供应商 API 自动拉取可用模型</p>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3\">\n {providers.map((provider) => (\n <div key={provider.id} className=\"flex items-center justify-between p-3 border border-slate-200 rounded-xl hover:border-emerald-300 hover:shadow-sm transition-all duration-300 cursor-pointer bg-white/80 backdrop-blur-sm\">\n <div className=\"flex-1\">\n <div className=\"font-semibold text-xs text-slate-800\">{provider.name}</div>\n <div className=\"text-[10px] text-slate-500 mt-0.5\">{provider.protocol}</div>\n </div>\n <button\n onClick={() => handleFetchModels(provider.id)}\n className=\"ml-3 inline-flex items-center px-2.5 py-1 border border-transparent text-[10px] font-semibold rounded-lg text-emerald-700 bg-emerald-50 hover:bg-emerald-100 transition-all duration-300\"\n >\n <svg className=\"w-3 h-3 mr-1\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n 拉取\n </button>\n </div>\n ))}\n </div>\n </div>\n\n {/* 筛选和搜索栏 */}\n <div className=\"mb-5 bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 p-5\">\n <div className=\"flex flex-col sm:flex-row gap-4\">\n {/* 供应商筛选 */}\n <div className=\"flex-1\">\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">按供应商筛选</label>\n <select\n value={selectedProviderId ?? ''}\n onChange={(e) => setSelectedProviderId(e.target.value ? parseInt(e.target.value) : null)}\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n >\n <option value=\"\">全部供应商</option>\n {providers.map((provider) => (\n <option key={provider.id} value={provider.id}>\n {provider.name} ({provider.protocol})\n </option>\n ))}\n </select>\n </div>\n {/* 搜索框 */}\n <div className=\"flex-1\">\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">搜索模型</label>\n <div className=\"relative\">\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder=\"搜索模型名称、ID、供应商...\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 pl-9 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n />\n <svg className=\"absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n {searchQuery && (\n <button\n onClick={() => setSearchQuery('')}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 p-1 text-slate-400 hover:text-slate-600 transition-colors\"\n >\n <svg className=\"w-4 h-4\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n {/* 仅显示已启用 */}\n <div className=\"flex items-center\">\n <label className=\"flex items-center cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={showEnabledOnly}\n onChange={(e) => setShowEnabledOnly(e.target.checked)}\n className=\"w-4 h-4 text-emerald-600 border-slate-300 rounded focus:ring-emerald-500 transition-all duration-300\"\n />\n <span className=\"ml-2 text-xs font-semibold text-slate-700\">仅已启用</span>\n </label>\n </div>\n </div>\n {/* 结果统计 */}\n {(selectedProviderId !== null || searchQuery.trim() || showEnabledOnly) && (\n <div className=\"mt-3 text-xs text-slate-500\">\n 显示 {filteredModels.length} 个模型,第 {(currentPage - 1) * pageSize + 1}-{Math.min(currentPage * pageSize, filteredModels.length)} 个\n </div>\n )}\n </div>\n\n <div className=\"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50 overflow-hidden\">\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full divide-y divide-slate-100\">\n <thead className=\"bg-emerald-50/30\">\n <tr>\n <th className=\"px-4 py-2.5 text-left text-xs font-semibold text-slate-600 uppercase tracking-wider\">\n 名称\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 模型 ID\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 供应商\n </th>\n <th className=\"px-6 py-3.5 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 状态\n </th>\n <th className=\"px-6 py-3.5 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider\">\n 操作\n </th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-slate-100\">\n {paginatedModels.length === 0 ? (\n <tr>\n <td colSpan={5} className=\"px-4 py-12 text-center\">\n <div className=\"text-slate-400\">\n {models.length === 0 ? (\n <>\n <svg className=\"mx-auto h-10 w-10 mb-3 text-slate-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4\" />\n </svg>\n <p className=\"text-xs text-slate-500\">暂无模型,请先添加或拉取模型</p>\n </>\n ) : (\n <>\n <svg className=\"mx-auto h-10 w-10 mb-3 text-slate-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={1.5} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <p className=\"text-xs text-slate-500\">没有找到匹配的模型</p>\n {(selectedProviderId !== null || searchQuery.trim() || showEnabledOnly) && (\n <button\n onClick={() => {\n setSelectedProviderId(null);\n setSearchQuery('');\n setShowEnabledOnly(false);\n }}\n className=\"mt-2 text-xs text-emerald-600 hover:text-emerald-700 underline\"\n >\n 清除筛选条件\n </button>\n )}\n </>\n )}\n </div>\n </td>\n </tr>\n ) : (\n paginatedModels.map((model) => (\n <tr key={model.id} className=\"hover:bg-emerald-50/20 transition-colors duration-300\">\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs font-medium text-slate-800\">{model.name}</div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600 font-mono\">{model.model_id}</div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <div className=\"text-xs text-slate-600\">\n <span className=\"font-medium\">{model.provider_name}</span>\n <span className=\"text-slate-400 ml-1\">({model.provider_protocol})</span>\n </div>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap\">\n <span className={`px-2 py-0.5 inline-flex text-xs leading-4 font-semibold rounded-full border ${\n model.enabled \n ? 'bg-emerald-100/80 text-emerald-700 border-emerald-200/50' \n : 'bg-slate-100/80 text-slate-600 border-slate-200/50'\n }`}>\n {model.enabled ? '启用' : '禁用'}\n </span>\n </td>\n <td className=\"px-4 py-3 whitespace-nowrap text-right text-xs font-medium\">\n <div className=\"flex items-center justify-end space-x-3\">\n <button\n onClick={() => handleToggleEnabled(model.id, model.enabled)}\n className=\"text-emerald-600 hover:text-emerald-700 font-medium transition-colors duration-300\"\n >\n {model.enabled ? '禁用' : '启用'}\n </button>\n <button\n onClick={() => handleDelete(model.id)}\n className=\"text-rose-500 hover:text-rose-600 font-medium transition-colors duration-300\"\n >\n 删除\n </button>\n </div>\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {/* 分页控件 */}\n {totalPages > 1 && (\n <div className=\"mt-4 flex items-center justify-between px-4 py-3 bg-emerald-50/20 border-t border-emerald-100/50\">\n <div className=\"text-xs text-slate-600\">\n 第 <span className=\"font-semibold text-slate-800\">{currentPage}</span> / {totalPages} 页\n </div>\n <div className=\"flex items-center space-x-2\">\n <button\n onClick={() => setCurrentPage(p => Math.max(1, p - 1))}\n disabled={currentPage === 1}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-emerald-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 上一页\n </button>\n <div className=\"flex items-center space-x-1\">\n {Array.from({ length: totalPages }, (_, i) => i + 1)\n .filter(page => {\n // 只显示当前页附近的页码\n const offset = Math.abs(page - currentPage);\n return offset < 2 || page === 1 || page === totalPages;\n })\n .sort((a, b) => a - b)\n .map((page) => (\n <button\n key={page}\n onClick={() => setCurrentPage(page)}\n className={`w-8 h-8 font-semibold text-xs rounded-lg transition-all duration-300 ${\n currentPage === page\n ? 'bg-emerald-600 text-white shadow-md'\n : 'bg-white text-slate-600 border border-slate-200 hover:bg-emerald-50 hover:border-emerald-300'\n }`}\n >\n {page}\n </button>\n ))}\n </div>\n <button\n onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}\n disabled={currentPage === totalPages}\n className=\"px-3 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-emerald-50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300\"\n >\n 下一页\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n </main>\n\n {showModal && (\n <div className=\"fixed z-50 inset-0 overflow-y-auto\">\n <div className=\"flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0\">\n <div className=\"fixed inset-0 bg-slate-900/40 backdrop-blur-sm transition-opacity\" onClick={() => setShowModal(false)}></div>\n <div className=\"inline-block align-bottom bg-white rounded-2xl text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full border border-emerald-100/50\">\n <form onSubmit={handleSubmit} className=\"bg-white px-6 pt-5 pb-4 sm:p-6\">\n <div className=\"mb-5\">\n <h3 className=\"text-base font-bold text-slate-800 mb-1\">添加模型</h3>\n <p className=\"text-xs text-slate-500\">手动添加新的 AI 模型</p>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">供应商</label>\n <select\n required\n value={formData.provider_id}\n onChange={(e) => setFormData({ ...formData, provider_id: e.target.value })}\n autoComplete=\"off\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n >\n <option value=\"\">选择供应商</option>\n {providers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">名称</label>\n <input\n type=\"text\"\n required\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n autoComplete=\"off\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n placeholder=\"例如: GPT-4\"\n />\n </div>\n <div>\n <label className=\"block text-xs font-semibold text-slate-700 mb-1.5\">模型 ID</label>\n <input\n type=\"text\"\n required\n value={formData.model_id}\n onChange={(e) => setFormData({ ...formData, model_id: e.target.value })}\n autoComplete=\"off\"\n className=\"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1\"\n placeholder=\"例如: gpt-4\"\n />\n </div>\n </div>\n <div className=\"mt-5 flex items-center justify-end space-x-2\">\n <button\n type=\"button\"\n onClick={() => setShowModal(false)}\n className=\"px-3.5 py-1.5 border border-slate-200 rounded-lg text-xs font-semibold text-slate-600 bg-white hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-slate-400/30 transition-all duration-300\"\n >\n 取消\n </button>\n <button\n type=\"submit\"\n className=\"px-4 py-1.5 border border-transparent rounded-lg text-xs font-semibold text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 transition-all duration-300\"\n >\n 保存\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n )}\n\n <ConfirmDialog\n open={showDeleteConfirm}\n title=\"确认删除\"\n message=\"确定要删除这个模型吗?此操作不可恢复。\"\n onConfirm={confirmDelete}\n onCancel={() => {\n setShowDeleteConfirm(false);\n setDeleteId(null);\n }}\n confirmText=\"删除\"\n cancelText=\"取消\"\n type=\"danger\"\n />\n\n <ConfirmDialog\n open={showFetchConfirm}\n title=\"拉取模型列表\"\n message=\"确定要从供应商拉取模型列表吗?\"\n onConfirm={confirmFetch}\n onCancel={() => {\n setShowFetchConfirm(false);\n setFetchProviderId(null);\n }}\n confirmText=\"拉取\"\n cancelText=\"取消\"\n type=\"info\"\n />\n </>\n );\n}\n"],"names":["ModelsPage","models","setModels","filteredModels","setFilteredModels","providers","setProviders","loading","setLoading","showModal","setShowModal","showDeleteConfirm","setShowDeleteConfirm","showFetchConfirm","setShowFetchConfirm","deleteId","setDeleteId","fetchProviderId","setFetchProviderId","selectedProviderId","setSelectedProviderId","searchQuery","setSearchQuery","currentPage","setCurrentPage","showEnabledOnly","setShowEnabledOnly","pageSize","formData","setFormData","provider_id","name","model_id","enabled","showToast","loadData","paginatedModels","startIndex","endIndex","slice","totalPages","Math","ceil","length","filterModels","filtered","filter","model","trim","query","toLowerCase","includes","provider_name","provider_protocol","modelsRes","providersRes","Promise","all","fetch","modelsData","json","providersData","error","console","handleSubmit","e","preventDefault","method","headers","body","JSON","stringify","parseInt","handleToggleEnabled","id","handleDelete","confirmDelete","handleFetchModels","providerId","confirmFetch","res","data","ok","count","message","className","onClick","fill","stroke","viewBox","strokeLinecap","strokeLinejoin","strokeWidth","d","map","provider","protocol","value","onChange","target","type","placeholder","checked","min","colSpan","p","max","disabled","Array","from","_","i","page","offset","abs","sort","a","b","onSubmit","required","autoComplete","open","title","onConfirm","onCancel","confirmText","cancelText"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
module.exports=[40777,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(81844),e=a.i(21215);a.s(["default",0,function(){let[a,f]=(0,c.useState)({}),[g,h]=(0,c.useState)(!0),[i,j]=(0,c.useState)(!1),[k,l]=(0,c.useState)({status:"stopped"}),[m,n]=(0,c.useState)(!1),[o,p]=(0,c.useState)(!1),[q,r]=(0,c.useState)(!1),{showToast:s}=(0,e.useToast)(),t=(0,c.useCallback)(async()=>{try{let a=await fetch("/api/config"),b=await a.json();f({port:b.port||"1357",api_key:b.api_key||""})}catch(a){console.error("Failed to load config:",a)}finally{h(!1)}},[]),u=(0,c.useCallback)(async()=>{try{let a=await fetch("/api/service/status"),b=await a.json();l(b)}catch(a){console.error("Failed to load service status:",a)}},[]);(0,c.useEffect)(()=>{t(),u();let a=setInterval(u,2e3);return()=>clearInterval(a)},[t,u]);let v=async()=>{if(!m&&"running"!==k.status){n(!0);try{let b=a.port?parseInt(a.port,10):1357,c=await fetch("/api/service/start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({port:b})}),d=await c.json();d.error?s(`启动失败: ${d.error}`,"error"):(s("服务已启动","success"),l(d))}catch(a){console.error("Failed to start service:",a),s("启动失败","error")}finally{n(!1),setTimeout(u,500)}}},w=async()=>{if(!o&&"stopped"!==k.status){p(!0);try{let a=await fetch("/api/service/stop",{method:"POST",headers:{"Content-Type":"application/json"}}),b=await a.json();b.error?s(`停止失败: ${b.error}`,"error"):(s("服务已停止","success"),l(b))}catch(a){console.error("Failed to stop service:",a),s("停止失败","error")}finally{p(!1),setTimeout(u,500)}}},x=async()=>{j(!0);try{let b=await fetch("/api/config",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:"port",value:a.port})});if(!b.ok){let a=await b.json();throw Error(a.error||"保存端口配置失败")}if(a.api_key){let b=await fetch("/api/config",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({key:"api_key",value:a.api_key})});if(!b.ok){let a=await b.json();throw Error(a.error||"保存 API Key 配置失败")}}s("配置已保存","success")}catch(a){console.error("Failed to save config:",a),s(a.message||"保存失败","error")}finally{j(!1)}};return g?(0,b.jsx)("div",{className:"min-h-screen flex items-center justify-center",children:(0,b.jsx)("div",{className:"text-lg",children:"加载中..."})}):(0,b.jsxs)("div",{className:"min-h-screen bg-gradient-to-br from-emerald-50/30 via-white to-slate-50/50",children:[(0,b.jsx)(d.default,{}),(0,b.jsx)("main",{className:"max-w-3xl mx-auto py-6 sm:px-6 lg:px-8",children:(0,b.jsx)("div",{className:"px-4 py-4 sm:px-0",children:(0,b.jsx)("div",{className:"bg-white/70 backdrop-blur-sm shadow-md rounded-2xl border border-emerald-100/50",children:(0,b.jsxs)("div",{className:"px-6 py-5 sm:p-6",children:[(0,b.jsxs)("div",{className:"mb-5",children:[(0,b.jsx)("h2",{className:"text-lg font-bold text-slate-800 mb-1",children:"网关配置"}),(0,b.jsx)("p",{className:"text-xs text-slate-500",children:"配置 API 网关的运行参数"})]}),(0,b.jsxs)("div",{className:"space-y-3.5",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"端口"}),(0,b.jsx)("input",{type:"number",value:a.port,onChange:b=>f({...a,port:b.target.value}),autoComplete:"off",className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1",placeholder:"1357"}),(0,b.jsx)("p",{className:"mt-1 text-xs text-slate-400",children:"提示:API 网关默认端口为 1357"})]}),(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{className:"block text-xs font-semibold text-slate-700 mb-1.5",children:"API Key (可选)"}),(0,b.jsxs)("div",{className:"relative",children:[(0,b.jsx)("input",{type:q?"text":"password",value:a.api_key,onChange:b=>f({...a,api_key:b.target.value}),autoComplete:"new-password",className:"block w-full rounded-lg border border-slate-200 bg-white/80 px-3 py-2 pr-9 text-xs shadow-sm transition-all duration-300 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/20 focus:ring-offset-1",placeholder:"留空则不验证"}),(0,b.jsx)("button",{type:"button",onClick:()=>r(!q),className:"absolute right-2 top-1/2 -translate-y-1/2 p-1 text-slate-400 hover:text-slate-600 transition-colors",tabIndex:-1,children:q?(0,b.jsx)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21"})}):(0,b.jsxs)("svg",{className:"w-4 h-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:[(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M15 12a3 3 0 11-6 0 3 3 0 016 0z"}),(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"})]})})]})]}),(0,b.jsxs)("div",{className:"flex items-center justify-between pt-3",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("span",{className:"text-xs text-slate-500",children:"状态: "}),(0,b.jsx)("span",{className:`text-xs font-medium ${"running"===k.status?"text-emerald-600":"text-slate-500"}`,children:"running"===k.status?"运行中":"已停止"}),"running"===k.status&&k.port&&(0,b.jsxs)("span",{className:"text-xs text-slate-400 ml-2",children:["(端口: ",k.port,")"]})]}),(0,b.jsxs)("div",{className:"flex space-x-2",children:[(0,b.jsx)("button",{onClick:x,disabled:i||"running"===k.status,className:"inline-flex items-center px-3.5 py-1.5 border border-transparent text-xs font-semibold rounded-lg shadow-sm text-white bg-emerald-600 hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-emerald-500/50 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300",children:i?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("svg",{className:"animate-spin -ml-1 mr-1.5 h-3 w-3 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,b.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,b.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),"保存中"]}):"保存配置"}),(0,b.jsx)("button",{onClick:"running"===k.status?w:v,disabled:m||o,className:`inline-flex items-center px-3.5 py-1.5 border border-transparent text-xs font-semibold rounded-lg shadow-sm text-white focus:outline-none focus:ring-2 focus:ring-offset-1 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed ${"running"===k.status?"bg-rose-500 hover:bg-rose-600 focus:ring-rose-500/50":"bg-emerald-600 hover:bg-emerald-700 focus:ring-emerald-500/50"}`,children:m?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("svg",{className:"animate-spin -ml-1 mr-1.5 h-3 w-3 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,b.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,b.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),"启动中"]}):o?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("svg",{className:"animate-spin -ml-1 mr-1.5 h-3 w-3 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[(0,b.jsx)("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),(0,b.jsx)("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),"停止中"]}):"running"===k.status?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("svg",{className:"w-3 h-3 mr-1.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:[(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"}),(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 10a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z"})]}),"停止"]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)("svg",{className:"w-3 h-3 mr-1.5",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:[(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"}),(0,b.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M21 12a9 9 0 11-18 0 9 9 0 0118 0z"})]}),"启动"]})})]})]})]})]})})})})]})}])}];
|
|
2
|
+
|
|
3
|
+
//# sourceMappingURL=src_app_page_tsx_0ss2.w7._.js.map
|