ai-zero-token 1.0.8 → 1.0.10
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/README.md +39 -0
- package/README.zh-CN.md +39 -0
- package/admin-ui/dist/assets/index-BBXWfa-w.js +11 -0
- package/admin-ui/dist/assets/index-n7rmcV5d.css +1 -0
- package/admin-ui/dist/assets/wechat-contact-Dlaib1YP.png +0 -0
- package/admin-ui/dist/index.html +13 -0
- package/build/icon.icns +0 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/dist/core/providers/http-client.js +1 -1
- package/dist/core/providers/openai-codex/chat.js +23 -0
- package/dist/core/providers/openai-codex/oauth.js +24 -1
- package/dist/core/services/auth-service.js +264 -21
- package/dist/core/services/chat-service.js +2 -2
- package/dist/core/services/config-service.js +15 -3
- package/dist/core/services/image-service.js +2 -2
- package/dist/core/services/version-service.js +18 -13
- package/dist/core/store/settings-store.js +6 -0
- package/dist/desktop/main.js +127 -0
- package/dist/server/admin-page.js +1094 -100
- package/dist/server/app.js +160 -6
- package/docs/DESKTOP_RELEASE.md +64 -0
- package/docs/PRODUCT_UPDATE_DESKTOP_TOOLBOX.md +429 -0
- package/package.json +70 -4
|
@@ -27,6 +27,9 @@ function renderAdminPage() {
|
|
|
27
27
|
--orange-soft: rgba(245, 158, 11, 0.12);
|
|
28
28
|
--red: #ef4444;
|
|
29
29
|
--red-soft: rgba(239, 68, 68, 0.12);
|
|
30
|
+
--plan-color: #94a3b8;
|
|
31
|
+
--plan-soft: rgba(148, 163, 184, 0.12);
|
|
32
|
+
--plan-border: var(--line);
|
|
30
33
|
--shadow: 0 2px 10px rgba(15, 23, 42, 0.06);
|
|
31
34
|
--radius: 16px;
|
|
32
35
|
--radius-sm: 12px;
|
|
@@ -341,6 +344,45 @@ function renderAdminPage() {
|
|
|
341
344
|
min-height: 112px;
|
|
342
345
|
}
|
|
343
346
|
|
|
347
|
+
.summary-card-head {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
gap: 8px;
|
|
351
|
+
min-width: 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.summary-icon {
|
|
355
|
+
width: 22px;
|
|
356
|
+
height: 22px;
|
|
357
|
+
border-radius: 999px;
|
|
358
|
+
display: inline-grid;
|
|
359
|
+
place-items: center;
|
|
360
|
+
flex: 0 0 auto;
|
|
361
|
+
color: var(--brand);
|
|
362
|
+
background: var(--brand-soft);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.summary-icon svg {
|
|
366
|
+
width: 14px;
|
|
367
|
+
height: 14px;
|
|
368
|
+
display: block;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.summary-icon.blue {
|
|
372
|
+
color: var(--blue);
|
|
373
|
+
background: var(--blue-soft);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.summary-icon.green {
|
|
377
|
+
color: #15803d;
|
|
378
|
+
background: var(--green-soft);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.summary-icon.orange {
|
|
382
|
+
color: #b45309;
|
|
383
|
+
background: var(--orange-soft);
|
|
384
|
+
}
|
|
385
|
+
|
|
344
386
|
.summary-card label {
|
|
345
387
|
color: var(--text-muted);
|
|
346
388
|
font-size: 12px;
|
|
@@ -368,6 +410,60 @@ function renderAdminPage() {
|
|
|
368
410
|
overflow-wrap: anywhere;
|
|
369
411
|
}
|
|
370
412
|
|
|
413
|
+
.summary-card.account-status-summary {
|
|
414
|
+
gap: 12px;
|
|
415
|
+
min-height: 112px;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.account-status-list {
|
|
419
|
+
display: grid;
|
|
420
|
+
gap: 8px;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.account-status-line {
|
|
424
|
+
display: grid;
|
|
425
|
+
grid-template-columns: 20px auto minmax(0, 1fr);
|
|
426
|
+
align-items: center;
|
|
427
|
+
gap: 8px;
|
|
428
|
+
min-width: 0;
|
|
429
|
+
color: var(--text-soft);
|
|
430
|
+
font-size: 13px;
|
|
431
|
+
line-height: 1.45;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.account-status-line svg {
|
|
435
|
+
width: 18px;
|
|
436
|
+
height: 18px;
|
|
437
|
+
padding: 3px;
|
|
438
|
+
border-radius: 999px;
|
|
439
|
+
flex: 0 0 auto;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.account-status-line.gateway svg {
|
|
443
|
+
color: var(--blue);
|
|
444
|
+
background: var(--blue-soft);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.account-status-line.codex svg {
|
|
448
|
+
color: #15803d;
|
|
449
|
+
background: var(--green-soft);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.account-status-line span {
|
|
453
|
+
color: var(--text-muted);
|
|
454
|
+
font-weight: 700;
|
|
455
|
+
white-space: nowrap;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.account-status-line strong {
|
|
459
|
+
min-width: 0;
|
|
460
|
+
color: var(--text);
|
|
461
|
+
font-size: clamp(16px, 1.05vw, 18px);
|
|
462
|
+
line-height: 1.25;
|
|
463
|
+
letter-spacing: -0.02em;
|
|
464
|
+
overflow-wrap: anywhere;
|
|
465
|
+
}
|
|
466
|
+
|
|
371
467
|
.main-grid {
|
|
372
468
|
display: grid;
|
|
373
469
|
grid-template-columns: minmax(0, 1fr) minmax(460px, 560px);
|
|
@@ -487,6 +583,88 @@ function renderAdminPage() {
|
|
|
487
583
|
display: flex;
|
|
488
584
|
}
|
|
489
585
|
|
|
586
|
+
.drawer-backdrop {
|
|
587
|
+
position: fixed;
|
|
588
|
+
inset: 0;
|
|
589
|
+
display: none;
|
|
590
|
+
justify-content: flex-end;
|
|
591
|
+
background: rgba(15, 23, 42, 0.38);
|
|
592
|
+
backdrop-filter: blur(4px);
|
|
593
|
+
z-index: 60;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.drawer-backdrop.is-open {
|
|
597
|
+
display: flex;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.settings-drawer {
|
|
601
|
+
width: min(460px, 100vw);
|
|
602
|
+
height: 100vh;
|
|
603
|
+
background: var(--panel);
|
|
604
|
+
border-left: 1px solid var(--line);
|
|
605
|
+
box-shadow: -18px 0 48px rgba(15, 23, 42, 0.16);
|
|
606
|
+
display: grid;
|
|
607
|
+
grid-template-rows: auto minmax(0, 1fr) auto;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.settings-drawer-head,
|
|
611
|
+
.settings-drawer-footer {
|
|
612
|
+
padding: 18px 20px;
|
|
613
|
+
display: flex;
|
|
614
|
+
align-items: flex-start;
|
|
615
|
+
justify-content: space-between;
|
|
616
|
+
gap: 14px;
|
|
617
|
+
border-bottom: 1px solid var(--line);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
.settings-drawer-footer {
|
|
621
|
+
align-items: center;
|
|
622
|
+
border-top: 1px solid var(--line);
|
|
623
|
+
border-bottom: 0;
|
|
624
|
+
background: #fbfdff;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.settings-drawer-head h3 {
|
|
628
|
+
margin: 0;
|
|
629
|
+
font-size: 22px;
|
|
630
|
+
line-height: 1.2;
|
|
631
|
+
letter-spacing: -0.03em;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.settings-drawer-head p {
|
|
635
|
+
margin: 6px 0 0;
|
|
636
|
+
color: var(--text-muted);
|
|
637
|
+
font-size: 13px;
|
|
638
|
+
line-height: 1.6;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
.settings-drawer-body {
|
|
642
|
+
padding: 18px 20px;
|
|
643
|
+
overflow: auto;
|
|
644
|
+
display: grid;
|
|
645
|
+
align-content: start;
|
|
646
|
+
gap: 16px;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.settings-section {
|
|
650
|
+
display: grid;
|
|
651
|
+
gap: 12px;
|
|
652
|
+
padding-bottom: 16px;
|
|
653
|
+
border-bottom: 1px solid var(--line);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.settings-section:last-child {
|
|
657
|
+
border-bottom: 0;
|
|
658
|
+
padding-bottom: 0;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.settings-section h4 {
|
|
662
|
+
margin: 0;
|
|
663
|
+
color: var(--text);
|
|
664
|
+
font-size: 14px;
|
|
665
|
+
line-height: 1.4;
|
|
666
|
+
}
|
|
667
|
+
|
|
490
668
|
.modal-card {
|
|
491
669
|
width: min(760px, calc(100vw - 32px));
|
|
492
670
|
background: var(--panel);
|
|
@@ -662,35 +840,89 @@ function renderAdminPage() {
|
|
|
662
840
|
|
|
663
841
|
.account-grid {
|
|
664
842
|
display: grid;
|
|
665
|
-
grid-auto-rows: 1fr;
|
|
666
843
|
gap: 16px;
|
|
667
|
-
|
|
844
|
+
align-items: start;
|
|
845
|
+
justify-content: stretch;
|
|
846
|
+
width: 100%;
|
|
668
847
|
}
|
|
669
848
|
|
|
670
849
|
.account-grid.profile-count-1 {
|
|
671
|
-
grid-template-columns: minmax(
|
|
850
|
+
grid-template-columns: minmax(340px, 520px);
|
|
672
851
|
}
|
|
673
852
|
|
|
674
853
|
.account-grid.profile-count-2 {
|
|
675
|
-
grid-template-columns: repeat(2, minmax(
|
|
854
|
+
grid-template-columns: repeat(2, minmax(340px, 1fr));
|
|
676
855
|
}
|
|
677
856
|
|
|
678
857
|
.account-grid.profile-count-3 {
|
|
679
|
-
grid-template-columns: repeat(3, minmax(
|
|
858
|
+
grid-template-columns: repeat(3, minmax(320px, 1fr));
|
|
680
859
|
}
|
|
681
860
|
|
|
682
861
|
.account-grid.profile-count-many {
|
|
683
|
-
grid-template-columns: repeat(auto-fit, minmax(
|
|
862
|
+
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
|
|
684
863
|
}
|
|
685
864
|
|
|
686
865
|
.account-card {
|
|
866
|
+
--plan-color: #94a3b8;
|
|
867
|
+
--plan-soft: rgba(148, 163, 184, 0.12);
|
|
868
|
+
--plan-border: var(--line);
|
|
869
|
+
--usage-color: #16a34a;
|
|
870
|
+
--usage-soft: rgba(22, 163, 74, 0.12);
|
|
871
|
+
position: relative;
|
|
687
872
|
border-radius: 16px;
|
|
688
873
|
padding: 14px;
|
|
689
874
|
display: grid;
|
|
690
875
|
grid-template-rows: auto auto auto 1fr auto;
|
|
691
876
|
gap: 12px;
|
|
692
877
|
min-width: 0;
|
|
693
|
-
|
|
878
|
+
border-color: var(--plan-border);
|
|
879
|
+
overflow: hidden;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.account-card::before {
|
|
883
|
+
content: "";
|
|
884
|
+
position: absolute;
|
|
885
|
+
inset: 0 0 auto;
|
|
886
|
+
height: 3px;
|
|
887
|
+
background: var(--plan-color);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
.account-card.plan-free {
|
|
891
|
+
--plan-color: #94a3b8;
|
|
892
|
+
--plan-soft: rgba(148, 163, 184, 0.12);
|
|
893
|
+
--plan-border: var(--line);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
.account-card.plan-plus {
|
|
897
|
+
--plan-color: #635bff;
|
|
898
|
+
--plan-soft: rgba(99, 91, 255, 0.11);
|
|
899
|
+
--plan-border: rgba(99, 91, 255, 0.2);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
.account-card.plan-pro {
|
|
903
|
+
--plan-color: #4f46e5;
|
|
904
|
+
--plan-soft: rgba(79, 70, 229, 0.11);
|
|
905
|
+
--plan-border: rgba(79, 70, 229, 0.22);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
.account-card.plan-team {
|
|
909
|
+
--plan-color: #0f766e;
|
|
910
|
+
--plan-soft: rgba(15, 118, 110, 0.11);
|
|
911
|
+
--plan-border: rgba(15, 118, 110, 0.22);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.account-card.plan-premium {
|
|
915
|
+
--plan-color: #d97706;
|
|
916
|
+
--plan-soft: rgba(217, 119, 6, 0.12);
|
|
917
|
+
--plan-border: rgba(217, 119, 6, 0.34);
|
|
918
|
+
box-shadow: 0 10px 26px rgba(180, 83, 9, 0.1), var(--shadow);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
.account-card.plan-enterprise {
|
|
922
|
+
--plan-color: #a16207;
|
|
923
|
+
--plan-soft: rgba(161, 98, 7, 0.14);
|
|
924
|
+
--plan-border: rgba(71, 85, 105, 0.28);
|
|
925
|
+
box-shadow: 0 12px 28px rgba(15, 23, 42, 0.1), var(--shadow);
|
|
694
926
|
}
|
|
695
927
|
|
|
696
928
|
.account-head {
|
|
@@ -698,6 +930,7 @@ function renderAdminPage() {
|
|
|
698
930
|
align-items: flex-start;
|
|
699
931
|
justify-content: space-between;
|
|
700
932
|
gap: 12px;
|
|
933
|
+
padding-top: 8px;
|
|
701
934
|
}
|
|
702
935
|
|
|
703
936
|
.account-title {
|
|
@@ -713,6 +946,7 @@ function renderAdminPage() {
|
|
|
713
946
|
gap: 6px;
|
|
714
947
|
min-height: 28px;
|
|
715
948
|
padding: 0 8px;
|
|
949
|
+
margin-top: 28px;
|
|
716
950
|
border: 1px solid var(--line);
|
|
717
951
|
border-radius: 8px;
|
|
718
952
|
background: #fff;
|
|
@@ -742,11 +976,12 @@ function renderAdminPage() {
|
|
|
742
976
|
height: 24px;
|
|
743
977
|
border-radius: 999px;
|
|
744
978
|
background: var(--panel-soft);
|
|
745
|
-
border: 1px solid var(--
|
|
979
|
+
border: 1px solid var(--plan-color);
|
|
980
|
+
box-shadow: 0 0 0 3px var(--plan-soft);
|
|
746
981
|
display: grid;
|
|
747
982
|
place-items: center;
|
|
748
983
|
font-size: 11px;
|
|
749
|
-
color: var(--
|
|
984
|
+
color: var(--plan-color);
|
|
750
985
|
font-weight: 700;
|
|
751
986
|
flex: 0 0 auto;
|
|
752
987
|
}
|
|
@@ -783,8 +1018,66 @@ function renderAdminPage() {
|
|
|
783
1018
|
}
|
|
784
1019
|
|
|
785
1020
|
.badge.brand {
|
|
786
|
-
color: var(--
|
|
787
|
-
background: var(--
|
|
1021
|
+
color: var(--plan-color);
|
|
1022
|
+
background: var(--plan-soft);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
.usage-corner {
|
|
1026
|
+
position: absolute;
|
|
1027
|
+
top: 10px;
|
|
1028
|
+
right: 12px;
|
|
1029
|
+
min-height: 24px;
|
|
1030
|
+
padding: 0 10px 0 8px;
|
|
1031
|
+
border-radius: 999px;
|
|
1032
|
+
color: #047857;
|
|
1033
|
+
background: linear-gradient(135deg, #ecfdf5, #d1fae5);
|
|
1034
|
+
border: 1px solid rgba(16, 185, 129, 0.28);
|
|
1035
|
+
box-shadow: 0 8px 18px rgba(16, 185, 129, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.82);
|
|
1036
|
+
font-size: 10px;
|
|
1037
|
+
font-weight: 800;
|
|
1038
|
+
line-height: 22px;
|
|
1039
|
+
letter-spacing: 0;
|
|
1040
|
+
pointer-events: none;
|
|
1041
|
+
z-index: 1;
|
|
1042
|
+
display: inline-flex;
|
|
1043
|
+
align-items: center;
|
|
1044
|
+
gap: 5px;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
.usage-corner::before {
|
|
1048
|
+
content: "";
|
|
1049
|
+
width: 6px;
|
|
1050
|
+
height: 6px;
|
|
1051
|
+
border-radius: 999px;
|
|
1052
|
+
background: currentColor;
|
|
1053
|
+
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.12);
|
|
1054
|
+
flex: 0 0 auto;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
.usage-corner span {
|
|
1058
|
+
line-height: 1;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
.usage-corner.codex-only {
|
|
1062
|
+
color: #1d4ed8;
|
|
1063
|
+
background: linear-gradient(135deg, #eff6ff, #dbeafe);
|
|
1064
|
+
border-color: rgba(37, 99, 235, 0.24);
|
|
1065
|
+
box-shadow: 0 8px 18px rgba(37, 99, 235, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.82);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
.usage-corner.codex-only::before {
|
|
1069
|
+
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
.usage-corner.dual {
|
|
1073
|
+
color: #4f46e5;
|
|
1074
|
+
background: linear-gradient(135deg, #f5f3ff, #ede9fe);
|
|
1075
|
+
border-color: rgba(99, 91, 255, 0.25);
|
|
1076
|
+
box-shadow: 0 8px 18px rgba(99, 91, 255, 0.13), inset 0 1px 0 rgba(255, 255, 255, 0.82);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
.usage-corner.dual::before {
|
|
1080
|
+
box-shadow: 0 0 0 3px rgba(99, 91, 255, 0.12);
|
|
788
1081
|
}
|
|
789
1082
|
|
|
790
1083
|
.badge.blue {
|
|
@@ -807,9 +1100,148 @@ function renderAdminPage() {
|
|
|
807
1100
|
background: var(--red-soft);
|
|
808
1101
|
}
|
|
809
1102
|
|
|
810
|
-
.account-metrics {
|
|
811
|
-
display: grid;
|
|
812
|
-
gap: 10px;
|
|
1103
|
+
.account-metrics {
|
|
1104
|
+
display: grid;
|
|
1105
|
+
gap: 10px;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
.usage-status-row {
|
|
1109
|
+
display: flex;
|
|
1110
|
+
flex-wrap: nowrap;
|
|
1111
|
+
align-items: center;
|
|
1112
|
+
justify-content: space-between;
|
|
1113
|
+
gap: 8px;
|
|
1114
|
+
padding: 8px 10px;
|
|
1115
|
+
border-radius: 10px;
|
|
1116
|
+
background: var(--panel-soft);
|
|
1117
|
+
color: var(--text-muted);
|
|
1118
|
+
font-size: 11px;
|
|
1119
|
+
line-height: 1.4;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
.usage-status {
|
|
1123
|
+
display: inline-flex;
|
|
1124
|
+
align-items: center;
|
|
1125
|
+
gap: 5px;
|
|
1126
|
+
min-width: 0;
|
|
1127
|
+
white-space: nowrap;
|
|
1128
|
+
font-weight: 700;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
.usage-status svg {
|
|
1132
|
+
width: 12px;
|
|
1133
|
+
height: 12px;
|
|
1134
|
+
color: var(--text-muted);
|
|
1135
|
+
flex: 0 0 auto;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
.usage-dot {
|
|
1139
|
+
width: 6px;
|
|
1140
|
+
height: 6px;
|
|
1141
|
+
border-radius: 999px;
|
|
1142
|
+
background: #cbd5e1;
|
|
1143
|
+
flex: 0 0 auto;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
.usage-dot.active {
|
|
1147
|
+
background: #22c55e;
|
|
1148
|
+
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.12);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
.usage-state-text {
|
|
1152
|
+
color: var(--text-muted);
|
|
1153
|
+
font-weight: 700;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
.usage-status.is-active .usage-state-text {
|
|
1157
|
+
color: #15803d;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
.compact-meta-row {
|
|
1161
|
+
display: grid;
|
|
1162
|
+
gap: 8px;
|
|
1163
|
+
min-width: 0;
|
|
1164
|
+
color: var(--text-muted);
|
|
1165
|
+
font-size: 11px;
|
|
1166
|
+
line-height: 1.45;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.compact-reset-list {
|
|
1170
|
+
display: flex;
|
|
1171
|
+
flex-wrap: nowrap;
|
|
1172
|
+
align-items: center;
|
|
1173
|
+
gap: 10px;
|
|
1174
|
+
min-width: 0;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
.compact-meta-item {
|
|
1178
|
+
display: flex;
|
|
1179
|
+
align-items: baseline;
|
|
1180
|
+
gap: 5px;
|
|
1181
|
+
min-width: 0;
|
|
1182
|
+
flex: 1 1 0;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.compact-meta-item label {
|
|
1186
|
+
color: var(--text-muted);
|
|
1187
|
+
font-size: 10px;
|
|
1188
|
+
line-height: 1.4;
|
|
1189
|
+
white-space: nowrap;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
.compact-meta-item strong {
|
|
1193
|
+
color: var(--text-soft);
|
|
1194
|
+
font-size: 11px;
|
|
1195
|
+
line-height: 1.4;
|
|
1196
|
+
text-align: left;
|
|
1197
|
+
overflow-wrap: anywhere;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.compact-meta-actions {
|
|
1201
|
+
display: flex;
|
|
1202
|
+
align-items: center;
|
|
1203
|
+
justify-content: center;
|
|
1204
|
+
gap: 10px;
|
|
1205
|
+
margin-top: 2px;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.compact-meta-actions::before,
|
|
1209
|
+
.compact-meta-actions::after {
|
|
1210
|
+
content: "";
|
|
1211
|
+
height: 1px;
|
|
1212
|
+
background: var(--line);
|
|
1213
|
+
flex: 1 1 auto;
|
|
1214
|
+
min-width: 18px;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
.details-toggle {
|
|
1218
|
+
display: inline-flex;
|
|
1219
|
+
align-items: center;
|
|
1220
|
+
justify-content: center;
|
|
1221
|
+
gap: 5px;
|
|
1222
|
+
min-height: 24px;
|
|
1223
|
+
padding: 0 6px;
|
|
1224
|
+
border: 0;
|
|
1225
|
+
background: transparent;
|
|
1226
|
+
color: var(--brand);
|
|
1227
|
+
font-size: 11px;
|
|
1228
|
+
font-weight: 700;
|
|
1229
|
+
white-space: nowrap;
|
|
1230
|
+
cursor: pointer;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
.details-toggle:hover {
|
|
1234
|
+
color: #4338ca;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
.details-toggle svg {
|
|
1238
|
+
width: 12px;
|
|
1239
|
+
height: 12px;
|
|
1240
|
+
transition: transform 0.16s ease;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
.details-toggle.is-expanded svg {
|
|
1244
|
+
transform: rotate(180deg);
|
|
813
1245
|
}
|
|
814
1246
|
|
|
815
1247
|
.quota-row {
|
|
@@ -871,6 +1303,8 @@ function renderAdminPage() {
|
|
|
871
1303
|
display: grid;
|
|
872
1304
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
873
1305
|
gap: 8px 12px;
|
|
1306
|
+
padding-top: 10px;
|
|
1307
|
+
border-top: 1px solid var(--line);
|
|
874
1308
|
}
|
|
875
1309
|
|
|
876
1310
|
.meta-item {
|
|
@@ -911,6 +1345,38 @@ function renderAdminPage() {
|
|
|
911
1345
|
font-size: 12px;
|
|
912
1346
|
}
|
|
913
1347
|
|
|
1348
|
+
.account-actions .btn-secondary.is-current {
|
|
1349
|
+
position: relative;
|
|
1350
|
+
opacity: 1;
|
|
1351
|
+
color: #047857;
|
|
1352
|
+
background: linear-gradient(135deg, #f0fdf4, #dcfce7);
|
|
1353
|
+
border-color: rgba(16, 185, 129, 0.36);
|
|
1354
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8), 0 6px 14px rgba(16, 185, 129, 0.08);
|
|
1355
|
+
cursor: default;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
.account-actions .btn-secondary.is-current::before {
|
|
1359
|
+
content: "";
|
|
1360
|
+
width: 7px;
|
|
1361
|
+
height: 7px;
|
|
1362
|
+
border-radius: 999px;
|
|
1363
|
+
background: #22c55e;
|
|
1364
|
+
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.12);
|
|
1365
|
+
flex: 0 0 auto;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
.account-actions .btn-secondary.is-current.codex {
|
|
1369
|
+
color: #1d4ed8;
|
|
1370
|
+
background: linear-gradient(135deg, #eff6ff, #dbeafe);
|
|
1371
|
+
border-color: rgba(37, 99, 235, 0.32);
|
|
1372
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8), 0 6px 14px rgba(37, 99, 235, 0.08);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
.account-actions .btn-secondary.is-current.codex::before {
|
|
1376
|
+
background: #3b82f6;
|
|
1377
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.12);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
914
1380
|
.account-status {
|
|
915
1381
|
display: inline-flex;
|
|
916
1382
|
align-items: center;
|
|
@@ -1325,6 +1791,10 @@ function renderAdminPage() {
|
|
|
1325
1791
|
padding: 12px;
|
|
1326
1792
|
}
|
|
1327
1793
|
|
|
1794
|
+
.settings-drawer {
|
|
1795
|
+
width: 100vw;
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1328
1798
|
.modal-head,
|
|
1329
1799
|
.modal-body {
|
|
1330
1800
|
padding-left: 16px;
|
|
@@ -1366,7 +1836,7 @@ function renderAdminPage() {
|
|
|
1366
1836
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M8 6h13"></path><path d="M8 12h13"></path><path d="M8 18h13"></path><path d="M3 6h.01"></path><path d="M3 12h.01"></path><path d="M3 18h.01"></path></svg>
|
|
1367
1837
|
\u8BF7\u6C42\u65E5\u5FD7
|
|
1368
1838
|
</button>
|
|
1369
|
-
<button class="nav-item" type="button" data-
|
|
1839
|
+
<button class="nav-item" type="button" data-open-settings>
|
|
1370
1840
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.6 1.6 0 0 0 .33 1.76l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.6 1.6 0 0 0-1.76-.33 1.6 1.6 0 0 0-.97 1.46V21a2 2 0 0 1-4 0v-.09a1.6 1.6 0 0 0-.97-1.46 1.6 1.6 0 0 0-1.76.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.6 1.6 0 0 0 .33-1.76 1.6 1.6 0 0 0-1.46-.97H3a2 2 0 0 1 0-4h.09a1.6 1.6 0 0 0 1.46-.97 1.6 1.6 0 0 0-.33-1.76l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.6 1.6 0 0 0 1.76.33H9a1.6 1.6 0 0 0 .97-1.46V3a2 2 0 0 1 4 0v.09a1.6 1.6 0 0 0 .97 1.46 1.6 1.6 0 0 0 1.76-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.6 1.6 0 0 0-.33 1.76V9c0 .64.38 1.22.97 1.46H21a2 2 0 0 1 0 4h-.09c-.64 0-1.22.38-1.46.97Z"></path></svg>
|
|
1371
1841
|
\u7CFB\u7EDF\u8BBE\u7F6E
|
|
1372
1842
|
</button>
|
|
@@ -1389,6 +1859,7 @@ function renderAdminPage() {
|
|
|
1389
1859
|
</div>
|
|
1390
1860
|
<div class="top-actions">
|
|
1391
1861
|
<a class="btn-link" href="https://github.com/fchangjun/AI-Zero-Token" target="_blank" rel="noreferrer">GitHub \u4ED3\u5E93</a>
|
|
1862
|
+
<button class="btn-secondary" id="openSettingsBtn" type="button">\u8BBE\u7F6E</button>
|
|
1392
1863
|
<button class="btn-secondary" id="contactBtn" type="button">\u4EA4\u6D41\u53CD\u9988</button>
|
|
1393
1864
|
<button class="btn-secondary" id="toggleEmailBtn" type="button">\u8131\u654F\u6A21\u5F0F</button>
|
|
1394
1865
|
<button class="btn-primary" id="loginBtn" type="button">+ \u65B0\u589E\u8D26\u53F7</button>
|
|
@@ -1427,8 +1898,9 @@ function renderAdminPage() {
|
|
|
1427
1898
|
<option value="all">\u5168\u90E8\u72B6\u6001</option>
|
|
1428
1899
|
<option value="healthy">\u5065\u5EB7</option>
|
|
1429
1900
|
<option value="warning">\u5373\u5C06\u8017\u5C3D</option>
|
|
1901
|
+
<option value="invalid">\u767B\u5F55\u5931\u6548</option>
|
|
1430
1902
|
<option value="expired">\u5DF2\u8FC7\u671F</option>
|
|
1431
|
-
<option value="active">\
|
|
1903
|
+
<option value="active">\u4F7F\u7528\u4E2D</option>
|
|
1432
1904
|
</select>
|
|
1433
1905
|
<select class="control" id="profileSort">
|
|
1434
1906
|
<option value="quota-desc">\u6309\u4E3B\u989D\u5EA6\u6392\u5E8F</option>
|
|
@@ -1508,32 +1980,6 @@ function renderAdminPage() {
|
|
|
1508
1980
|
<select class="control" id="endpointSelect"></select>
|
|
1509
1981
|
</div>
|
|
1510
1982
|
|
|
1511
|
-
<div class="field" id="settings">
|
|
1512
|
-
<label for="defaultModel">\u9ED8\u8BA4\u6A21\u578B</label>
|
|
1513
|
-
<select class="control" id="defaultModel"></select>
|
|
1514
|
-
<p class="hint">\u5207\u6362\u540E\u4F1A\u5F71\u54CD\u672A\u663E\u5F0F\u4F20 <code>model</code> \u7684\u8BF7\u6C42\u3002</p>
|
|
1515
|
-
<p class="hint" id="modelCatalogHint"></p>
|
|
1516
|
-
<div class="actions">
|
|
1517
|
-
<button class="btn-secondary" id="refreshModelsBtn" type="button">\u540C\u6B65 Codex \u6A21\u578B</button>
|
|
1518
|
-
<button class="btn-primary" id="saveModelBtn" type="button">\u4FDD\u5B58\u9ED8\u8BA4\u6A21\u578B</button>
|
|
1519
|
-
</div>
|
|
1520
|
-
</div>
|
|
1521
|
-
|
|
1522
|
-
<div class="field">
|
|
1523
|
-
<label class="checkbox-row" for="proxyEnabled">
|
|
1524
|
-
<input id="proxyEnabled" type="checkbox" />
|
|
1525
|
-
\u542F\u7528\u4E0A\u6E38\u4EE3\u7406
|
|
1526
|
-
</label>
|
|
1527
|
-
<label for="proxyUrl">\u4EE3\u7406\u5730\u5740</label>
|
|
1528
|
-
<input class="input" id="proxyUrl" type="text" placeholder="\u586B\u5199\u4F60\u7684\u4EE3\u7406\u5730\u5740" />
|
|
1529
|
-
<label for="proxyNoProxy">\u76F4\u8FDE\u5730\u5740</label>
|
|
1530
|
-
<input class="input" id="proxyNoProxy" type="text" placeholder="localhost,127.0.0.1,::1" />
|
|
1531
|
-
<p class="hint">\u542F\u7528\u540E\uFF0COAuth \u6362\u53D6 token\u3001\u6A21\u578B\u5237\u65B0\u548C\u63A5\u53E3\u8F6C\u53D1\u4F1A\u901A\u8FC7\u6B64\u4EE3\u7406\u8BBF\u95EE\u6D77\u5916\u4E0A\u6E38\u3002</p>
|
|
1532
|
-
<div class="actions">
|
|
1533
|
-
<button class="btn-primary" id="saveProxyBtn" type="button">\u4FDD\u5B58\u4EE3\u7406\u914D\u7F6E</button>
|
|
1534
|
-
</div>
|
|
1535
|
-
</div>
|
|
1536
|
-
|
|
1537
1983
|
<div class="field">
|
|
1538
1984
|
<label for="requestBody">\u8BF7\u6C42\u4F53 JSON</label>
|
|
1539
1985
|
<textarea class="textarea" id="requestBody" spellcheck="false"></textarea>
|
|
@@ -1597,6 +2043,65 @@ function renderAdminPage() {
|
|
|
1597
2043
|
</main>
|
|
1598
2044
|
</div>
|
|
1599
2045
|
|
|
2046
|
+
<div class="drawer-backdrop" id="settingsDrawerBackdrop" aria-hidden="true">
|
|
2047
|
+
<aside class="settings-drawer" role="dialog" aria-modal="true" aria-labelledby="settingsDrawerTitle">
|
|
2048
|
+
<div class="settings-drawer-head">
|
|
2049
|
+
<div>
|
|
2050
|
+
<h3 id="settingsDrawerTitle">\u7CFB\u7EDF\u8BBE\u7F6E</h3>
|
|
2051
|
+
<p>\u96C6\u4E2D\u7BA1\u7406\u9ED8\u8BA4\u6A21\u578B\u3001\u4E0A\u6E38\u4EE3\u7406\u548C\u989D\u5EA6\u8017\u5C3D\u540E\u7684\u81EA\u52A8\u5207\u6362\u7B56\u7565\u3002</p>
|
|
2052
|
+
</div>
|
|
2053
|
+
<button class="btn-secondary" id="closeSettingsDrawerBtn" type="button">\u5173\u95ED</button>
|
|
2054
|
+
</div>
|
|
2055
|
+
<div class="settings-drawer-body">
|
|
2056
|
+
<section class="settings-section">
|
|
2057
|
+
<h4>\u9ED8\u8BA4\u6A21\u578B</h4>
|
|
2058
|
+
<div class="field">
|
|
2059
|
+
<label for="defaultModel">\u9ED8\u8BA4\u6A21\u578B</label>
|
|
2060
|
+
<select class="control" id="defaultModel"></select>
|
|
2061
|
+
<p class="hint">\u5F71\u54CD\u672A\u663E\u5F0F\u4F20 <code>model</code> \u7684\u8BF7\u6C42\u3002</p>
|
|
2062
|
+
<p class="hint" id="modelCatalogHint"></p>
|
|
2063
|
+
<div class="actions">
|
|
2064
|
+
<button class="btn-secondary" id="refreshModelsBtn" type="button">\u540C\u6B65 Codex \u6A21\u578B</button>
|
|
2065
|
+
</div>
|
|
2066
|
+
</div>
|
|
2067
|
+
</section>
|
|
2068
|
+
|
|
2069
|
+
<section class="settings-section">
|
|
2070
|
+
<h4>\u4E0A\u6E38\u4EE3\u7406</h4>
|
|
2071
|
+
<div class="field">
|
|
2072
|
+
<label class="checkbox-row" for="proxyEnabled">
|
|
2073
|
+
<input id="proxyEnabled" type="checkbox" />
|
|
2074
|
+
\u542F\u7528\u4E0A\u6E38\u4EE3\u7406
|
|
2075
|
+
</label>
|
|
2076
|
+
<label for="proxyUrl">\u4EE3\u7406\u5730\u5740</label>
|
|
2077
|
+
<input class="input" id="proxyUrl" type="text" placeholder="\u586B\u5199\u4F60\u7684\u4EE3\u7406\u5730\u5740" />
|
|
2078
|
+
<label for="proxyNoProxy">\u76F4\u8FDE\u5730\u5740</label>
|
|
2079
|
+
<input class="input" id="proxyNoProxy" type="text" placeholder="localhost,127.0.0.1,::1" />
|
|
2080
|
+
<p class="hint">\u542F\u7528\u540E\uFF0COAuth \u6362\u53D6 token\u3001\u6A21\u578B\u5237\u65B0\u548C\u63A5\u53E3\u8F6C\u53D1\u4F1A\u901A\u8FC7\u6B64\u4EE3\u7406\u8BBF\u95EE\u6D77\u5916\u4E0A\u6E38\u3002</p>
|
|
2081
|
+
<div class="actions">
|
|
2082
|
+
<button class="btn-secondary" id="testProxyBtn" type="button">\u6D4B\u8BD5\u4EE3\u7406</button>
|
|
2083
|
+
</div>
|
|
2084
|
+
</div>
|
|
2085
|
+
</section>
|
|
2086
|
+
|
|
2087
|
+
<section class="settings-section">
|
|
2088
|
+
<h4>\u8D26\u53F7\u5207\u6362</h4>
|
|
2089
|
+
<div class="field">
|
|
2090
|
+
<label class="checkbox-row" for="autoSwitchEnabled">
|
|
2091
|
+
<input id="autoSwitchEnabled" type="checkbox" />
|
|
2092
|
+
\u989D\u5EA6\u8017\u5C3D\u81EA\u52A8\u5207\u6362
|
|
2093
|
+
</label>
|
|
2094
|
+
<p class="hint">\u5F00\u542F\u540E\uFF0C\u5F53\u524D API \u8D26\u53F7\u989D\u5EA6\u5FEB\u7167\u5DF2\u8017\u5C3D\u65F6\uFF0C\u7F51\u5173\u4F1A\u6309\u8D26\u53F7\u6C60\u987A\u5E8F\u5207\u5230\u4ECD\u6709\u989D\u5EA6\u7684\u8D26\u53F7\uFF0C\u5E76\u5C3D\u91CF\u907F\u5F00 Codex \u6B63\u5728\u4F7F\u7528\u7684\u8D26\u53F7\u3002</p>
|
|
2095
|
+
</div>
|
|
2096
|
+
</section>
|
|
2097
|
+
</div>
|
|
2098
|
+
<div class="settings-drawer-footer">
|
|
2099
|
+
<p class="status-inline" id="settingsStatus"></p>
|
|
2100
|
+
<button class="btn-primary" id="saveSettingsBtn" type="button">\u4FDD\u5B58\u8BBE\u7F6E</button>
|
|
2101
|
+
</div>
|
|
2102
|
+
</aside>
|
|
2103
|
+
</div>
|
|
2104
|
+
|
|
1600
2105
|
<div class="modal-backdrop" id="imagePreviewModal" aria-hidden="true">
|
|
1601
2106
|
<section class="modal-card preview-modal-card" role="dialog" aria-modal="true" aria-labelledby="imagePreviewTitle">
|
|
1602
2107
|
<div class="modal-head">
|
|
@@ -1686,7 +2191,8 @@ function renderAdminPage() {
|
|
|
1686
2191
|
</div>
|
|
1687
2192
|
|
|
1688
2193
|
<script>
|
|
1689
|
-
const RUNTIME_AUTO_REFRESH_MS =
|
|
2194
|
+
const RUNTIME_AUTO_REFRESH_MS = 5 * 60 * 1000;
|
|
2195
|
+
const ACTIVE_PROFILE_REFRESH_MS = 15 * 1000;
|
|
1690
2196
|
|
|
1691
2197
|
const state = {
|
|
1692
2198
|
config: null,
|
|
@@ -1698,7 +2204,9 @@ function renderAdminPage() {
|
|
|
1698
2204
|
sort: "quota-desc",
|
|
1699
2205
|
},
|
|
1700
2206
|
selectedProfileIds: {},
|
|
2207
|
+
expandedProfileIds: {},
|
|
1701
2208
|
testerResultTab: "response",
|
|
2209
|
+
settingsDirty: false,
|
|
1702
2210
|
};
|
|
1703
2211
|
|
|
1704
2212
|
const endpointMeta = {
|
|
@@ -1743,6 +2251,7 @@ function renderAdminPage() {
|
|
|
1743
2251
|
const accountModal = document.getElementById("accountModal");
|
|
1744
2252
|
const contactModal = document.getElementById("contactModal");
|
|
1745
2253
|
const imagePreviewModal = document.getElementById("imagePreviewModal");
|
|
2254
|
+
const settingsDrawerBackdrop = document.getElementById("settingsDrawerBackdrop");
|
|
1746
2255
|
const contactBtn = document.getElementById("contactBtn");
|
|
1747
2256
|
const previewModalImage = document.getElementById("previewModalImage");
|
|
1748
2257
|
const previewModalMeta = document.getElementById("previewModalMeta");
|
|
@@ -1759,6 +2268,10 @@ function renderAdminPage() {
|
|
|
1759
2268
|
const proxyEnabled = document.getElementById("proxyEnabled");
|
|
1760
2269
|
const proxyUrl = document.getElementById("proxyUrl");
|
|
1761
2270
|
const proxyNoProxy = document.getElementById("proxyNoProxy");
|
|
2271
|
+
const testProxyBtn = document.getElementById("testProxyBtn");
|
|
2272
|
+
const autoSwitchEnabled = document.getElementById("autoSwitchEnabled");
|
|
2273
|
+
const settingsStatus = document.getElementById("settingsStatus");
|
|
2274
|
+
const saveSettingsBtn = document.getElementById("saveSettingsBtn");
|
|
1762
2275
|
|
|
1763
2276
|
function setBusy(button, busy) {
|
|
1764
2277
|
if (button) {
|
|
@@ -1790,6 +2303,13 @@ function renderAdminPage() {
|
|
|
1790
2303
|
return date.toLocaleString("zh-CN", { hour12: false });
|
|
1791
2304
|
}
|
|
1792
2305
|
|
|
2306
|
+
function timestampToMillis(value) {
|
|
2307
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
2308
|
+
return null;
|
|
2309
|
+
}
|
|
2310
|
+
return value < 1000000000000 ? value * 1000 : value;
|
|
2311
|
+
}
|
|
2312
|
+
|
|
1793
2313
|
function formatShortTime(value) {
|
|
1794
2314
|
if (!value) {
|
|
1795
2315
|
return "--:--";
|
|
@@ -1850,6 +2370,9 @@ function renderAdminPage() {
|
|
|
1850
2370
|
if (minutes === 60 * 24) {
|
|
1851
2371
|
return "\u65E5\u989D\u5EA6";
|
|
1852
2372
|
}
|
|
2373
|
+
if (minutes === 60 * 5) {
|
|
2374
|
+
return "5 \u5C0F\u65F6\u989D\u5EA6";
|
|
2375
|
+
}
|
|
1853
2376
|
if (minutes === 60 * 24 * 7) {
|
|
1854
2377
|
return "\u5468\u989D\u5EA6";
|
|
1855
2378
|
}
|
|
@@ -1862,6 +2385,68 @@ function renderAdminPage() {
|
|
|
1862
2385
|
: "unknown";
|
|
1863
2386
|
}
|
|
1864
2387
|
|
|
2388
|
+
function getPlanRank(profile) {
|
|
2389
|
+
const plan = getPlanType(profile).toLowerCase();
|
|
2390
|
+
if (plan.indexOf("enterprise") !== -1 || plan.indexOf("business") !== -1) {
|
|
2391
|
+
return 60;
|
|
2392
|
+
}
|
|
2393
|
+
if (plan.indexOf("team") !== -1) {
|
|
2394
|
+
return 50;
|
|
2395
|
+
}
|
|
2396
|
+
if (plan.indexOf("pro") !== -1 || plan.indexOf("premium") !== -1) {
|
|
2397
|
+
return 40;
|
|
2398
|
+
}
|
|
2399
|
+
if (plan.indexOf("plus") !== -1) {
|
|
2400
|
+
return 30;
|
|
2401
|
+
}
|
|
2402
|
+
if (plan.indexOf("free") !== -1) {
|
|
2403
|
+
return 10;
|
|
2404
|
+
}
|
|
2405
|
+
return 0;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
function getPlanKey(profile) {
|
|
2409
|
+
const plan = getPlanType(profile).toLowerCase();
|
|
2410
|
+
if (plan.indexOf("enterprise") !== -1 || plan.indexOf("business") !== -1) {
|
|
2411
|
+
return "enterprise";
|
|
2412
|
+
}
|
|
2413
|
+
if (plan.indexOf("team") !== -1) {
|
|
2414
|
+
return "team";
|
|
2415
|
+
}
|
|
2416
|
+
if (plan.indexOf("pro") !== -1 || plan.indexOf("premium") !== -1) {
|
|
2417
|
+
return plan.indexOf("premium") !== -1 ? "premium" : "pro";
|
|
2418
|
+
}
|
|
2419
|
+
if (plan.indexOf("plus") !== -1) {
|
|
2420
|
+
return "plus";
|
|
2421
|
+
}
|
|
2422
|
+
if (plan.indexOf("free") !== -1) {
|
|
2423
|
+
return "free";
|
|
2424
|
+
}
|
|
2425
|
+
return "unknown";
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
function getUsageCorner(profile, isCodexActive) {
|
|
2429
|
+
if (profile.isActive && isCodexActive) {
|
|
2430
|
+
return {
|
|
2431
|
+
className: "dual",
|
|
2432
|
+
label: "API + Codex",
|
|
2433
|
+
};
|
|
2434
|
+
}
|
|
2435
|
+
if (profile.isActive) {
|
|
2436
|
+
return {
|
|
2437
|
+
className: "api-only",
|
|
2438
|
+
label: "API",
|
|
2439
|
+
};
|
|
2440
|
+
}
|
|
2441
|
+
if (isCodexActive) {
|
|
2442
|
+
return {
|
|
2443
|
+
className: "codex-only",
|
|
2444
|
+
label: "Codex",
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
return null;
|
|
2448
|
+
}
|
|
2449
|
+
|
|
1865
2450
|
function getQuotaSnapshotTime(profile) {
|
|
1866
2451
|
return profile && profile.quota && typeof profile.quota.capturedAt === "number"
|
|
1867
2452
|
? profile.quota.capturedAt
|
|
@@ -1951,6 +2536,15 @@ function renderAdminPage() {
|
|
|
1951
2536
|
};
|
|
1952
2537
|
}
|
|
1953
2538
|
|
|
2539
|
+
if (profile.authStatus && (profile.authStatus.state === "token_invalidated" || profile.authStatus.state === "auth_error")) {
|
|
2540
|
+
return {
|
|
2541
|
+
supported: false,
|
|
2542
|
+
label: "\u8BA4\u8BC1\u5931\u6548",
|
|
2543
|
+
detail: "\u8D26\u53F7\u8BA4\u8BC1\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u540E\u518D\u4F7F\u7528\u56FE\u7247\u751F\u6210\u3002",
|
|
2544
|
+
badgeClass: "red",
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
|
|
1954
2548
|
const planType = getPlanType(profile);
|
|
1955
2549
|
if (planType === "free") {
|
|
1956
2550
|
return {
|
|
@@ -1969,6 +2563,17 @@ function renderAdminPage() {
|
|
|
1969
2563
|
};
|
|
1970
2564
|
}
|
|
1971
2565
|
|
|
2566
|
+
function describeAuthStatus(profile) {
|
|
2567
|
+
const authStatus = profile && profile.authStatus ? profile.authStatus : null;
|
|
2568
|
+
if (!authStatus || authStatus.state === "ok") {
|
|
2569
|
+
return authStatus && authStatus.checkedAt ? "\u6B63\u5E38 \xB7 " + formatTime(authStatus.checkedAt) : "\u6B63\u5E38";
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
const prefix = authStatus.state === "token_invalidated" ? "\u767B\u5F55\u5931\u6548" : "\u8BA4\u8BC1\u5F02\u5E38";
|
|
2573
|
+
const detail = authStatus.code || authStatus.httpStatus ? " (" + (authStatus.code || authStatus.httpStatus) + ")" : "";
|
|
2574
|
+
return prefix + detail + " \xB7 " + formatTime(authStatus.checkedAt);
|
|
2575
|
+
}
|
|
2576
|
+
|
|
1972
2577
|
function maskEmail(email) {
|
|
1973
2578
|
if (typeof email !== "string" || email.indexOf("@") === -1) {
|
|
1974
2579
|
return email || "";
|
|
@@ -2050,8 +2655,59 @@ function renderAdminPage() {
|
|
|
2050
2655
|
return Math.max(0, Math.min(100, value));
|
|
2051
2656
|
}
|
|
2052
2657
|
|
|
2658
|
+
function isProfileQuotaExhausted(profile) {
|
|
2659
|
+
if (!profile || !profile.quota) {
|
|
2660
|
+
return false;
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
return getPrimaryUsage(profile) >= 100 || getSecondaryUsage(profile) >= 100;
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
function findProfileById(profileId) {
|
|
2667
|
+
const profiles = state.config && Array.isArray(state.config.profiles) ? state.config.profiles : [];
|
|
2668
|
+
return profiles.find(function (profile) {
|
|
2669
|
+
return profile.profileId === profileId;
|
|
2670
|
+
}) || null;
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
function confirmQuotaSwitch(action, profileId) {
|
|
2674
|
+
if (action !== "activate" && action !== "apply-codex") {
|
|
2675
|
+
return true;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
const profile = findProfileById(profileId);
|
|
2679
|
+
if (!isProfileQuotaExhausted(profile)) {
|
|
2680
|
+
return true;
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
const target = action === "activate" ? "\u7F51\u5173" : "Codex";
|
|
2684
|
+
const label = getProfileDisplayLabel(profile);
|
|
2685
|
+
const message = "\u8D26\u53F7 \u201C" + label + "\u201D \u7684\u989D\u5EA6\u5FEB\u7167\u663E\u793A\u5DF2\u8017\u5C3D\u3002\\n\\n\u4ECD\u8981\u5E94\u7528\u5230 " + target + " \u5417\uFF1F";
|
|
2686
|
+
const confirmed = window.confirm(message);
|
|
2687
|
+
if (!confirmed) {
|
|
2688
|
+
authStatus.textContent = "\u5DF2\u53D6\u6D88\u5E94\u7528\u5230 " + target + "\u3002";
|
|
2689
|
+
}
|
|
2690
|
+
return confirmed;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2053
2693
|
function getProfileHealth(profile) {
|
|
2054
2694
|
const now = Date.now();
|
|
2695
|
+
if (profile && profile.authStatus && profile.authStatus.state === "token_invalidated") {
|
|
2696
|
+
return {
|
|
2697
|
+
key: "invalid",
|
|
2698
|
+
label: "\u767B\u5F55\u5931\u6548",
|
|
2699
|
+
badgeClass: "red",
|
|
2700
|
+
barClass: "red",
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
if (profile && profile.authStatus && profile.authStatus.state === "auth_error") {
|
|
2704
|
+
return {
|
|
2705
|
+
key: "invalid",
|
|
2706
|
+
label: "\u8BA4\u8BC1\u5F02\u5E38",
|
|
2707
|
+
badgeClass: "red",
|
|
2708
|
+
barClass: "red",
|
|
2709
|
+
};
|
|
2710
|
+
}
|
|
2055
2711
|
if (profile && profile.expiresAt && profile.expiresAt <= now) {
|
|
2056
2712
|
return {
|
|
2057
2713
|
key: "expired",
|
|
@@ -2096,8 +2752,9 @@ function renderAdminPage() {
|
|
|
2096
2752
|
const quota = profile.quota;
|
|
2097
2753
|
const resetAt = slot === "primary" ? quota.primaryResetAt : quota.secondaryResetAt;
|
|
2098
2754
|
const resetAfter = slot === "primary" ? quota.primaryResetAfterSeconds : quota.secondaryResetAfterSeconds;
|
|
2099
|
-
|
|
2100
|
-
|
|
2755
|
+
const resetAtMillis = timestampToMillis(resetAt);
|
|
2756
|
+
if (resetAtMillis) {
|
|
2757
|
+
return formatTime(resetAtMillis);
|
|
2101
2758
|
}
|
|
2102
2759
|
if (typeof resetAfter === "number" && resetAfter > 0) {
|
|
2103
2760
|
return formatCompactDuration(resetAfter) + "\u540E";
|
|
@@ -2105,6 +2762,39 @@ function renderAdminPage() {
|
|
|
2105
2762
|
return "\u672A\u77E5";
|
|
2106
2763
|
}
|
|
2107
2764
|
|
|
2765
|
+
function formatCompactDateTime(value) {
|
|
2766
|
+
if (!value) {
|
|
2767
|
+
return "\u6682\u65E0\u6570\u636E";
|
|
2768
|
+
}
|
|
2769
|
+
const date = new Date(value);
|
|
2770
|
+
if (Number.isNaN(date.getTime())) {
|
|
2771
|
+
return "\u672A\u77E5";
|
|
2772
|
+
}
|
|
2773
|
+
const month = String(date.getMonth() + 1);
|
|
2774
|
+
const day = String(date.getDate());
|
|
2775
|
+
const time = date.toLocaleTimeString("zh-CN", { hour12: false, hour: "2-digit", minute: "2-digit" });
|
|
2776
|
+
return month + "/" + day + " " + time;
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
function describeCompactReset(profile, slot) {
|
|
2780
|
+
if (!profile || !profile.quota) {
|
|
2781
|
+
return "\u6682\u65E0\u6570\u636E";
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
const quota = profile.quota;
|
|
2785
|
+
const resetAt = slot === "primary" ? quota.primaryResetAt : quota.secondaryResetAt;
|
|
2786
|
+
const resetAfter = slot === "primary" ? quota.primaryResetAfterSeconds : quota.secondaryResetAfterSeconds;
|
|
2787
|
+
const resetAtMillis = timestampToMillis(resetAt);
|
|
2788
|
+
if (resetAtMillis) {
|
|
2789
|
+
return formatCompactDateTime(resetAtMillis);
|
|
2790
|
+
}
|
|
2791
|
+
if (typeof resetAfter === "number" && resetAfter > 0) {
|
|
2792
|
+
const capturedAt = timestampToMillis(quota.capturedAt);
|
|
2793
|
+
return capturedAt ? formatCompactDateTime(capturedAt + resetAfter * 1000) : formatCompactDuration(resetAfter) + "\u540E";
|
|
2794
|
+
}
|
|
2795
|
+
return "\u672A\u77E5";
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2108
2798
|
function getQuotaWindowLabel(profile, slot) {
|
|
2109
2799
|
const quota = profile && profile.quota ? profile.quota : null;
|
|
2110
2800
|
if (!quota) {
|
|
@@ -2114,6 +2804,17 @@ function renderAdminPage() {
|
|
|
2114
2804
|
return formatWindowLabel(quota && quota[field]);
|
|
2115
2805
|
}
|
|
2116
2806
|
|
|
2807
|
+
function getResetLabel(profile, slot) {
|
|
2808
|
+
const label = getQuotaWindowLabel(profile, slot);
|
|
2809
|
+
if (label === "5 \u5C0F\u65F6\u989D\u5EA6") {
|
|
2810
|
+
return "5\u5C0F\u65F6\u91CD\u7F6E";
|
|
2811
|
+
}
|
|
2812
|
+
if (label === "\u5468\u989D\u5EA6") {
|
|
2813
|
+
return "\u5468\u91CD\u7F6E";
|
|
2814
|
+
}
|
|
2815
|
+
return label.replace("\u989D\u5EA6", "") + "\u91CD\u7F6E";
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2117
2818
|
function formatQuotaUsage(percent, profile, slot) {
|
|
2118
2819
|
if (!profile || !profile.quota) {
|
|
2119
2820
|
return "\u7B49\u5F85\u5237\u65B0";
|
|
@@ -2362,50 +3063,58 @@ function renderAdminPage() {
|
|
|
2362
3063
|
const codexProfile = codexAccountId && Array.isArray(config.profiles)
|
|
2363
3064
|
? config.profiles.find(function (profile) { return profile.accountId === codexAccountId; })
|
|
2364
3065
|
: null;
|
|
3066
|
+
const gatewayLabel = config.profile ? getProfileDisplayLabel(config.profile) : "\u672A\u6FC0\u6D3B\u8D26\u53F7";
|
|
3067
|
+
const codexLabel = codexProfile
|
|
3068
|
+
? getProfileDisplayLabel(codexProfile)
|
|
3069
|
+
: (codexAccountId ? maskIdentifier(codexAccountId) : "\u672A\u68C0\u6D4B\u5230");
|
|
2365
3070
|
|
|
2366
3071
|
return [
|
|
2367
3072
|
{
|
|
3073
|
+
icon: "users",
|
|
3074
|
+
iconClass: "blue",
|
|
2368
3075
|
label: "\u8D26\u53F7\u603B\u6570",
|
|
2369
3076
|
value: String(config.status.profileCount || 0),
|
|
2370
3077
|
detail: "\u5DF2\u4FDD\u5B58\u5230\u672C\u5730\u8D26\u53F7\u6C60",
|
|
2371
3078
|
},
|
|
2372
3079
|
{
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
: "\u5C1A\u672A\u6FC0\u6D3B\u8D26\u53F7",
|
|
2378
|
-
compact: true,
|
|
3080
|
+
kind: "account-status",
|
|
3081
|
+
label: "\u5F53\u524D\u8D26\u53F7\u72B6\u6001",
|
|
3082
|
+
gatewayLabel: gatewayLabel,
|
|
3083
|
+
codexLabel: codexLabel,
|
|
2379
3084
|
},
|
|
2380
3085
|
{
|
|
3086
|
+
icon: "model",
|
|
3087
|
+
iconClass: "brand",
|
|
2381
3088
|
label: "\u9ED8\u8BA4\u6A21\u578B",
|
|
2382
3089
|
value: config.settings.defaultModel || "-",
|
|
2383
3090
|
detail: "\u672A\u663E\u5F0F\u6307\u5B9A model \u65F6\u751F\u6548",
|
|
2384
3091
|
compact: true,
|
|
2385
3092
|
},
|
|
2386
3093
|
{
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
detail: config.codex && config.codex.exists ? "\u6765\u81EA ~/.codex/auth.json" : "\u5C1A\u672A\u5E94\u7528\u5230 Codex",
|
|
2390
|
-
compact: true,
|
|
2391
|
-
},
|
|
2392
|
-
{
|
|
3094
|
+
icon: "version",
|
|
3095
|
+
iconClass: config.versionStatus && config.versionStatus.needsUpdate ? "orange" : "green",
|
|
2393
3096
|
label: "\u5F53\u524D\u7248\u672C",
|
|
2394
3097
|
value: getVersionValue(config),
|
|
2395
3098
|
detail: getVersionDetail(config),
|
|
2396
3099
|
compact: true,
|
|
2397
3100
|
},
|
|
2398
3101
|
{
|
|
3102
|
+
icon: "requests",
|
|
3103
|
+
iconClass: "blue",
|
|
2399
3104
|
label: "\u4ECA\u65E5\u8BF7\u6C42\u6570",
|
|
2400
3105
|
value: String(requests.length),
|
|
2401
3106
|
detail: "\u57FA\u4E8E\u672C\u9875\u6700\u8FD1\u6D4B\u8BD5\u8BB0\u5F55",
|
|
2402
3107
|
},
|
|
2403
3108
|
{
|
|
3109
|
+
icon: "latency",
|
|
3110
|
+
iconClass: "orange",
|
|
2404
3111
|
label: "\u5E73\u5747\u8017\u65F6",
|
|
2405
3112
|
value: requests.length ? (avg / 1000).toFixed(2) + " s" : "--",
|
|
2406
3113
|
detail: requests.length ? "\u7EDF\u8BA1\u6700\u8FD1 " + String(requests.length) + " \u6B21" : "\u7B49\u5F85\u8BF7\u6C42\u6837\u672C",
|
|
2407
3114
|
},
|
|
2408
3115
|
{
|
|
3116
|
+
icon: "service",
|
|
3117
|
+
iconClass: config.status.loggedIn ? "green" : "orange",
|
|
2409
3118
|
label: "\u670D\u52A1\u72B6\u6001",
|
|
2410
3119
|
value: config.status.loggedIn ? "\u8FD0\u884C\u4E2D" : "\u5F85\u767B\u5F55",
|
|
2411
3120
|
detail: config.status.loggedIn ? "\u7F51\u5173\u53EF\u8F6C\u53D1\u8BF7\u6C42" : "\u8BF7\u5148\u5B8C\u6210 OAuth \u767B\u5F55",
|
|
@@ -2414,14 +3123,63 @@ function renderAdminPage() {
|
|
|
2414
3123
|
];
|
|
2415
3124
|
}
|
|
2416
3125
|
|
|
3126
|
+
function getSummaryIcon(name) {
|
|
3127
|
+
if (name === "users") {
|
|
3128
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>';
|
|
3129
|
+
}
|
|
3130
|
+
if (name === "model") {
|
|
3131
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="4" y="4" width="16" height="16" rx="2"></rect><path d="M9 9h6v6H9z"></path><path d="M9 1v3"></path><path d="M15 1v3"></path><path d="M9 20v3"></path><path d="M15 20v3"></path><path d="M20 9h3"></path><path d="M20 15h3"></path><path d="M1 9h3"></path><path d="M1 15h3"></path></svg>';
|
|
3132
|
+
}
|
|
3133
|
+
if (name === "version") {
|
|
3134
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6 9 17l-5-5"></path></svg>';
|
|
3135
|
+
}
|
|
3136
|
+
if (name === "requests") {
|
|
3137
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12h18"></path><path d="m15 6 6 6-6 6"></path></svg>';
|
|
3138
|
+
}
|
|
3139
|
+
if (name === "latency") {
|
|
3140
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 6v6l4 2"></path><circle cx="12" cy="12" r="9"></circle></svg>';
|
|
3141
|
+
}
|
|
3142
|
+
if (name === "service") {
|
|
3143
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3 4 7v6c0 5 3.4 7.7 8 8 4.6-.3 8-3 8-8V7l-8-4Z"></path><path d="m9 12 2 2 4-4"></path></svg>';
|
|
3144
|
+
}
|
|
3145
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"></circle></svg>';
|
|
3146
|
+
}
|
|
3147
|
+
|
|
2417
3148
|
function renderOverview(config) {
|
|
2418
3149
|
const container = document.getElementById("summaryGrid");
|
|
2419
3150
|
const cards = getOverviewCards(config);
|
|
2420
3151
|
container.innerHTML = cards.map(function (card) {
|
|
3152
|
+
if (card.kind === "account-status") {
|
|
3153
|
+
return ""
|
|
3154
|
+
+ '<article class="summary-card account-status-summary">'
|
|
3155
|
+
+ '<div class="summary-card-head">'
|
|
3156
|
+
+ '<span class="summary-icon green">'
|
|
3157
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 17 10 11 4 5"></path><path d="M12 19h8"></path></svg>'
|
|
3158
|
+
+ "</span>"
|
|
3159
|
+
+ "<label>" + escapeHtml(card.label) + "</label>"
|
|
3160
|
+
+ "</div>"
|
|
3161
|
+
+ '<div class="account-status-list">'
|
|
3162
|
+
+ '<div class="account-status-line gateway">'
|
|
3163
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"></circle><path d="M3 12h18"></path><path d="M12 3c2.5 2.7 3.8 5.7 3.8 9S14.5 18.3 12 21"></path><path d="M12 3c-2.5 2.7-3.8 5.7-3.8 9s1.3 6.3 3.8 9"></path></svg>'
|
|
3164
|
+
+ "<span>\u7F51\u5173\uFF1A</span>"
|
|
3165
|
+
+ "<strong>" + escapeHtml(card.gatewayLabel) + "</strong>"
|
|
3166
|
+
+ "</div>"
|
|
3167
|
+
+ '<div class="account-status-line codex">'
|
|
3168
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 17 10 11 4 5"></path><path d="M12 19h8"></path></svg>'
|
|
3169
|
+
+ "<span>Codex\uFF1A</span>"
|
|
3170
|
+
+ "<strong>" + escapeHtml(card.codexLabel) + "</strong>"
|
|
3171
|
+
+ "</div>"
|
|
3172
|
+
+ "</div>"
|
|
3173
|
+
+ "</article>";
|
|
3174
|
+
}
|
|
2421
3175
|
const valueClass = card.compact ? "summary-value-sm" : "";
|
|
3176
|
+
const iconClass = card.iconClass ? " " + card.iconClass : "";
|
|
2422
3177
|
return ""
|
|
2423
3178
|
+ '<article class="summary-card">'
|
|
2424
|
-
+
|
|
3179
|
+
+ '<div class="summary-card-head">'
|
|
3180
|
+
+ '<span class="summary-icon' + iconClass + '">' + getSummaryIcon(card.icon) + "</span>"
|
|
3181
|
+
+ "<label>" + escapeHtml(card.label) + "</label>"
|
|
3182
|
+
+ "</div>"
|
|
2425
3183
|
+ '<strong class="' + valueClass + '">' + escapeHtml(card.value) + "</strong>"
|
|
2426
3184
|
+ "<span>" + escapeHtml(card.detail) + "</span>"
|
|
2427
3185
|
+ "</article>";
|
|
@@ -2433,6 +3191,7 @@ function renderAdminPage() {
|
|
|
2433
3191
|
const search = state.filters.search.trim().toLowerCase();
|
|
2434
3192
|
const status = state.filters.status;
|
|
2435
3193
|
const sort = state.filters.sort;
|
|
3194
|
+
const codexAccountId = config.codex && config.codex.accountId ? config.codex.accountId : "";
|
|
2436
3195
|
|
|
2437
3196
|
const filtered = profiles.filter(function (profile) {
|
|
2438
3197
|
const label = getProfileDisplayLabel(profile).toLowerCase();
|
|
@@ -2447,7 +3206,8 @@ function renderAdminPage() {
|
|
|
2447
3206
|
}
|
|
2448
3207
|
|
|
2449
3208
|
const health = getProfileHealth(profile);
|
|
2450
|
-
|
|
3209
|
+
const isCodexActive = Boolean(codexAccountId && profile.accountId === codexAccountId);
|
|
3210
|
+
if (status === "active" && !profile.isActive && !isCodexActive) {
|
|
2451
3211
|
return false;
|
|
2452
3212
|
}
|
|
2453
3213
|
if (status === "healthy" && health.key !== "healthy") {
|
|
@@ -2456,6 +3216,9 @@ function renderAdminPage() {
|
|
|
2456
3216
|
if (status === "warning" && health.key !== "warning") {
|
|
2457
3217
|
return false;
|
|
2458
3218
|
}
|
|
3219
|
+
if (status === "invalid" && health.key !== "invalid") {
|
|
3220
|
+
return false;
|
|
3221
|
+
}
|
|
2459
3222
|
if (status === "expired" && health.key !== "expired") {
|
|
2460
3223
|
return false;
|
|
2461
3224
|
}
|
|
@@ -2463,6 +3226,24 @@ function renderAdminPage() {
|
|
|
2463
3226
|
});
|
|
2464
3227
|
|
|
2465
3228
|
filtered.sort(function (a, b) {
|
|
3229
|
+
const aCodexActive = Boolean(codexAccountId && a.accountId === codexAccountId);
|
|
3230
|
+
const bCodexActive = Boolean(codexAccountId && b.accountId === codexAccountId);
|
|
3231
|
+
const activeDiff = Number(b.isActive || bCodexActive) - Number(a.isActive || aCodexActive);
|
|
3232
|
+
if (activeDiff !== 0) {
|
|
3233
|
+
return activeDiff;
|
|
3234
|
+
}
|
|
3235
|
+
const gatewayDiff = Number(b.isActive) - Number(a.isActive);
|
|
3236
|
+
if (gatewayDiff !== 0) {
|
|
3237
|
+
return gatewayDiff;
|
|
3238
|
+
}
|
|
3239
|
+
const codexDiff = Number(bCodexActive) - Number(aCodexActive);
|
|
3240
|
+
if (codexDiff !== 0) {
|
|
3241
|
+
return codexDiff;
|
|
3242
|
+
}
|
|
3243
|
+
const planDiff = getPlanRank(b) - getPlanRank(a);
|
|
3244
|
+
if (planDiff !== 0) {
|
|
3245
|
+
return planDiff;
|
|
3246
|
+
}
|
|
2466
3247
|
if (sort === "latency-asc") {
|
|
2467
3248
|
const aCapturedAt = getQuotaSnapshotTime(a) || 0;
|
|
2468
3249
|
const bCapturedAt = getQuotaSnapshotTime(b) || 0;
|
|
@@ -2499,6 +3280,11 @@ function renderAdminPage() {
|
|
|
2499
3280
|
delete state.selectedProfileIds[profileId];
|
|
2500
3281
|
}
|
|
2501
3282
|
});
|
|
3283
|
+
Object.keys(state.expandedProfileIds).forEach(function (profileId) {
|
|
3284
|
+
if (!availableIds[profileId]) {
|
|
3285
|
+
delete state.expandedProfileIds[profileId];
|
|
3286
|
+
}
|
|
3287
|
+
});
|
|
2502
3288
|
}
|
|
2503
3289
|
|
|
2504
3290
|
function updateSelectedProfileControls() {
|
|
@@ -2512,6 +3298,7 @@ function renderAdminPage() {
|
|
|
2512
3298
|
syncSelectedProfiles(config);
|
|
2513
3299
|
updateSelectedProfileControls();
|
|
2514
3300
|
const profiles = getFilteredProfiles(config);
|
|
3301
|
+
const codexAccountId = config.codex && config.codex.accountId ? config.codex.accountId : "";
|
|
2515
3302
|
const gridClass = profiles.length <= 0
|
|
2516
3303
|
? ""
|
|
2517
3304
|
: profiles.length === 1
|
|
@@ -2530,22 +3317,29 @@ function renderAdminPage() {
|
|
|
2530
3317
|
|
|
2531
3318
|
container.innerHTML = profiles.map(function (profile) {
|
|
2532
3319
|
const selected = !!state.selectedProfileIds[profile.profileId];
|
|
2533
|
-
const
|
|
3320
|
+
const expanded = !!state.expandedProfileIds[profile.profileId];
|
|
2534
3321
|
const health = getProfileHealth(profile);
|
|
2535
3322
|
const planType = getPlanType(profile);
|
|
3323
|
+
const planKey = getPlanKey(profile);
|
|
2536
3324
|
const imageCapability = getImageCapability(profile);
|
|
2537
3325
|
const primary = getPrimaryUsage(profile);
|
|
2538
3326
|
const secondary = getSecondaryUsage(profile);
|
|
2539
3327
|
const primaryClass = health.barClass || "blue";
|
|
2540
3328
|
const secondaryClass = secondary >= 85 ? "orange" : "blue";
|
|
3329
|
+
const isCodexActive = Boolean(codexAccountId && profile.accountId === codexAccountId);
|
|
3330
|
+
const usageCorner = getUsageCorner(profile, isCodexActive);
|
|
3331
|
+
const apiUsageClass = profile.isActive ? " is-active" : "";
|
|
3332
|
+
const codexUsageClass = isCodexActive ? " is-active" : "";
|
|
2541
3333
|
const actionButton = profile.isActive
|
|
2542
|
-
?
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
3334
|
+
? '<button class="btn-secondary is-current" type="button" disabled>\u7F51\u5173\u4F7F\u7528\u4E2D</button>'
|
|
3335
|
+
: '<button class="btn-secondary" type="button" data-profile-action="activate" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5E94\u7528\u7F51\u5173</button>';
|
|
3336
|
+
const codexButton = isCodexActive
|
|
3337
|
+
? '<button class="btn-secondary is-current codex" type="button" disabled>Codex \u4F7F\u7528\u4E2D</button>'
|
|
3338
|
+
: '<button class="btn-secondary" type="button" data-profile-action="apply-codex" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5E94\u7528 Codex</button>';
|
|
2546
3339
|
|
|
2547
3340
|
return ""
|
|
2548
|
-
+ '<article class="account-card" data-profile-card="' + escapeHtml(profile.profileId) + '">'
|
|
3341
|
+
+ '<article class="account-card plan-' + escapeHtml(planKey) + '" data-profile-card="' + escapeHtml(profile.profileId) + '">'
|
|
3342
|
+
+ (usageCorner ? '<span class="usage-corner ' + escapeHtml(usageCorner.className) + '"><span>' + escapeHtml(usageCorner.label) + "</span></span>" : "")
|
|
2549
3343
|
+ '<div class="account-head">'
|
|
2550
3344
|
+ '<div class="account-title">'
|
|
2551
3345
|
+ '<div class="account-name">'
|
|
@@ -2553,7 +3347,6 @@ function renderAdminPage() {
|
|
|
2553
3347
|
+ "<strong>" + escapeHtml(getProfileDisplayLabel(profile)) + "</strong>"
|
|
2554
3348
|
+ "</div>"
|
|
2555
3349
|
+ '<div class="badge-row">'
|
|
2556
|
-
+ (profile.isActive ? '<span class="badge blue">\u5F53\u524D\u4F7F\u7528</span>' : "")
|
|
2557
3350
|
+ '<span class="badge brand">' + escapeHtml(planType) + "</span>"
|
|
2558
3351
|
+ '<span class="badge ' + escapeHtml(health.badgeClass) + '">' + escapeHtml(health.label) + "</span>"
|
|
2559
3352
|
+ '<span class="badge ' + escapeHtml(imageCapability.badgeClass) + '">' + escapeHtml(imageCapability.label) + "</span>"
|
|
@@ -2571,18 +3364,47 @@ function renderAdminPage() {
|
|
|
2571
3364
|
+ '<div class="progress-track"><div class="progress-bar ' + escapeHtml(secondaryClass) + '" style="width:' + escapeHtml(String(secondary)) + '%"></div></div>'
|
|
2572
3365
|
+ "</div>"
|
|
2573
3366
|
+ "</div>"
|
|
2574
|
-
+ '<div class="
|
|
2575
|
-
+ '<
|
|
2576
|
-
+
|
|
2577
|
-
+
|
|
2578
|
-
+
|
|
2579
|
-
+
|
|
2580
|
-
+
|
|
2581
|
-
+ '<
|
|
3367
|
+
+ '<div class="usage-status-row">'
|
|
3368
|
+
+ '<span class="usage-status' + apiUsageClass + '">'
|
|
3369
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"></circle><path d="M3 12h18"></path><path d="M12 3c2.5 2.7 3.8 5.7 3.8 9S14.5 18.3 12 21"></path><path d="M12 3c-2.5 2.7-3.8 5.7-3.8 9s1.3 6.3 3.8 9"></path></svg>'
|
|
3370
|
+
+ "<span>API</span>"
|
|
3371
|
+
+ '<span class="usage-dot' + (profile.isActive ? " active" : "") + '"></span>'
|
|
3372
|
+
+ '<span class="usage-state-text">' + (profile.isActive ? "\u4F7F\u7528\u4E2D" : "\u672A\u4F7F\u7528") + "</span>"
|
|
3373
|
+
+ "</span>"
|
|
3374
|
+
+ '<span class="usage-status' + codexUsageClass + '">'
|
|
3375
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 17 10 11 4 5"></path><path d="M12 19h8"></path></svg>'
|
|
3376
|
+
+ "<span>Codex</span>"
|
|
3377
|
+
+ '<span class="usage-dot' + (isCodexActive ? " active" : "") + '"></span>'
|
|
3378
|
+
+ '<span class="usage-state-text">' + (isCodexActive ? "\u4F7F\u7528\u4E2D" : "\u672A\u4F7F\u7528") + "</span>"
|
|
3379
|
+
+ "</span>"
|
|
3380
|
+
+ "</div>"
|
|
3381
|
+
+ '<div class="compact-meta-row">'
|
|
3382
|
+
+ '<div class="compact-reset-list">'
|
|
3383
|
+
+ '<div class="compact-meta-item"><label>' + escapeHtml(getResetLabel(profile, "primary")) + '</label><strong>' + escapeHtml(describeCompactReset(profile, "primary")) + "</strong></div>"
|
|
3384
|
+
+ '<div class="compact-meta-item"><label>' + escapeHtml(getResetLabel(profile, "secondary")) + '</label><strong>' + escapeHtml(describeCompactReset(profile, "secondary")) + "</strong></div>"
|
|
3385
|
+
+ "</div>"
|
|
3386
|
+
+ '<div class="compact-meta-actions">'
|
|
3387
|
+
+ '<button class="details-toggle' + (expanded ? " is-expanded" : "") + '" type="button" data-profile-action="toggle-details" data-profile-id="' + escapeHtml(profile.profileId) + '">'
|
|
3388
|
+
+ "<span>" + (expanded ? "\u6536\u8D77\u8BE6\u60C5" : "\u67E5\u770B\u8BE6\u60C5") + "</span>"
|
|
3389
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"></path></svg>'
|
|
3390
|
+
+ "</button>"
|
|
3391
|
+
+ "</div>"
|
|
2582
3392
|
+ "</div>"
|
|
3393
|
+
+ (expanded
|
|
3394
|
+
? '<div class="meta-grid">'
|
|
3395
|
+
+ '<div class="meta-item"><label>\u5957\u9910</label><strong>' + escapeHtml(planType) + "</strong></div>"
|
|
3396
|
+
+ '<div class="meta-item"><label>\u751F\u56FE\u80FD\u529B</label><strong>' + escapeHtml(imageCapability.detail) + "</strong></div>"
|
|
3397
|
+
+ '<div class="meta-item"><label>\u8BA4\u8BC1\u72B6\u6001</label><strong>' + escapeHtml(describeAuthStatus(profile)) + "</strong></div>"
|
|
3398
|
+
+ '<div class="meta-item"><label>\u989D\u5EA6\u5FEB\u7167</label><strong>' + escapeHtml(describeQuotaSnapshot(profile)) + "</strong></div>"
|
|
3399
|
+
+ '<div class="meta-item"><label>\u989D\u5EA6\u9650\u5236</label><strong>' + escapeHtml(describeQuotaLimit(profile)) + "</strong></div>"
|
|
3400
|
+
+ '<div class="meta-item"><label>Account ID</label><code>' + escapeHtml(state.showEmails ? (profile.accountId || "\u672A\u63D0\u4F9B") : maskIdentifier(profile.accountId || "\u672A\u63D0\u4F9B")) + "</code></div>"
|
|
3401
|
+
+ '<div class="meta-item"><label>\u8FC7\u671F\u65F6\u95F4</label><span>' + escapeHtml(formatTime(profile.expiresAt)) + "</span></div>"
|
|
3402
|
+
+ "</div>"
|
|
3403
|
+
: "")
|
|
2583
3404
|
+ '<div class="account-actions">'
|
|
2584
3405
|
+ actionButton
|
|
2585
|
-
+
|
|
3406
|
+
+ codexButton
|
|
3407
|
+
+ '<button class="btn-secondary" type="button" data-profile-action="sync-quota" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5237\u65B0\u989D\u5EA6</button>'
|
|
2586
3408
|
+ '<button class="btn-secondary" type="button" data-profile-action="export" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5BFC\u51FA</button>'
|
|
2587
3409
|
+ '<button class="btn-danger" type="button" data-profile-action="remove" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5220\u9664</button>'
|
|
2588
3410
|
+ "</div>"
|
|
@@ -2747,6 +3569,7 @@ function renderAdminPage() {
|
|
|
2747
3569
|
["Provider", config.status.activeProvider || "openai-codex"],
|
|
2748
3570
|
["\u9ED8\u8BA4\u6A21\u578B", config.settings.defaultModel],
|
|
2749
3571
|
["\u4E0A\u6E38\u4EE3\u7406", config.settings.networkProxy && config.settings.networkProxy.enabled ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528"],
|
|
3572
|
+
["\u81EA\u52A8\u5207\u6362", config.settings.autoSwitch && config.settings.autoSwitch.enabled ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528"],
|
|
2750
3573
|
["\u5F53\u524D\u7248\u672C", getVersionValue(config)],
|
|
2751
3574
|
["\u5F53\u524D\u5957\u9910", config.profile ? getPlanType(config.profile) : "\u672A\u767B\u5F55"],
|
|
2752
3575
|
["\u751F\u56FE\u80FD\u529B", getImageCapability(config.profile).detail],
|
|
@@ -2766,6 +3589,7 @@ function renderAdminPage() {
|
|
|
2766
3589
|
["\u5F53\u524D\u8D26\u53F7", getProfileDisplayLabel(config.profile)],
|
|
2767
3590
|
["\u9ED8\u8BA4\u6A21\u578B", config.settings.defaultModel],
|
|
2768
3591
|
["\u4E0A\u6E38\u4EE3\u7406", config.settings.networkProxy && config.settings.networkProxy.enabled ? config.settings.networkProxy.url : "\u672A\u542F\u7528"],
|
|
3592
|
+
["\u81EA\u52A8\u5207\u6362", config.settings.autoSwitch && config.settings.autoSwitch.enabled ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528"],
|
|
2769
3593
|
["\u7248\u672C\u72B6\u6001", getVersionDetail(config)],
|
|
2770
3594
|
["\u5F53\u524D\u5957\u9910", config.profile ? getPlanType(config.profile) : "\u672A\u767B\u5F55"],
|
|
2771
3595
|
["\u751F\u56FE\u80FD\u529B", getImageCapability(config.profile).detail],
|
|
@@ -2832,6 +3656,47 @@ function renderAdminPage() {
|
|
|
2832
3656
|
proxyNoProxy.value = proxy.noProxy || "localhost,127.0.0.1,::1";
|
|
2833
3657
|
}
|
|
2834
3658
|
|
|
3659
|
+
function renderAutoSwitchSettings(config) {
|
|
3660
|
+
const autoSwitch = config.settings.autoSwitch || {
|
|
3661
|
+
enabled: false,
|
|
3662
|
+
};
|
|
3663
|
+
autoSwitchEnabled.checked = !!autoSwitch.enabled;
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
function isSettingsDrawerOpen() {
|
|
3667
|
+
return settingsDrawerBackdrop.classList.contains("is-open");
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
function renderSettingsFields(config, options) {
|
|
3671
|
+
if (!config) {
|
|
3672
|
+
return;
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3675
|
+
if (!(options && options.force) && state.settingsDirty && isSettingsDrawerOpen()) {
|
|
3676
|
+
return;
|
|
3677
|
+
}
|
|
3678
|
+
|
|
3679
|
+
renderModelOptions(config);
|
|
3680
|
+
renderModelCatalogStatus(config);
|
|
3681
|
+
renderProxySettings(config);
|
|
3682
|
+
renderAutoSwitchSettings(config);
|
|
3683
|
+
state.settingsDirty = false;
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
function markSettingsDirty() {
|
|
3687
|
+
state.settingsDirty = true;
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3690
|
+
function resetSettingsDraft() {
|
|
3691
|
+
state.settingsDirty = false;
|
|
3692
|
+
if (state.config) {
|
|
3693
|
+
renderSettingsFields(state.config, {
|
|
3694
|
+
force: true,
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
settingsStatus.textContent = "";
|
|
3698
|
+
}
|
|
3699
|
+
|
|
2835
3700
|
function syncHero(config) {
|
|
2836
3701
|
const profileText = config.profile
|
|
2837
3702
|
? "\u5F53\u524D\u8D26\u53F7\u4E3A " + getProfileDisplayLabel(config.profile) + "\uFF0C\u5957\u9910 " + getPlanType(config.profile) + "\uFF0C\u53EF\u5728\u53F3\u4FA7\u5B8C\u6210\u6A21\u578B\u5207\u6362\u548C\u63A5\u53E3\u8C03\u8BD5\u3002"
|
|
@@ -2866,9 +3731,7 @@ function renderAdminPage() {
|
|
|
2866
3731
|
syncHero(config);
|
|
2867
3732
|
renderOverview(config);
|
|
2868
3733
|
renderProfiles(config);
|
|
2869
|
-
|
|
2870
|
-
renderModelCatalogStatus(config);
|
|
2871
|
-
renderProxySettings(config);
|
|
3734
|
+
renderSettingsFields(config);
|
|
2872
3735
|
renderUpdatePanel(config);
|
|
2873
3736
|
renderEndpoints(config);
|
|
2874
3737
|
renderServiceInfo(config);
|
|
@@ -2926,6 +3789,8 @@ function renderAdminPage() {
|
|
|
2926
3789
|
const silent = !!(options && options.silent);
|
|
2927
3790
|
const url = syncRuntime ? "/_gateway/admin/runtime-refresh" : "/_gateway/admin/config";
|
|
2928
3791
|
const requestOptions = syncRuntime ? { method: "POST" } : undefined;
|
|
3792
|
+
const previousProfileId = state.config && state.config.profile ? state.config.profile.profileId : "";
|
|
3793
|
+
const previousStatus = authStatus.textContent;
|
|
2929
3794
|
|
|
2930
3795
|
if (!silent) {
|
|
2931
3796
|
testerMeta.textContent = syncRuntime ? "\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001" : "\u5237\u65B0\u7BA1\u7406\u72B6\u6001";
|
|
@@ -2933,9 +3798,14 @@ function renderAdminPage() {
|
|
|
2933
3798
|
|
|
2934
3799
|
const config = await fetchJson(url, requestOptions);
|
|
2935
3800
|
renderConfig(config);
|
|
3801
|
+
const nextProfileId = config && config.profile ? config.profile.profileId : "";
|
|
2936
3802
|
|
|
2937
3803
|
if (!silent) {
|
|
2938
3804
|
testerMeta.textContent = "\u51C6\u5907\u5C31\u7EEA";
|
|
3805
|
+
} else if (previousProfileId && nextProfileId && previousProfileId !== nextProfileId) {
|
|
3806
|
+
authStatus.textContent = "\u68C0\u6D4B\u5230\u989D\u5EA6\u8017\u5C3D\uFF0C\u7F51\u5173\u5DF2\u81EA\u52A8\u5207\u6362\u5230: " + getProfileDisplayLabel(config.profile);
|
|
3807
|
+
} else {
|
|
3808
|
+
authStatus.textContent = previousStatus;
|
|
2939
3809
|
}
|
|
2940
3810
|
|
|
2941
3811
|
return config;
|
|
@@ -2956,6 +3826,20 @@ function renderAdminPage() {
|
|
|
2956
3826
|
}, RUNTIME_AUTO_REFRESH_MS);
|
|
2957
3827
|
}
|
|
2958
3828
|
|
|
3829
|
+
function scheduleActiveProfileRefresh() {
|
|
3830
|
+
window.setInterval(function () {
|
|
3831
|
+
if (document.hidden || !state.config || !state.config.settings || !state.config.settings.autoSwitch || !state.config.settings.autoSwitch.enabled) {
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
refreshConfig({
|
|
3836
|
+
silent: true,
|
|
3837
|
+
}).catch(function (error) {
|
|
3838
|
+
console.warn("[admin] active profile refresh failed", error && error.message ? error.message : String(error));
|
|
3839
|
+
});
|
|
3840
|
+
}, ACTIVE_PROFILE_REFRESH_MS);
|
|
3841
|
+
}
|
|
3842
|
+
|
|
2959
3843
|
async function syncQuotaAfterProfileChange(config, sourceLabel) {
|
|
2960
3844
|
if (!config || !config.profile || config.profile.quota) {
|
|
2961
3845
|
return config;
|
|
@@ -3018,6 +3902,10 @@ function renderAdminPage() {
|
|
|
3018
3902
|
}
|
|
3019
3903
|
|
|
3020
3904
|
async function runProfileAction(action, profileId, button) {
|
|
3905
|
+
if (!confirmQuotaSwitch(action, profileId)) {
|
|
3906
|
+
return;
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3021
3909
|
if (action === "export") {
|
|
3022
3910
|
await exportProfile(profileId, button);
|
|
3023
3911
|
return;
|
|
@@ -3026,6 +3914,28 @@ function renderAdminPage() {
|
|
|
3026
3914
|
await applyProfileToCodex(profileId, button);
|
|
3027
3915
|
return;
|
|
3028
3916
|
}
|
|
3917
|
+
if (action === "sync-quota") {
|
|
3918
|
+
setBusy(button, true);
|
|
3919
|
+
authStatus.textContent = "\u6B63\u5728\u5237\u65B0\u8D26\u53F7\u989D\u5EA6...";
|
|
3920
|
+
try {
|
|
3921
|
+
const config = await fetchJson("/_gateway/admin/profiles/sync-quota", {
|
|
3922
|
+
method: "POST",
|
|
3923
|
+
headers: {
|
|
3924
|
+
"Content-Type": "application/json",
|
|
3925
|
+
},
|
|
3926
|
+
body: formatJson({
|
|
3927
|
+
profileId: profileId,
|
|
3928
|
+
}),
|
|
3929
|
+
});
|
|
3930
|
+
renderConfig(config);
|
|
3931
|
+
authStatus.textContent = "\u989D\u5EA6\u4FE1\u606F\u5DF2\u540C\u6B65\u3002";
|
|
3932
|
+
} catch (error) {
|
|
3933
|
+
authStatus.textContent = error.message;
|
|
3934
|
+
} finally {
|
|
3935
|
+
setBusy(button, false);
|
|
3936
|
+
}
|
|
3937
|
+
return;
|
|
3938
|
+
}
|
|
3029
3939
|
|
|
3030
3940
|
setBusy(button, true);
|
|
3031
3941
|
authStatus.textContent = action === "activate" ? "\u6B63\u5728\u5207\u6362\u5F53\u524D\u8D26\u53F7..." : "\u6B63\u5728\u5220\u9664\u8D26\u53F7...";
|
|
@@ -3075,7 +3985,7 @@ function renderAdminPage() {
|
|
|
3075
3985
|
const config = result.config || await fetchJson("/_gateway/admin/config");
|
|
3076
3986
|
renderConfig(config);
|
|
3077
3987
|
const codex = result.codex || config.codex || {};
|
|
3078
|
-
authStatus.textContent = "\u5DF2\u5E94\u7528\u5230 Codex\u3002\
|
|
3988
|
+
authStatus.textContent = "\u5DF2\u5E94\u7528\u5230 Codex\u3002\u8BF7\u5173\u95ED Codex \u5E94\u7528\u5E76\u91CD\u65B0\u6253\u5F00\u540E\u751F\u6548\u3002"
|
|
3079
3989
|
+ (codex.backupPath ? " \u5DF2\u5907\u4EFD\u539F auth.json\u3002" : "");
|
|
3080
3990
|
} catch (error) {
|
|
3081
3991
|
authStatus.textContent = error.message;
|
|
@@ -3194,11 +4104,15 @@ function renderAdminPage() {
|
|
|
3194
4104
|
});
|
|
3195
4105
|
}
|
|
3196
4106
|
|
|
3197
|
-
async function
|
|
3198
|
-
const button = document.getElementById("saveModelBtn");
|
|
4107
|
+
async function saveSettings() {
|
|
3199
4108
|
const select = document.getElementById("defaultModel");
|
|
3200
|
-
|
|
3201
|
-
|
|
4109
|
+
const savedProxy = state.config && state.config.settings && state.config.settings.networkProxy
|
|
4110
|
+
? state.config.settings.networkProxy
|
|
4111
|
+
: { url: "", noProxy: "localhost,127.0.0.1,::1" };
|
|
4112
|
+
const nextProxyUrl = proxyUrl.value.trim() || (!proxyEnabled.checked ? savedProxy.url || "" : "");
|
|
4113
|
+
setBusy(saveSettingsBtn, true);
|
|
4114
|
+
settingsStatus.textContent = "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E...";
|
|
4115
|
+
authStatus.textContent = "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E...";
|
|
3202
4116
|
try {
|
|
3203
4117
|
const config = await fetchJson("/_gateway/admin/settings", {
|
|
3204
4118
|
method: "PUT",
|
|
@@ -3207,24 +4121,36 @@ function renderAdminPage() {
|
|
|
3207
4121
|
},
|
|
3208
4122
|
body: formatJson({
|
|
3209
4123
|
defaultModel: select.value,
|
|
4124
|
+
networkProxy: {
|
|
4125
|
+
enabled: proxyEnabled.checked,
|
|
4126
|
+
url: nextProxyUrl,
|
|
4127
|
+
noProxy: proxyNoProxy.value,
|
|
4128
|
+
},
|
|
4129
|
+
autoSwitch: {
|
|
4130
|
+
enabled: autoSwitchEnabled.checked,
|
|
4131
|
+
},
|
|
3210
4132
|
}),
|
|
3211
4133
|
});
|
|
4134
|
+
state.settingsDirty = false;
|
|
3212
4135
|
renderConfig(config);
|
|
3213
|
-
|
|
4136
|
+
settingsStatus.textContent = "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002";
|
|
4137
|
+
authStatus.textContent = "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002";
|
|
3214
4138
|
} catch (error) {
|
|
3215
|
-
|
|
4139
|
+
const message = error && error.message ? error.message : String(error);
|
|
4140
|
+
settingsStatus.textContent = message;
|
|
4141
|
+
authStatus.textContent = message;
|
|
3216
4142
|
} finally {
|
|
3217
|
-
setBusy(
|
|
4143
|
+
setBusy(saveSettingsBtn, false);
|
|
3218
4144
|
}
|
|
3219
4145
|
}
|
|
3220
4146
|
|
|
3221
|
-
async function
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
authStatus.textContent = "\u6B63\u5728\
|
|
4147
|
+
async function testProxy() {
|
|
4148
|
+
setBusy(testProxyBtn, true);
|
|
4149
|
+
settingsStatus.textContent = "\u6B63\u5728\u6D4B\u8BD5\u4EE3\u7406\u8FDE\u63A5...";
|
|
4150
|
+
authStatus.textContent = "\u6B63\u5728\u6D4B\u8BD5\u4EE3\u7406\u8FDE\u63A5...";
|
|
3225
4151
|
try {
|
|
3226
|
-
const
|
|
3227
|
-
method: "
|
|
4152
|
+
const result = await fetchJson("/_gateway/admin/settings/proxy-test", {
|
|
4153
|
+
method: "POST",
|
|
3228
4154
|
headers: {
|
|
3229
4155
|
"Content-Type": "application/json",
|
|
3230
4156
|
},
|
|
@@ -3236,18 +4162,23 @@ function renderAdminPage() {
|
|
|
3236
4162
|
},
|
|
3237
4163
|
}),
|
|
3238
4164
|
});
|
|
3239
|
-
|
|
3240
|
-
|
|
4165
|
+
const message = "\u4EE3\u7406\u6D4B\u8BD5\u901A\u8FC7: HTTP " + String(result.status)
|
|
4166
|
+
+ "\uFF0C\u8017\u65F6 " + String(result.elapsedMs) + " ms\u3002";
|
|
4167
|
+
settingsStatus.textContent = message;
|
|
4168
|
+
authStatus.textContent = message;
|
|
3241
4169
|
} catch (error) {
|
|
3242
|
-
|
|
4170
|
+
const message = "\u4EE3\u7406\u6D4B\u8BD5\u5931\u8D25: " + (error && error.message ? error.message : String(error));
|
|
4171
|
+
settingsStatus.textContent = message;
|
|
4172
|
+
authStatus.textContent = message;
|
|
3243
4173
|
} finally {
|
|
3244
|
-
setBusy(
|
|
4174
|
+
setBusy(testProxyBtn, false);
|
|
3245
4175
|
}
|
|
3246
4176
|
}
|
|
3247
4177
|
|
|
3248
4178
|
async function refreshModels() {
|
|
3249
4179
|
const button = document.getElementById("refreshModelsBtn");
|
|
3250
4180
|
setBusy(button, true);
|
|
4181
|
+
settingsStatus.textContent = "\u6B63\u5728\u540C\u6B65 Codex \u6A21\u578B\u5217\u8868...";
|
|
3251
4182
|
authStatus.textContent = "\u6B63\u5728\u540C\u6B65 Codex \u6A21\u578B\u5217\u8868...";
|
|
3252
4183
|
try {
|
|
3253
4184
|
await fetchJson("/_gateway/models/refresh", {
|
|
@@ -3255,9 +4186,12 @@ function renderAdminPage() {
|
|
|
3255
4186
|
});
|
|
3256
4187
|
const config = await fetchJson("/_gateway/admin/config");
|
|
3257
4188
|
renderConfig(config);
|
|
4189
|
+
settingsStatus.textContent = "Codex \u6A21\u578B\u5217\u8868\u5DF2\u540C\u6B65\u3002";
|
|
3258
4190
|
authStatus.textContent = "Codex \u6A21\u578B\u5217\u8868\u5DF2\u540C\u6B65\u3002";
|
|
3259
4191
|
} catch (error) {
|
|
3260
|
-
|
|
4192
|
+
const message = error && error.message ? error.message : String(error);
|
|
4193
|
+
settingsStatus.textContent = message;
|
|
4194
|
+
authStatus.textContent = message;
|
|
3261
4195
|
} finally {
|
|
3262
4196
|
setBusy(button, false);
|
|
3263
4197
|
}
|
|
@@ -3278,6 +4212,7 @@ function renderAdminPage() {
|
|
|
3278
4212
|
const meta = endpointMeta[endpoint];
|
|
3279
4213
|
const button = document.getElementById("runTestBtn");
|
|
3280
4214
|
const tracker = createTimingTracker();
|
|
4215
|
+
const initialProfileId = state.config && state.config.profile ? state.config.profile.profileId : "";
|
|
3281
4216
|
setBusy(button, true);
|
|
3282
4217
|
setTesterResultTab("response");
|
|
3283
4218
|
testerMeta.textContent = "\u8BF7\u6C42\u4E2D: " + meta.method + " " + endpoint;
|
|
@@ -3359,6 +4294,13 @@ function renderAdminPage() {
|
|
|
3359
4294
|
testerMeta.textContent = "\u8BF7\u6C42\u5931\u8D25";
|
|
3360
4295
|
clearPreview();
|
|
3361
4296
|
} finally {
|
|
4297
|
+
if (initialProfileId) {
|
|
4298
|
+
await refreshConfig({
|
|
4299
|
+
silent: true,
|
|
4300
|
+
}).catch(function (error) {
|
|
4301
|
+
console.warn("[admin] refresh after gateway request failed", error && error.message ? error.message : String(error));
|
|
4302
|
+
});
|
|
4303
|
+
}
|
|
3362
4304
|
setBusy(button, false);
|
|
3363
4305
|
}
|
|
3364
4306
|
}
|
|
@@ -3392,12 +4334,37 @@ function renderAdminPage() {
|
|
|
3392
4334
|
contactModal.setAttribute("aria-hidden", "true");
|
|
3393
4335
|
}
|
|
3394
4336
|
|
|
4337
|
+
function openSettingsDrawer() {
|
|
4338
|
+
if (state.config && !state.settingsDirty) {
|
|
4339
|
+
renderSettingsFields(state.config, {
|
|
4340
|
+
force: true,
|
|
4341
|
+
});
|
|
4342
|
+
}
|
|
4343
|
+
settingsDrawerBackdrop.classList.add("is-open");
|
|
4344
|
+
settingsDrawerBackdrop.setAttribute("aria-hidden", "false");
|
|
4345
|
+
}
|
|
4346
|
+
|
|
4347
|
+
function closeSettingsDrawer() {
|
|
4348
|
+
resetSettingsDraft();
|
|
4349
|
+
settingsDrawerBackdrop.classList.remove("is-open");
|
|
4350
|
+
settingsDrawerBackdrop.setAttribute("aria-hidden", "true");
|
|
4351
|
+
}
|
|
4352
|
+
|
|
3395
4353
|
document.getElementById("loginBtn").addEventListener("click", openAccountModal);
|
|
4354
|
+
document.getElementById("openSettingsBtn").addEventListener("click", openSettingsDrawer);
|
|
4355
|
+
document.querySelectorAll("[data-open-settings]").forEach(function (button) {
|
|
4356
|
+
button.addEventListener("click", openSettingsDrawer);
|
|
4357
|
+
});
|
|
3396
4358
|
document.getElementById("refreshBtn").addEventListener("click", function () {
|
|
3397
4359
|
authStatus.textContent = "\u6B63\u5728\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001...";
|
|
3398
4360
|
refreshConfig({
|
|
3399
4361
|
syncRuntime: true,
|
|
3400
|
-
}).then(function () {
|
|
4362
|
+
}).then(function (config) {
|
|
4363
|
+
if (config && config.quotaSync) {
|
|
4364
|
+
const sync = config.quotaSync;
|
|
4365
|
+
authStatus.textContent = "\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001\u5DF2\u5237\u65B0: " + String(sync.synced) + "/" + String(sync.total) + " \u4E2A\u8D26\u53F7\u6210\u529F" + (sync.failed ? "\uFF0C" + String(sync.failed) + " \u4E2A\u5931\u8D25" : "") + (sync.skipped ? "\uFF0C" + String(sync.skipped) + " \u4E2A\u767B\u5F55\u5931\u6548\u5DF2\u8DF3\u8FC7" : "") + "\u3002";
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
3401
4368
|
authStatus.textContent = "\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001\u5DF2\u5237\u65B0\u3002";
|
|
3402
4369
|
}).catch(function (error) {
|
|
3403
4370
|
authStatus.textContent = error && error.message ? error.message : String(error);
|
|
@@ -3412,9 +4379,14 @@ function renderAdminPage() {
|
|
|
3412
4379
|
contactBtn.addEventListener("click", openContactModal);
|
|
3413
4380
|
document.getElementById("closeContactBtn").addEventListener("click", closeContactModal);
|
|
3414
4381
|
document.getElementById("closeImagePreviewBtn").addEventListener("click", closeImagePreviewModal);
|
|
4382
|
+
document.getElementById("closeSettingsDrawerBtn").addEventListener("click", closeSettingsDrawer);
|
|
3415
4383
|
document.getElementById("refreshModelsBtn").addEventListener("click", refreshModels);
|
|
3416
|
-
|
|
3417
|
-
|
|
4384
|
+
testProxyBtn.addEventListener("click", testProxy);
|
|
4385
|
+
saveSettingsBtn.addEventListener("click", saveSettings);
|
|
4386
|
+
[document.getElementById("defaultModel"), proxyEnabled, proxyUrl, proxyNoProxy, autoSwitchEnabled].forEach(function (element) {
|
|
4387
|
+
element.addEventListener("input", markSettingsDirty);
|
|
4388
|
+
element.addEventListener("change", markSettingsDirty);
|
|
4389
|
+
});
|
|
3418
4390
|
runTestBtn.addEventListener("click", runTest);
|
|
3419
4391
|
document.querySelectorAll("[data-result-tab]").forEach(function (button) {
|
|
3420
4392
|
button.addEventListener("click", function () {
|
|
@@ -3445,6 +4417,18 @@ function renderAdminPage() {
|
|
|
3445
4417
|
return;
|
|
3446
4418
|
}
|
|
3447
4419
|
|
|
4420
|
+
if (action === "toggle-details") {
|
|
4421
|
+
if (state.expandedProfileIds[profileId]) {
|
|
4422
|
+
delete state.expandedProfileIds[profileId];
|
|
4423
|
+
} else {
|
|
4424
|
+
state.expandedProfileIds[profileId] = true;
|
|
4425
|
+
}
|
|
4426
|
+
if (state.config) {
|
|
4427
|
+
renderProfiles(state.config);
|
|
4428
|
+
}
|
|
4429
|
+
return;
|
|
4430
|
+
}
|
|
4431
|
+
|
|
3448
4432
|
runProfileAction(action, profileId, button);
|
|
3449
4433
|
});
|
|
3450
4434
|
|
|
@@ -3544,6 +4528,12 @@ function renderAdminPage() {
|
|
|
3544
4528
|
}
|
|
3545
4529
|
});
|
|
3546
4530
|
|
|
4531
|
+
settingsDrawerBackdrop.addEventListener("click", function (event) {
|
|
4532
|
+
if (event.target === settingsDrawerBackdrop) {
|
|
4533
|
+
closeSettingsDrawer();
|
|
4534
|
+
}
|
|
4535
|
+
});
|
|
4536
|
+
|
|
3547
4537
|
imagePreviewModal.addEventListener("click", function (event) {
|
|
3548
4538
|
if (event.target === imagePreviewModal) {
|
|
3549
4539
|
closeImagePreviewModal();
|
|
@@ -3560,10 +4550,14 @@ function renderAdminPage() {
|
|
|
3560
4550
|
if (event.key === "Escape" && accountModal.classList.contains("is-open")) {
|
|
3561
4551
|
closeAccountModal();
|
|
3562
4552
|
}
|
|
4553
|
+
if (event.key === "Escape" && settingsDrawerBackdrop.classList.contains("is-open")) {
|
|
4554
|
+
closeSettingsDrawer();
|
|
4555
|
+
}
|
|
3563
4556
|
});
|
|
3564
4557
|
|
|
3565
4558
|
setTesterResultTab(state.testerResultTab);
|
|
3566
4559
|
scheduleRuntimeRefresh();
|
|
4560
|
+
scheduleActiveProfileRefresh();
|
|
3567
4561
|
refreshConfig().catch(function (error) {
|
|
3568
4562
|
authStatus.textContent = error && error.message ? error.message : String(error);
|
|
3569
4563
|
testerMeta.textContent = "\u52A0\u8F7D\u5931\u8D25";
|