ai-zero-token 1.0.7 → 1.0.9
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/CHANGELOG.md +8 -0
- package/README.md +146 -395
- package/README.zh-CN.md +258 -0
- package/dist/cli/commands/serve.js +1 -0
- package/dist/core/providers/http-client.js +1 -1
- package/dist/core/services/auth-service.js +98 -7
- package/dist/core/services/config-service.js +15 -3
- package/dist/core/services/image-service.js +2 -7
- package/dist/core/services/version-service.js +18 -13
- package/dist/core/store/settings-store.js +6 -0
- package/dist/server/admin-page.js +1018 -103
- package/dist/server/app.js +68 -2
- package/dist/server/index.js +17 -2
- package/package.json +2 -1
|
@@ -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 {
|
|
@@ -812,6 +1105,145 @@ function renderAdminPage() {
|
|
|
812
1105
|
gap: 10px;
|
|
813
1106
|
}
|
|
814
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);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
815
1247
|
.quota-row {
|
|
816
1248
|
display: grid;
|
|
817
1249
|
gap: 6px;
|
|
@@ -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>
|
|
@@ -1428,7 +1899,7 @@ function renderAdminPage() {
|
|
|
1428
1899
|
<option value="healthy">\u5065\u5EB7</option>
|
|
1429
1900
|
<option value="warning">\u5373\u5C06\u8017\u5C3D</option>
|
|
1430
1901
|
<option value="expired">\u5DF2\u8FC7\u671F</option>
|
|
1431
|
-
<option value="active">\
|
|
1902
|
+
<option value="active">\u4F7F\u7528\u4E2D</option>
|
|
1432
1903
|
</select>
|
|
1433
1904
|
<select class="control" id="profileSort">
|
|
1434
1905
|
<option value="quota-desc">\u6309\u4E3B\u989D\u5EA6\u6392\u5E8F</option>
|
|
@@ -1508,32 +1979,6 @@ function renderAdminPage() {
|
|
|
1508
1979
|
<select class="control" id="endpointSelect"></select>
|
|
1509
1980
|
</div>
|
|
1510
1981
|
|
|
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
1982
|
<div class="field">
|
|
1538
1983
|
<label for="requestBody">\u8BF7\u6C42\u4F53 JSON</label>
|
|
1539
1984
|
<textarea class="textarea" id="requestBody" spellcheck="false"></textarea>
|
|
@@ -1597,6 +2042,65 @@ function renderAdminPage() {
|
|
|
1597
2042
|
</main>
|
|
1598
2043
|
</div>
|
|
1599
2044
|
|
|
2045
|
+
<div class="drawer-backdrop" id="settingsDrawerBackdrop" aria-hidden="true">
|
|
2046
|
+
<aside class="settings-drawer" role="dialog" aria-modal="true" aria-labelledby="settingsDrawerTitle">
|
|
2047
|
+
<div class="settings-drawer-head">
|
|
2048
|
+
<div>
|
|
2049
|
+
<h3 id="settingsDrawerTitle">\u7CFB\u7EDF\u8BBE\u7F6E</h3>
|
|
2050
|
+
<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>
|
|
2051
|
+
</div>
|
|
2052
|
+
<button class="btn-secondary" id="closeSettingsDrawerBtn" type="button">\u5173\u95ED</button>
|
|
2053
|
+
</div>
|
|
2054
|
+
<div class="settings-drawer-body">
|
|
2055
|
+
<section class="settings-section">
|
|
2056
|
+
<h4>\u9ED8\u8BA4\u6A21\u578B</h4>
|
|
2057
|
+
<div class="field">
|
|
2058
|
+
<label for="defaultModel">\u9ED8\u8BA4\u6A21\u578B</label>
|
|
2059
|
+
<select class="control" id="defaultModel"></select>
|
|
2060
|
+
<p class="hint">\u5F71\u54CD\u672A\u663E\u5F0F\u4F20 <code>model</code> \u7684\u8BF7\u6C42\u3002</p>
|
|
2061
|
+
<p class="hint" id="modelCatalogHint"></p>
|
|
2062
|
+
<div class="actions">
|
|
2063
|
+
<button class="btn-secondary" id="refreshModelsBtn" type="button">\u540C\u6B65 Codex \u6A21\u578B</button>
|
|
2064
|
+
</div>
|
|
2065
|
+
</div>
|
|
2066
|
+
</section>
|
|
2067
|
+
|
|
2068
|
+
<section class="settings-section">
|
|
2069
|
+
<h4>\u4E0A\u6E38\u4EE3\u7406</h4>
|
|
2070
|
+
<div class="field">
|
|
2071
|
+
<label class="checkbox-row" for="proxyEnabled">
|
|
2072
|
+
<input id="proxyEnabled" type="checkbox" />
|
|
2073
|
+
\u542F\u7528\u4E0A\u6E38\u4EE3\u7406
|
|
2074
|
+
</label>
|
|
2075
|
+
<label for="proxyUrl">\u4EE3\u7406\u5730\u5740</label>
|
|
2076
|
+
<input class="input" id="proxyUrl" type="text" placeholder="\u586B\u5199\u4F60\u7684\u4EE3\u7406\u5730\u5740" />
|
|
2077
|
+
<label for="proxyNoProxy">\u76F4\u8FDE\u5730\u5740</label>
|
|
2078
|
+
<input class="input" id="proxyNoProxy" type="text" placeholder="localhost,127.0.0.1,::1" />
|
|
2079
|
+
<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>
|
|
2080
|
+
<div class="actions">
|
|
2081
|
+
<button class="btn-secondary" id="testProxyBtn" type="button">\u6D4B\u8BD5\u4EE3\u7406</button>
|
|
2082
|
+
</div>
|
|
2083
|
+
</div>
|
|
2084
|
+
</section>
|
|
2085
|
+
|
|
2086
|
+
<section class="settings-section">
|
|
2087
|
+
<h4>\u8D26\u53F7\u5207\u6362</h4>
|
|
2088
|
+
<div class="field">
|
|
2089
|
+
<label class="checkbox-row" for="autoSwitchEnabled">
|
|
2090
|
+
<input id="autoSwitchEnabled" type="checkbox" />
|
|
2091
|
+
\u989D\u5EA6\u8017\u5C3D\u81EA\u52A8\u5207\u6362
|
|
2092
|
+
</label>
|
|
2093
|
+
<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>
|
|
2094
|
+
</div>
|
|
2095
|
+
</section>
|
|
2096
|
+
</div>
|
|
2097
|
+
<div class="settings-drawer-footer">
|
|
2098
|
+
<p class="status-inline" id="settingsStatus"></p>
|
|
2099
|
+
<button class="btn-primary" id="saveSettingsBtn" type="button">\u4FDD\u5B58\u8BBE\u7F6E</button>
|
|
2100
|
+
</div>
|
|
2101
|
+
</aside>
|
|
2102
|
+
</div>
|
|
2103
|
+
|
|
1600
2104
|
<div class="modal-backdrop" id="imagePreviewModal" aria-hidden="true">
|
|
1601
2105
|
<section class="modal-card preview-modal-card" role="dialog" aria-modal="true" aria-labelledby="imagePreviewTitle">
|
|
1602
2106
|
<div class="modal-head">
|
|
@@ -1686,7 +2190,8 @@ function renderAdminPage() {
|
|
|
1686
2190
|
</div>
|
|
1687
2191
|
|
|
1688
2192
|
<script>
|
|
1689
|
-
const RUNTIME_AUTO_REFRESH_MS =
|
|
2193
|
+
const RUNTIME_AUTO_REFRESH_MS = 5 * 60 * 1000;
|
|
2194
|
+
const ACTIVE_PROFILE_REFRESH_MS = 15 * 1000;
|
|
1690
2195
|
|
|
1691
2196
|
const state = {
|
|
1692
2197
|
config: null,
|
|
@@ -1698,7 +2203,9 @@ function renderAdminPage() {
|
|
|
1698
2203
|
sort: "quota-desc",
|
|
1699
2204
|
},
|
|
1700
2205
|
selectedProfileIds: {},
|
|
2206
|
+
expandedProfileIds: {},
|
|
1701
2207
|
testerResultTab: "response",
|
|
2208
|
+
settingsDirty: false,
|
|
1702
2209
|
};
|
|
1703
2210
|
|
|
1704
2211
|
const endpointMeta = {
|
|
@@ -1743,6 +2250,7 @@ function renderAdminPage() {
|
|
|
1743
2250
|
const accountModal = document.getElementById("accountModal");
|
|
1744
2251
|
const contactModal = document.getElementById("contactModal");
|
|
1745
2252
|
const imagePreviewModal = document.getElementById("imagePreviewModal");
|
|
2253
|
+
const settingsDrawerBackdrop = document.getElementById("settingsDrawerBackdrop");
|
|
1746
2254
|
const contactBtn = document.getElementById("contactBtn");
|
|
1747
2255
|
const previewModalImage = document.getElementById("previewModalImage");
|
|
1748
2256
|
const previewModalMeta = document.getElementById("previewModalMeta");
|
|
@@ -1759,6 +2267,10 @@ function renderAdminPage() {
|
|
|
1759
2267
|
const proxyEnabled = document.getElementById("proxyEnabled");
|
|
1760
2268
|
const proxyUrl = document.getElementById("proxyUrl");
|
|
1761
2269
|
const proxyNoProxy = document.getElementById("proxyNoProxy");
|
|
2270
|
+
const testProxyBtn = document.getElementById("testProxyBtn");
|
|
2271
|
+
const autoSwitchEnabled = document.getElementById("autoSwitchEnabled");
|
|
2272
|
+
const settingsStatus = document.getElementById("settingsStatus");
|
|
2273
|
+
const saveSettingsBtn = document.getElementById("saveSettingsBtn");
|
|
1762
2274
|
|
|
1763
2275
|
function setBusy(button, busy) {
|
|
1764
2276
|
if (button) {
|
|
@@ -1850,6 +2362,9 @@ function renderAdminPage() {
|
|
|
1850
2362
|
if (minutes === 60 * 24) {
|
|
1851
2363
|
return "\u65E5\u989D\u5EA6";
|
|
1852
2364
|
}
|
|
2365
|
+
if (minutes === 60 * 5) {
|
|
2366
|
+
return "5 \u5C0F\u65F6\u989D\u5EA6";
|
|
2367
|
+
}
|
|
1853
2368
|
if (minutes === 60 * 24 * 7) {
|
|
1854
2369
|
return "\u5468\u989D\u5EA6";
|
|
1855
2370
|
}
|
|
@@ -1862,6 +2377,68 @@ function renderAdminPage() {
|
|
|
1862
2377
|
: "unknown";
|
|
1863
2378
|
}
|
|
1864
2379
|
|
|
2380
|
+
function getPlanRank(profile) {
|
|
2381
|
+
const plan = getPlanType(profile).toLowerCase();
|
|
2382
|
+
if (plan.indexOf("enterprise") !== -1 || plan.indexOf("business") !== -1) {
|
|
2383
|
+
return 60;
|
|
2384
|
+
}
|
|
2385
|
+
if (plan.indexOf("team") !== -1) {
|
|
2386
|
+
return 50;
|
|
2387
|
+
}
|
|
2388
|
+
if (plan.indexOf("pro") !== -1 || plan.indexOf("premium") !== -1) {
|
|
2389
|
+
return 40;
|
|
2390
|
+
}
|
|
2391
|
+
if (plan.indexOf("plus") !== -1) {
|
|
2392
|
+
return 30;
|
|
2393
|
+
}
|
|
2394
|
+
if (plan.indexOf("free") !== -1) {
|
|
2395
|
+
return 10;
|
|
2396
|
+
}
|
|
2397
|
+
return 0;
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
function getPlanKey(profile) {
|
|
2401
|
+
const plan = getPlanType(profile).toLowerCase();
|
|
2402
|
+
if (plan.indexOf("enterprise") !== -1 || plan.indexOf("business") !== -1) {
|
|
2403
|
+
return "enterprise";
|
|
2404
|
+
}
|
|
2405
|
+
if (plan.indexOf("team") !== -1) {
|
|
2406
|
+
return "team";
|
|
2407
|
+
}
|
|
2408
|
+
if (plan.indexOf("pro") !== -1 || plan.indexOf("premium") !== -1) {
|
|
2409
|
+
return plan.indexOf("premium") !== -1 ? "premium" : "pro";
|
|
2410
|
+
}
|
|
2411
|
+
if (plan.indexOf("plus") !== -1) {
|
|
2412
|
+
return "plus";
|
|
2413
|
+
}
|
|
2414
|
+
if (plan.indexOf("free") !== -1) {
|
|
2415
|
+
return "free";
|
|
2416
|
+
}
|
|
2417
|
+
return "unknown";
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
function getUsageCorner(profile, isCodexActive) {
|
|
2421
|
+
if (profile.isActive && isCodexActive) {
|
|
2422
|
+
return {
|
|
2423
|
+
className: "dual",
|
|
2424
|
+
label: "API + Codex",
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
if (profile.isActive) {
|
|
2428
|
+
return {
|
|
2429
|
+
className: "api-only",
|
|
2430
|
+
label: "API",
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
if (isCodexActive) {
|
|
2434
|
+
return {
|
|
2435
|
+
className: "codex-only",
|
|
2436
|
+
label: "Codex",
|
|
2437
|
+
};
|
|
2438
|
+
}
|
|
2439
|
+
return null;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
1865
2442
|
function getQuotaSnapshotTime(profile) {
|
|
1866
2443
|
return profile && profile.quota && typeof profile.quota.capturedAt === "number"
|
|
1867
2444
|
? profile.quota.capturedAt
|
|
@@ -1933,12 +2510,12 @@ function renderAdminPage() {
|
|
|
1933
2510
|
title.textContent = "\u53D1\u73B0\u65B0\u7248\u672C\u53EF\u66F4\u65B0";
|
|
1934
2511
|
detail.textContent = "\u5F53\u524D\u7248\u672C " + versionStatus.currentVersion + "\uFF0C\u6700\u65B0\u7248\u672C "
|
|
1935
2512
|
+ versionStatus.latestVersion + "\u3002\u66F4\u65B0\u540E\u53EF\u83B7\u5F97\u6700\u65B0\u6A21\u578B\u5217\u8868\u903B\u8F91\u3001\u7BA1\u7406\u9875\u4F53\u9A8C\u548C\u63A5\u53E3\u4FEE\u590D\u3002";
|
|
1936
|
-
command.textContent = "npm install -g " + versionStatus.packageName
|
|
2513
|
+
command.textContent = "npm install -g " + versionStatus.packageName;
|
|
1937
2514
|
panel.classList.add("is-visible");
|
|
1938
2515
|
}
|
|
1939
2516
|
|
|
1940
2517
|
function supportsImageGeneration(profile) {
|
|
1941
|
-
return
|
|
2518
|
+
return Boolean(profile);
|
|
1942
2519
|
}
|
|
1943
2520
|
|
|
1944
2521
|
function getImageCapability(profile) {
|
|
@@ -1954,10 +2531,10 @@ function renderAdminPage() {
|
|
|
1954
2531
|
const planType = getPlanType(profile);
|
|
1955
2532
|
if (planType === "free") {
|
|
1956
2533
|
return {
|
|
1957
|
-
supported:
|
|
1958
|
-
label: "\u751F\u56FE
|
|
1959
|
-
detail: "free \
|
|
1960
|
-
badgeClass: "
|
|
2534
|
+
supported: true,
|
|
2535
|
+
label: "\u53EF\u5C1D\u8BD5\u751F\u56FE",
|
|
2536
|
+
detail: "free \u8D26\u53F7\u53EF\u5C1D\u8BD5\u56FE\u7247\u751F\u6210\uFF0C\u989D\u5EA6\u548C\u53EF\u7528\u6027\u4EE5\u4E0A\u6E38\u8FD4\u56DE\u4E3A\u51C6\u3002",
|
|
2537
|
+
badgeClass: "orange",
|
|
1961
2538
|
};
|
|
1962
2539
|
}
|
|
1963
2540
|
|
|
@@ -2050,6 +2627,41 @@ function renderAdminPage() {
|
|
|
2050
2627
|
return Math.max(0, Math.min(100, value));
|
|
2051
2628
|
}
|
|
2052
2629
|
|
|
2630
|
+
function isProfileQuotaExhausted(profile) {
|
|
2631
|
+
if (!profile || !profile.quota) {
|
|
2632
|
+
return false;
|
|
2633
|
+
}
|
|
2634
|
+
|
|
2635
|
+
return getPrimaryUsage(profile) >= 100 || getSecondaryUsage(profile) >= 100;
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
function findProfileById(profileId) {
|
|
2639
|
+
const profiles = state.config && Array.isArray(state.config.profiles) ? state.config.profiles : [];
|
|
2640
|
+
return profiles.find(function (profile) {
|
|
2641
|
+
return profile.profileId === profileId;
|
|
2642
|
+
}) || null;
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
function confirmQuotaSwitch(action, profileId) {
|
|
2646
|
+
if (action !== "activate" && action !== "apply-codex") {
|
|
2647
|
+
return true;
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
const profile = findProfileById(profileId);
|
|
2651
|
+
if (!isProfileQuotaExhausted(profile)) {
|
|
2652
|
+
return true;
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
const target = action === "activate" ? "\u7F51\u5173" : "Codex";
|
|
2656
|
+
const label = getProfileDisplayLabel(profile);
|
|
2657
|
+
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";
|
|
2658
|
+
const confirmed = window.confirm(message);
|
|
2659
|
+
if (!confirmed) {
|
|
2660
|
+
authStatus.textContent = "\u5DF2\u53D6\u6D88\u5E94\u7528\u5230 " + target + "\u3002";
|
|
2661
|
+
}
|
|
2662
|
+
return confirmed;
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2053
2665
|
function getProfileHealth(profile) {
|
|
2054
2666
|
const now = Date.now();
|
|
2055
2667
|
if (profile && profile.expiresAt && profile.expiresAt <= now) {
|
|
@@ -2105,6 +2717,37 @@ function renderAdminPage() {
|
|
|
2105
2717
|
return "\u672A\u77E5";
|
|
2106
2718
|
}
|
|
2107
2719
|
|
|
2720
|
+
function formatCompactDateTime(value) {
|
|
2721
|
+
if (!value) {
|
|
2722
|
+
return "\u6682\u65E0\u6570\u636E";
|
|
2723
|
+
}
|
|
2724
|
+
const date = new Date(value);
|
|
2725
|
+
if (Number.isNaN(date.getTime())) {
|
|
2726
|
+
return "\u672A\u77E5";
|
|
2727
|
+
}
|
|
2728
|
+
const month = String(date.getMonth() + 1);
|
|
2729
|
+
const day = String(date.getDate());
|
|
2730
|
+
const time = date.toLocaleTimeString("zh-CN", { hour12: false, hour: "2-digit", minute: "2-digit" });
|
|
2731
|
+
return month + "/" + day + " " + time;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
function describeCompactReset(profile, slot) {
|
|
2735
|
+
if (!profile || !profile.quota) {
|
|
2736
|
+
return "\u6682\u65E0\u6570\u636E";
|
|
2737
|
+
}
|
|
2738
|
+
|
|
2739
|
+
const quota = profile.quota;
|
|
2740
|
+
const resetAt = slot === "primary" ? quota.primaryResetAt : quota.secondaryResetAt;
|
|
2741
|
+
const resetAfter = slot === "primary" ? quota.primaryResetAfterSeconds : quota.secondaryResetAfterSeconds;
|
|
2742
|
+
if (typeof resetAt === "number" && resetAt > 0) {
|
|
2743
|
+
return formatCompactDateTime(resetAt * 1000);
|
|
2744
|
+
}
|
|
2745
|
+
if (typeof resetAfter === "number" && resetAfter > 0) {
|
|
2746
|
+
return formatCompactDuration(resetAfter) + "\u540E";
|
|
2747
|
+
}
|
|
2748
|
+
return "\u672A\u77E5";
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2108
2751
|
function getQuotaWindowLabel(profile, slot) {
|
|
2109
2752
|
const quota = profile && profile.quota ? profile.quota : null;
|
|
2110
2753
|
if (!quota) {
|
|
@@ -2114,6 +2757,17 @@ function renderAdminPage() {
|
|
|
2114
2757
|
return formatWindowLabel(quota && quota[field]);
|
|
2115
2758
|
}
|
|
2116
2759
|
|
|
2760
|
+
function getResetLabel(profile, slot) {
|
|
2761
|
+
const label = getQuotaWindowLabel(profile, slot);
|
|
2762
|
+
if (label === "5 \u5C0F\u65F6\u989D\u5EA6") {
|
|
2763
|
+
return "5\u5C0F\u65F6\u91CD\u7F6E";
|
|
2764
|
+
}
|
|
2765
|
+
if (label === "\u5468\u989D\u5EA6") {
|
|
2766
|
+
return "\u5468\u91CD\u7F6E";
|
|
2767
|
+
}
|
|
2768
|
+
return label.replace("\u989D\u5EA6", "") + "\u91CD\u7F6E";
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2117
2771
|
function formatQuotaUsage(percent, profile, slot) {
|
|
2118
2772
|
if (!profile || !profile.quota) {
|
|
2119
2773
|
return "\u7B49\u5F85\u5237\u65B0";
|
|
@@ -2362,50 +3016,58 @@ function renderAdminPage() {
|
|
|
2362
3016
|
const codexProfile = codexAccountId && Array.isArray(config.profiles)
|
|
2363
3017
|
? config.profiles.find(function (profile) { return profile.accountId === codexAccountId; })
|
|
2364
3018
|
: null;
|
|
3019
|
+
const gatewayLabel = config.profile ? getProfileDisplayLabel(config.profile) : "\u672A\u6FC0\u6D3B\u8D26\u53F7";
|
|
3020
|
+
const codexLabel = codexProfile
|
|
3021
|
+
? getProfileDisplayLabel(codexProfile)
|
|
3022
|
+
: (codexAccountId ? maskIdentifier(codexAccountId) : "\u672A\u68C0\u6D4B\u5230");
|
|
2365
3023
|
|
|
2366
3024
|
return [
|
|
2367
3025
|
{
|
|
3026
|
+
icon: "users",
|
|
3027
|
+
iconClass: "blue",
|
|
2368
3028
|
label: "\u8D26\u53F7\u603B\u6570",
|
|
2369
3029
|
value: String(config.status.profileCount || 0),
|
|
2370
3030
|
detail: "\u5DF2\u4FDD\u5B58\u5230\u672C\u5730\u8D26\u53F7\u6C60",
|
|
2371
3031
|
},
|
|
2372
3032
|
{
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
: "\u5C1A\u672A\u6FC0\u6D3B\u8D26\u53F7",
|
|
2378
|
-
compact: true,
|
|
3033
|
+
kind: "account-status",
|
|
3034
|
+
label: "\u5F53\u524D\u8D26\u53F7\u72B6\u6001",
|
|
3035
|
+
gatewayLabel: gatewayLabel,
|
|
3036
|
+
codexLabel: codexLabel,
|
|
2379
3037
|
},
|
|
2380
3038
|
{
|
|
3039
|
+
icon: "model",
|
|
3040
|
+
iconClass: "brand",
|
|
2381
3041
|
label: "\u9ED8\u8BA4\u6A21\u578B",
|
|
2382
3042
|
value: config.settings.defaultModel || "-",
|
|
2383
3043
|
detail: "\u672A\u663E\u5F0F\u6307\u5B9A model \u65F6\u751F\u6548",
|
|
2384
3044
|
compact: true,
|
|
2385
3045
|
},
|
|
2386
3046
|
{
|
|
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
|
-
{
|
|
3047
|
+
icon: "version",
|
|
3048
|
+
iconClass: config.versionStatus && config.versionStatus.needsUpdate ? "orange" : "green",
|
|
2393
3049
|
label: "\u5F53\u524D\u7248\u672C",
|
|
2394
3050
|
value: getVersionValue(config),
|
|
2395
3051
|
detail: getVersionDetail(config),
|
|
2396
3052
|
compact: true,
|
|
2397
3053
|
},
|
|
2398
3054
|
{
|
|
3055
|
+
icon: "requests",
|
|
3056
|
+
iconClass: "blue",
|
|
2399
3057
|
label: "\u4ECA\u65E5\u8BF7\u6C42\u6570",
|
|
2400
3058
|
value: String(requests.length),
|
|
2401
3059
|
detail: "\u57FA\u4E8E\u672C\u9875\u6700\u8FD1\u6D4B\u8BD5\u8BB0\u5F55",
|
|
2402
3060
|
},
|
|
2403
3061
|
{
|
|
3062
|
+
icon: "latency",
|
|
3063
|
+
iconClass: "orange",
|
|
2404
3064
|
label: "\u5E73\u5747\u8017\u65F6",
|
|
2405
3065
|
value: requests.length ? (avg / 1000).toFixed(2) + " s" : "--",
|
|
2406
3066
|
detail: requests.length ? "\u7EDF\u8BA1\u6700\u8FD1 " + String(requests.length) + " \u6B21" : "\u7B49\u5F85\u8BF7\u6C42\u6837\u672C",
|
|
2407
3067
|
},
|
|
2408
3068
|
{
|
|
3069
|
+
icon: "service",
|
|
3070
|
+
iconClass: config.status.loggedIn ? "green" : "orange",
|
|
2409
3071
|
label: "\u670D\u52A1\u72B6\u6001",
|
|
2410
3072
|
value: config.status.loggedIn ? "\u8FD0\u884C\u4E2D" : "\u5F85\u767B\u5F55",
|
|
2411
3073
|
detail: config.status.loggedIn ? "\u7F51\u5173\u53EF\u8F6C\u53D1\u8BF7\u6C42" : "\u8BF7\u5148\u5B8C\u6210 OAuth \u767B\u5F55",
|
|
@@ -2414,14 +3076,63 @@ function renderAdminPage() {
|
|
|
2414
3076
|
];
|
|
2415
3077
|
}
|
|
2416
3078
|
|
|
3079
|
+
function getSummaryIcon(name) {
|
|
3080
|
+
if (name === "users") {
|
|
3081
|
+
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>';
|
|
3082
|
+
}
|
|
3083
|
+
if (name === "model") {
|
|
3084
|
+
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>';
|
|
3085
|
+
}
|
|
3086
|
+
if (name === "version") {
|
|
3087
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6 9 17l-5-5"></path></svg>';
|
|
3088
|
+
}
|
|
3089
|
+
if (name === "requests") {
|
|
3090
|
+
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>';
|
|
3091
|
+
}
|
|
3092
|
+
if (name === "latency") {
|
|
3093
|
+
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>';
|
|
3094
|
+
}
|
|
3095
|
+
if (name === "service") {
|
|
3096
|
+
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>';
|
|
3097
|
+
}
|
|
3098
|
+
return '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"></circle></svg>';
|
|
3099
|
+
}
|
|
3100
|
+
|
|
2417
3101
|
function renderOverview(config) {
|
|
2418
3102
|
const container = document.getElementById("summaryGrid");
|
|
2419
3103
|
const cards = getOverviewCards(config);
|
|
2420
3104
|
container.innerHTML = cards.map(function (card) {
|
|
3105
|
+
if (card.kind === "account-status") {
|
|
3106
|
+
return ""
|
|
3107
|
+
+ '<article class="summary-card account-status-summary">'
|
|
3108
|
+
+ '<div class="summary-card-head">'
|
|
3109
|
+
+ '<span class="summary-icon green">'
|
|
3110
|
+
+ '<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>'
|
|
3111
|
+
+ "</span>"
|
|
3112
|
+
+ "<label>" + escapeHtml(card.label) + "</label>"
|
|
3113
|
+
+ "</div>"
|
|
3114
|
+
+ '<div class="account-status-list">'
|
|
3115
|
+
+ '<div class="account-status-line gateway">'
|
|
3116
|
+
+ '<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>'
|
|
3117
|
+
+ "<span>\u7F51\u5173\uFF1A</span>"
|
|
3118
|
+
+ "<strong>" + escapeHtml(card.gatewayLabel) + "</strong>"
|
|
3119
|
+
+ "</div>"
|
|
3120
|
+
+ '<div class="account-status-line codex">'
|
|
3121
|
+
+ '<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>'
|
|
3122
|
+
+ "<span>Codex\uFF1A</span>"
|
|
3123
|
+
+ "<strong>" + escapeHtml(card.codexLabel) + "</strong>"
|
|
3124
|
+
+ "</div>"
|
|
3125
|
+
+ "</div>"
|
|
3126
|
+
+ "</article>";
|
|
3127
|
+
}
|
|
2421
3128
|
const valueClass = card.compact ? "summary-value-sm" : "";
|
|
3129
|
+
const iconClass = card.iconClass ? " " + card.iconClass : "";
|
|
2422
3130
|
return ""
|
|
2423
3131
|
+ '<article class="summary-card">'
|
|
2424
|
-
+
|
|
3132
|
+
+ '<div class="summary-card-head">'
|
|
3133
|
+
+ '<span class="summary-icon' + iconClass + '">' + getSummaryIcon(card.icon) + "</span>"
|
|
3134
|
+
+ "<label>" + escapeHtml(card.label) + "</label>"
|
|
3135
|
+
+ "</div>"
|
|
2425
3136
|
+ '<strong class="' + valueClass + '">' + escapeHtml(card.value) + "</strong>"
|
|
2426
3137
|
+ "<span>" + escapeHtml(card.detail) + "</span>"
|
|
2427
3138
|
+ "</article>";
|
|
@@ -2433,6 +3144,7 @@ function renderAdminPage() {
|
|
|
2433
3144
|
const search = state.filters.search.trim().toLowerCase();
|
|
2434
3145
|
const status = state.filters.status;
|
|
2435
3146
|
const sort = state.filters.sort;
|
|
3147
|
+
const codexAccountId = config.codex && config.codex.accountId ? config.codex.accountId : "";
|
|
2436
3148
|
|
|
2437
3149
|
const filtered = profiles.filter(function (profile) {
|
|
2438
3150
|
const label = getProfileDisplayLabel(profile).toLowerCase();
|
|
@@ -2447,7 +3159,8 @@ function renderAdminPage() {
|
|
|
2447
3159
|
}
|
|
2448
3160
|
|
|
2449
3161
|
const health = getProfileHealth(profile);
|
|
2450
|
-
|
|
3162
|
+
const isCodexActive = Boolean(codexAccountId && profile.accountId === codexAccountId);
|
|
3163
|
+
if (status === "active" && !profile.isActive && !isCodexActive) {
|
|
2451
3164
|
return false;
|
|
2452
3165
|
}
|
|
2453
3166
|
if (status === "healthy" && health.key !== "healthy") {
|
|
@@ -2463,6 +3176,24 @@ function renderAdminPage() {
|
|
|
2463
3176
|
});
|
|
2464
3177
|
|
|
2465
3178
|
filtered.sort(function (a, b) {
|
|
3179
|
+
const aCodexActive = Boolean(codexAccountId && a.accountId === codexAccountId);
|
|
3180
|
+
const bCodexActive = Boolean(codexAccountId && b.accountId === codexAccountId);
|
|
3181
|
+
const activeDiff = Number(b.isActive || bCodexActive) - Number(a.isActive || aCodexActive);
|
|
3182
|
+
if (activeDiff !== 0) {
|
|
3183
|
+
return activeDiff;
|
|
3184
|
+
}
|
|
3185
|
+
const gatewayDiff = Number(b.isActive) - Number(a.isActive);
|
|
3186
|
+
if (gatewayDiff !== 0) {
|
|
3187
|
+
return gatewayDiff;
|
|
3188
|
+
}
|
|
3189
|
+
const codexDiff = Number(bCodexActive) - Number(aCodexActive);
|
|
3190
|
+
if (codexDiff !== 0) {
|
|
3191
|
+
return codexDiff;
|
|
3192
|
+
}
|
|
3193
|
+
const planDiff = getPlanRank(b) - getPlanRank(a);
|
|
3194
|
+
if (planDiff !== 0) {
|
|
3195
|
+
return planDiff;
|
|
3196
|
+
}
|
|
2466
3197
|
if (sort === "latency-asc") {
|
|
2467
3198
|
const aCapturedAt = getQuotaSnapshotTime(a) || 0;
|
|
2468
3199
|
const bCapturedAt = getQuotaSnapshotTime(b) || 0;
|
|
@@ -2499,6 +3230,11 @@ function renderAdminPage() {
|
|
|
2499
3230
|
delete state.selectedProfileIds[profileId];
|
|
2500
3231
|
}
|
|
2501
3232
|
});
|
|
3233
|
+
Object.keys(state.expandedProfileIds).forEach(function (profileId) {
|
|
3234
|
+
if (!availableIds[profileId]) {
|
|
3235
|
+
delete state.expandedProfileIds[profileId];
|
|
3236
|
+
}
|
|
3237
|
+
});
|
|
2502
3238
|
}
|
|
2503
3239
|
|
|
2504
3240
|
function updateSelectedProfileControls() {
|
|
@@ -2512,6 +3248,7 @@ function renderAdminPage() {
|
|
|
2512
3248
|
syncSelectedProfiles(config);
|
|
2513
3249
|
updateSelectedProfileControls();
|
|
2514
3250
|
const profiles = getFilteredProfiles(config);
|
|
3251
|
+
const codexAccountId = config.codex && config.codex.accountId ? config.codex.accountId : "";
|
|
2515
3252
|
const gridClass = profiles.length <= 0
|
|
2516
3253
|
? ""
|
|
2517
3254
|
: profiles.length === 1
|
|
@@ -2530,22 +3267,29 @@ function renderAdminPage() {
|
|
|
2530
3267
|
|
|
2531
3268
|
container.innerHTML = profiles.map(function (profile) {
|
|
2532
3269
|
const selected = !!state.selectedProfileIds[profile.profileId];
|
|
2533
|
-
const
|
|
3270
|
+
const expanded = !!state.expandedProfileIds[profile.profileId];
|
|
2534
3271
|
const health = getProfileHealth(profile);
|
|
2535
3272
|
const planType = getPlanType(profile);
|
|
3273
|
+
const planKey = getPlanKey(profile);
|
|
2536
3274
|
const imageCapability = getImageCapability(profile);
|
|
2537
3275
|
const primary = getPrimaryUsage(profile);
|
|
2538
3276
|
const secondary = getSecondaryUsage(profile);
|
|
2539
3277
|
const primaryClass = health.barClass || "blue";
|
|
2540
3278
|
const secondaryClass = secondary >= 85 ? "orange" : "blue";
|
|
3279
|
+
const isCodexActive = Boolean(codexAccountId && profile.accountId === codexAccountId);
|
|
3280
|
+
const usageCorner = getUsageCorner(profile, isCodexActive);
|
|
3281
|
+
const apiUsageClass = profile.isActive ? " is-active" : "";
|
|
3282
|
+
const codexUsageClass = isCodexActive ? " is-active" : "";
|
|
2541
3283
|
const actionButton = profile.isActive
|
|
2542
|
-
?
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
3284
|
+
? '<button class="btn-secondary is-current" type="button" disabled>\u7F51\u5173\u4F7F\u7528\u4E2D</button>'
|
|
3285
|
+
: '<button class="btn-secondary" type="button" data-profile-action="activate" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5E94\u7528\u7F51\u5173</button>';
|
|
3286
|
+
const codexButton = isCodexActive
|
|
3287
|
+
? '<button class="btn-secondary is-current codex" type="button" disabled>Codex \u4F7F\u7528\u4E2D</button>'
|
|
3288
|
+
: '<button class="btn-secondary" type="button" data-profile-action="apply-codex" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5E94\u7528 Codex</button>';
|
|
2546
3289
|
|
|
2547
3290
|
return ""
|
|
2548
|
-
+ '<article class="account-card" data-profile-card="' + escapeHtml(profile.profileId) + '">'
|
|
3291
|
+
+ '<article class="account-card plan-' + escapeHtml(planKey) + '" data-profile-card="' + escapeHtml(profile.profileId) + '">'
|
|
3292
|
+
+ (usageCorner ? '<span class="usage-corner ' + escapeHtml(usageCorner.className) + '"><span>' + escapeHtml(usageCorner.label) + "</span></span>" : "")
|
|
2549
3293
|
+ '<div class="account-head">'
|
|
2550
3294
|
+ '<div class="account-title">'
|
|
2551
3295
|
+ '<div class="account-name">'
|
|
@@ -2553,7 +3297,6 @@ function renderAdminPage() {
|
|
|
2553
3297
|
+ "<strong>" + escapeHtml(getProfileDisplayLabel(profile)) + "</strong>"
|
|
2554
3298
|
+ "</div>"
|
|
2555
3299
|
+ '<div class="badge-row">'
|
|
2556
|
-
+ (profile.isActive ? '<span class="badge blue">\u5F53\u524D\u4F7F\u7528</span>' : "")
|
|
2557
3300
|
+ '<span class="badge brand">' + escapeHtml(planType) + "</span>"
|
|
2558
3301
|
+ '<span class="badge ' + escapeHtml(health.badgeClass) + '">' + escapeHtml(health.label) + "</span>"
|
|
2559
3302
|
+ '<span class="badge ' + escapeHtml(imageCapability.badgeClass) + '">' + escapeHtml(imageCapability.label) + "</span>"
|
|
@@ -2571,18 +3314,45 @@ function renderAdminPage() {
|
|
|
2571
3314
|
+ '<div class="progress-track"><div class="progress-bar ' + escapeHtml(secondaryClass) + '" style="width:' + escapeHtml(String(secondary)) + '%"></div></div>'
|
|
2572
3315
|
+ "</div>"
|
|
2573
3316
|
+ "</div>"
|
|
2574
|
-
+ '<div class="
|
|
2575
|
-
+ '<
|
|
2576
|
-
+
|
|
2577
|
-
+
|
|
2578
|
-
+
|
|
2579
|
-
+
|
|
2580
|
-
+
|
|
2581
|
-
+ '<
|
|
3317
|
+
+ '<div class="usage-status-row">'
|
|
3318
|
+
+ '<span class="usage-status' + apiUsageClass + '">'
|
|
3319
|
+
+ '<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>'
|
|
3320
|
+
+ "<span>API</span>"
|
|
3321
|
+
+ '<span class="usage-dot' + (profile.isActive ? " active" : "") + '"></span>'
|
|
3322
|
+
+ '<span class="usage-state-text">' + (profile.isActive ? "\u4F7F\u7528\u4E2D" : "\u672A\u4F7F\u7528") + "</span>"
|
|
3323
|
+
+ "</span>"
|
|
3324
|
+
+ '<span class="usage-status' + codexUsageClass + '">'
|
|
3325
|
+
+ '<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>'
|
|
3326
|
+
+ "<span>Codex</span>"
|
|
3327
|
+
+ '<span class="usage-dot' + (isCodexActive ? " active" : "") + '"></span>'
|
|
3328
|
+
+ '<span class="usage-state-text">' + (isCodexActive ? "\u4F7F\u7528\u4E2D" : "\u672A\u4F7F\u7528") + "</span>"
|
|
3329
|
+
+ "</span>"
|
|
2582
3330
|
+ "</div>"
|
|
3331
|
+
+ '<div class="compact-meta-row">'
|
|
3332
|
+
+ '<div class="compact-reset-list">'
|
|
3333
|
+
+ '<div class="compact-meta-item"><label>' + escapeHtml(getResetLabel(profile, "primary")) + '</label><strong>' + escapeHtml(describeCompactReset(profile, "primary")) + "</strong></div>"
|
|
3334
|
+
+ '<div class="compact-meta-item"><label>' + escapeHtml(getResetLabel(profile, "secondary")) + '</label><strong>' + escapeHtml(describeCompactReset(profile, "secondary")) + "</strong></div>"
|
|
3335
|
+
+ "</div>"
|
|
3336
|
+
+ '<div class="compact-meta-actions">'
|
|
3337
|
+
+ '<button class="details-toggle' + (expanded ? " is-expanded" : "") + '" type="button" data-profile-action="toggle-details" data-profile-id="' + escapeHtml(profile.profileId) + '">'
|
|
3338
|
+
+ "<span>" + (expanded ? "\u6536\u8D77\u8BE6\u60C5" : "\u67E5\u770B\u8BE6\u60C5") + "</span>"
|
|
3339
|
+
+ '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"></path></svg>'
|
|
3340
|
+
+ "</button>"
|
|
3341
|
+
+ "</div>"
|
|
3342
|
+
+ "</div>"
|
|
3343
|
+
+ (expanded
|
|
3344
|
+
? '<div class="meta-grid">'
|
|
3345
|
+
+ '<div class="meta-item"><label>\u5957\u9910</label><strong>' + escapeHtml(planType) + "</strong></div>"
|
|
3346
|
+
+ '<div class="meta-item"><label>\u751F\u56FE\u80FD\u529B</label><strong>' + escapeHtml(imageCapability.detail) + "</strong></div>"
|
|
3347
|
+
+ '<div class="meta-item"><label>\u989D\u5EA6\u5FEB\u7167</label><strong>' + escapeHtml(describeQuotaSnapshot(profile)) + "</strong></div>"
|
|
3348
|
+
+ '<div class="meta-item"><label>\u989D\u5EA6\u9650\u5236</label><strong>' + escapeHtml(describeQuotaLimit(profile)) + "</strong></div>"
|
|
3349
|
+
+ '<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>"
|
|
3350
|
+
+ '<div class="meta-item"><label>\u8FC7\u671F\u65F6\u95F4</label><span>' + escapeHtml(formatTime(profile.expiresAt)) + "</span></div>"
|
|
3351
|
+
+ "</div>"
|
|
3352
|
+
: "")
|
|
2583
3353
|
+ '<div class="account-actions">'
|
|
2584
3354
|
+ actionButton
|
|
2585
|
-
+
|
|
3355
|
+
+ codexButton
|
|
2586
3356
|
+ '<button class="btn-secondary" type="button" data-profile-action="export" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5BFC\u51FA</button>'
|
|
2587
3357
|
+ '<button class="btn-danger" type="button" data-profile-action="remove" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5220\u9664</button>'
|
|
2588
3358
|
+ "</div>"
|
|
@@ -2747,6 +3517,7 @@ function renderAdminPage() {
|
|
|
2747
3517
|
["Provider", config.status.activeProvider || "openai-codex"],
|
|
2748
3518
|
["\u9ED8\u8BA4\u6A21\u578B", config.settings.defaultModel],
|
|
2749
3519
|
["\u4E0A\u6E38\u4EE3\u7406", config.settings.networkProxy && config.settings.networkProxy.enabled ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528"],
|
|
3520
|
+
["\u81EA\u52A8\u5207\u6362", config.settings.autoSwitch && config.settings.autoSwitch.enabled ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528"],
|
|
2750
3521
|
["\u5F53\u524D\u7248\u672C", getVersionValue(config)],
|
|
2751
3522
|
["\u5F53\u524D\u5957\u9910", config.profile ? getPlanType(config.profile) : "\u672A\u767B\u5F55"],
|
|
2752
3523
|
["\u751F\u56FE\u80FD\u529B", getImageCapability(config.profile).detail],
|
|
@@ -2766,6 +3537,7 @@ function renderAdminPage() {
|
|
|
2766
3537
|
["\u5F53\u524D\u8D26\u53F7", getProfileDisplayLabel(config.profile)],
|
|
2767
3538
|
["\u9ED8\u8BA4\u6A21\u578B", config.settings.defaultModel],
|
|
2768
3539
|
["\u4E0A\u6E38\u4EE3\u7406", config.settings.networkProxy && config.settings.networkProxy.enabled ? config.settings.networkProxy.url : "\u672A\u542F\u7528"],
|
|
3540
|
+
["\u81EA\u52A8\u5207\u6362", config.settings.autoSwitch && config.settings.autoSwitch.enabled ? "\u5DF2\u542F\u7528" : "\u672A\u542F\u7528"],
|
|
2769
3541
|
["\u7248\u672C\u72B6\u6001", getVersionDetail(config)],
|
|
2770
3542
|
["\u5F53\u524D\u5957\u9910", config.profile ? getPlanType(config.profile) : "\u672A\u767B\u5F55"],
|
|
2771
3543
|
["\u751F\u56FE\u80FD\u529B", getImageCapability(config.profile).detail],
|
|
@@ -2832,6 +3604,47 @@ function renderAdminPage() {
|
|
|
2832
3604
|
proxyNoProxy.value = proxy.noProxy || "localhost,127.0.0.1,::1";
|
|
2833
3605
|
}
|
|
2834
3606
|
|
|
3607
|
+
function renderAutoSwitchSettings(config) {
|
|
3608
|
+
const autoSwitch = config.settings.autoSwitch || {
|
|
3609
|
+
enabled: false,
|
|
3610
|
+
};
|
|
3611
|
+
autoSwitchEnabled.checked = !!autoSwitch.enabled;
|
|
3612
|
+
}
|
|
3613
|
+
|
|
3614
|
+
function isSettingsDrawerOpen() {
|
|
3615
|
+
return settingsDrawerBackdrop.classList.contains("is-open");
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
function renderSettingsFields(config, options) {
|
|
3619
|
+
if (!config) {
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
if (!(options && options.force) && state.settingsDirty && isSettingsDrawerOpen()) {
|
|
3624
|
+
return;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
renderModelOptions(config);
|
|
3628
|
+
renderModelCatalogStatus(config);
|
|
3629
|
+
renderProxySettings(config);
|
|
3630
|
+
renderAutoSwitchSettings(config);
|
|
3631
|
+
state.settingsDirty = false;
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
function markSettingsDirty() {
|
|
3635
|
+
state.settingsDirty = true;
|
|
3636
|
+
}
|
|
3637
|
+
|
|
3638
|
+
function resetSettingsDraft() {
|
|
3639
|
+
state.settingsDirty = false;
|
|
3640
|
+
if (state.config) {
|
|
3641
|
+
renderSettingsFields(state.config, {
|
|
3642
|
+
force: true,
|
|
3643
|
+
});
|
|
3644
|
+
}
|
|
3645
|
+
settingsStatus.textContent = "";
|
|
3646
|
+
}
|
|
3647
|
+
|
|
2835
3648
|
function syncHero(config) {
|
|
2836
3649
|
const profileText = config.profile
|
|
2837
3650
|
? "\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"
|
|
@@ -2844,10 +3657,10 @@ function renderAdminPage() {
|
|
|
2844
3657
|
const isImageEndpoint = endpointSelect.value === "/v1/images/generations" || endpointSelect.value === "/v1/images/edits";
|
|
2845
3658
|
imageCapabilityHint.textContent = capability.detail;
|
|
2846
3659
|
imageCapabilityHint.className = capability.supported && !isImageEndpoint ? "hint" : "hint warn";
|
|
2847
|
-
runTestBtn.disabled = isImageEndpoint && !
|
|
3660
|
+
runTestBtn.disabled = isImageEndpoint && !config.profile;
|
|
2848
3661
|
if (isImageEndpoint && !capability.supported) {
|
|
2849
3662
|
testerMeta.textContent = capability.label;
|
|
2850
|
-
} else if (testerMeta.textContent === capability.label || testerMeta.textContent === "\u751F\u56FE\u53D7\u9650") {
|
|
3663
|
+
} else if (testerMeta.textContent === capability.label || testerMeta.textContent === "\u751F\u56FE\u53D7\u9650" || testerMeta.textContent === "\u53EF\u5C1D\u8BD5\u751F\u56FE") {
|
|
2851
3664
|
testerMeta.textContent = "\u51C6\u5907\u5C31\u7EEA";
|
|
2852
3665
|
}
|
|
2853
3666
|
}
|
|
@@ -2866,9 +3679,7 @@ function renderAdminPage() {
|
|
|
2866
3679
|
syncHero(config);
|
|
2867
3680
|
renderOverview(config);
|
|
2868
3681
|
renderProfiles(config);
|
|
2869
|
-
|
|
2870
|
-
renderModelCatalogStatus(config);
|
|
2871
|
-
renderProxySettings(config);
|
|
3682
|
+
renderSettingsFields(config);
|
|
2872
3683
|
renderUpdatePanel(config);
|
|
2873
3684
|
renderEndpoints(config);
|
|
2874
3685
|
renderServiceInfo(config);
|
|
@@ -2878,7 +3689,7 @@ function renderAdminPage() {
|
|
|
2878
3689
|
authStatus.textContent = config.status.loggedIn
|
|
2879
3690
|
? (supportsImageGeneration(config.profile)
|
|
2880
3691
|
? "\u7F51\u5173\u5DF2\u53EF\u76F4\u63A5\u8F6C\u53D1\u8BF7\u6C42\uFF0C\u53EF\u4EE5\u5728\u4E0B\u65B9\u5207\u6362\u9ED8\u8BA4\u6A21\u578B\u5E76\u53D1\u9001\u6D4B\u8BD5\u8BF7\u6C42\u3002"
|
|
2881
|
-
: "\u5F53\u524D\u8D26\u53F7\
|
|
3692
|
+
: "\u5F53\u524D\u8D26\u53F7\u672A\u5C31\u7EEA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u540E\u518D\u6D4B\u8BD5\u63A5\u53E3\u3002")
|
|
2882
3693
|
: "\u8BF7\u5148\u70B9\u51FB\u201C\u65B0\u589E\u8D26\u53F7\u201D\uFF0C\u5B8C\u6210 OAuth \u540E\u518D\u6D4B\u8BD5\u63A5\u53E3\u3002";
|
|
2883
3694
|
if (!requestBody.value) {
|
|
2884
3695
|
requestBody.value = buildExample(endpointSelect.value || "/v1/chat/completions");
|
|
@@ -2926,6 +3737,8 @@ function renderAdminPage() {
|
|
|
2926
3737
|
const silent = !!(options && options.silent);
|
|
2927
3738
|
const url = syncRuntime ? "/_gateway/admin/runtime-refresh" : "/_gateway/admin/config";
|
|
2928
3739
|
const requestOptions = syncRuntime ? { method: "POST" } : undefined;
|
|
3740
|
+
const previousProfileId = state.config && state.config.profile ? state.config.profile.profileId : "";
|
|
3741
|
+
const previousStatus = authStatus.textContent;
|
|
2929
3742
|
|
|
2930
3743
|
if (!silent) {
|
|
2931
3744
|
testerMeta.textContent = syncRuntime ? "\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001" : "\u5237\u65B0\u7BA1\u7406\u72B6\u6001";
|
|
@@ -2933,9 +3746,14 @@ function renderAdminPage() {
|
|
|
2933
3746
|
|
|
2934
3747
|
const config = await fetchJson(url, requestOptions);
|
|
2935
3748
|
renderConfig(config);
|
|
3749
|
+
const nextProfileId = config && config.profile ? config.profile.profileId : "";
|
|
2936
3750
|
|
|
2937
3751
|
if (!silent) {
|
|
2938
3752
|
testerMeta.textContent = "\u51C6\u5907\u5C31\u7EEA";
|
|
3753
|
+
} else if (previousProfileId && nextProfileId && previousProfileId !== nextProfileId) {
|
|
3754
|
+
authStatus.textContent = "\u68C0\u6D4B\u5230\u989D\u5EA6\u8017\u5C3D\uFF0C\u7F51\u5173\u5DF2\u81EA\u52A8\u5207\u6362\u5230: " + getProfileDisplayLabel(config.profile);
|
|
3755
|
+
} else {
|
|
3756
|
+
authStatus.textContent = previousStatus;
|
|
2939
3757
|
}
|
|
2940
3758
|
|
|
2941
3759
|
return config;
|
|
@@ -2956,6 +3774,20 @@ function renderAdminPage() {
|
|
|
2956
3774
|
}, RUNTIME_AUTO_REFRESH_MS);
|
|
2957
3775
|
}
|
|
2958
3776
|
|
|
3777
|
+
function scheduleActiveProfileRefresh() {
|
|
3778
|
+
window.setInterval(function () {
|
|
3779
|
+
if (document.hidden || !state.config || !state.config.settings || !state.config.settings.autoSwitch || !state.config.settings.autoSwitch.enabled) {
|
|
3780
|
+
return;
|
|
3781
|
+
}
|
|
3782
|
+
|
|
3783
|
+
refreshConfig({
|
|
3784
|
+
silent: true,
|
|
3785
|
+
}).catch(function (error) {
|
|
3786
|
+
console.warn("[admin] active profile refresh failed", error && error.message ? error.message : String(error));
|
|
3787
|
+
});
|
|
3788
|
+
}, ACTIVE_PROFILE_REFRESH_MS);
|
|
3789
|
+
}
|
|
3790
|
+
|
|
2959
3791
|
async function syncQuotaAfterProfileChange(config, sourceLabel) {
|
|
2960
3792
|
if (!config || !config.profile || config.profile.quota) {
|
|
2961
3793
|
return config;
|
|
@@ -3018,6 +3850,10 @@ function renderAdminPage() {
|
|
|
3018
3850
|
}
|
|
3019
3851
|
|
|
3020
3852
|
async function runProfileAction(action, profileId, button) {
|
|
3853
|
+
if (!confirmQuotaSwitch(action, profileId)) {
|
|
3854
|
+
return;
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3021
3857
|
if (action === "export") {
|
|
3022
3858
|
await exportProfile(profileId, button);
|
|
3023
3859
|
return;
|
|
@@ -3075,7 +3911,7 @@ function renderAdminPage() {
|
|
|
3075
3911
|
const config = result.config || await fetchJson("/_gateway/admin/config");
|
|
3076
3912
|
renderConfig(config);
|
|
3077
3913
|
const codex = result.codex || config.codex || {};
|
|
3078
|
-
authStatus.textContent = "\u5DF2\u5E94\u7528\u5230 Codex\u3002\
|
|
3914
|
+
authStatus.textContent = "\u5DF2\u5E94\u7528\u5230 Codex\u3002\u8BF7\u5173\u95ED Codex \u5E94\u7528\u5E76\u91CD\u65B0\u6253\u5F00\u540E\u751F\u6548\u3002"
|
|
3079
3915
|
+ (codex.backupPath ? " \u5DF2\u5907\u4EFD\u539F auth.json\u3002" : "");
|
|
3080
3916
|
} catch (error) {
|
|
3081
3917
|
authStatus.textContent = error.message;
|
|
@@ -3194,11 +4030,15 @@ function renderAdminPage() {
|
|
|
3194
4030
|
});
|
|
3195
4031
|
}
|
|
3196
4032
|
|
|
3197
|
-
async function
|
|
3198
|
-
const button = document.getElementById("saveModelBtn");
|
|
4033
|
+
async function saveSettings() {
|
|
3199
4034
|
const select = document.getElementById("defaultModel");
|
|
3200
|
-
|
|
3201
|
-
|
|
4035
|
+
const savedProxy = state.config && state.config.settings && state.config.settings.networkProxy
|
|
4036
|
+
? state.config.settings.networkProxy
|
|
4037
|
+
: { url: "", noProxy: "localhost,127.0.0.1,::1" };
|
|
4038
|
+
const nextProxyUrl = proxyUrl.value.trim() || (!proxyEnabled.checked ? savedProxy.url || "" : "");
|
|
4039
|
+
setBusy(saveSettingsBtn, true);
|
|
4040
|
+
settingsStatus.textContent = "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E...";
|
|
4041
|
+
authStatus.textContent = "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E...";
|
|
3202
4042
|
try {
|
|
3203
4043
|
const config = await fetchJson("/_gateway/admin/settings", {
|
|
3204
4044
|
method: "PUT",
|
|
@@ -3207,24 +4047,36 @@ function renderAdminPage() {
|
|
|
3207
4047
|
},
|
|
3208
4048
|
body: formatJson({
|
|
3209
4049
|
defaultModel: select.value,
|
|
4050
|
+
networkProxy: {
|
|
4051
|
+
enabled: proxyEnabled.checked,
|
|
4052
|
+
url: nextProxyUrl,
|
|
4053
|
+
noProxy: proxyNoProxy.value,
|
|
4054
|
+
},
|
|
4055
|
+
autoSwitch: {
|
|
4056
|
+
enabled: autoSwitchEnabled.checked,
|
|
4057
|
+
},
|
|
3210
4058
|
}),
|
|
3211
4059
|
});
|
|
4060
|
+
state.settingsDirty = false;
|
|
3212
4061
|
renderConfig(config);
|
|
3213
|
-
|
|
4062
|
+
settingsStatus.textContent = "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002";
|
|
4063
|
+
authStatus.textContent = "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002";
|
|
3214
4064
|
} catch (error) {
|
|
3215
|
-
|
|
4065
|
+
const message = error && error.message ? error.message : String(error);
|
|
4066
|
+
settingsStatus.textContent = message;
|
|
4067
|
+
authStatus.textContent = message;
|
|
3216
4068
|
} finally {
|
|
3217
|
-
setBusy(
|
|
4069
|
+
setBusy(saveSettingsBtn, false);
|
|
3218
4070
|
}
|
|
3219
4071
|
}
|
|
3220
4072
|
|
|
3221
|
-
async function
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
authStatus.textContent = "\u6B63\u5728\
|
|
4073
|
+
async function testProxy() {
|
|
4074
|
+
setBusy(testProxyBtn, true);
|
|
4075
|
+
settingsStatus.textContent = "\u6B63\u5728\u6D4B\u8BD5\u4EE3\u7406\u8FDE\u63A5...";
|
|
4076
|
+
authStatus.textContent = "\u6B63\u5728\u6D4B\u8BD5\u4EE3\u7406\u8FDE\u63A5...";
|
|
3225
4077
|
try {
|
|
3226
|
-
const
|
|
3227
|
-
method: "
|
|
4078
|
+
const result = await fetchJson("/_gateway/admin/settings/proxy-test", {
|
|
4079
|
+
method: "POST",
|
|
3228
4080
|
headers: {
|
|
3229
4081
|
"Content-Type": "application/json",
|
|
3230
4082
|
},
|
|
@@ -3236,18 +4088,23 @@ function renderAdminPage() {
|
|
|
3236
4088
|
},
|
|
3237
4089
|
}),
|
|
3238
4090
|
});
|
|
3239
|
-
|
|
3240
|
-
|
|
4091
|
+
const message = "\u4EE3\u7406\u6D4B\u8BD5\u901A\u8FC7: HTTP " + String(result.status)
|
|
4092
|
+
+ "\uFF0C\u8017\u65F6 " + String(result.elapsedMs) + " ms\u3002";
|
|
4093
|
+
settingsStatus.textContent = message;
|
|
4094
|
+
authStatus.textContent = message;
|
|
3241
4095
|
} catch (error) {
|
|
3242
|
-
|
|
4096
|
+
const message = "\u4EE3\u7406\u6D4B\u8BD5\u5931\u8D25: " + (error && error.message ? error.message : String(error));
|
|
4097
|
+
settingsStatus.textContent = message;
|
|
4098
|
+
authStatus.textContent = message;
|
|
3243
4099
|
} finally {
|
|
3244
|
-
setBusy(
|
|
4100
|
+
setBusy(testProxyBtn, false);
|
|
3245
4101
|
}
|
|
3246
4102
|
}
|
|
3247
4103
|
|
|
3248
4104
|
async function refreshModels() {
|
|
3249
4105
|
const button = document.getElementById("refreshModelsBtn");
|
|
3250
4106
|
setBusy(button, true);
|
|
4107
|
+
settingsStatus.textContent = "\u6B63\u5728\u540C\u6B65 Codex \u6A21\u578B\u5217\u8868...";
|
|
3251
4108
|
authStatus.textContent = "\u6B63\u5728\u540C\u6B65 Codex \u6A21\u578B\u5217\u8868...";
|
|
3252
4109
|
try {
|
|
3253
4110
|
await fetchJson("/_gateway/models/refresh", {
|
|
@@ -3255,9 +4112,12 @@ function renderAdminPage() {
|
|
|
3255
4112
|
});
|
|
3256
4113
|
const config = await fetchJson("/_gateway/admin/config");
|
|
3257
4114
|
renderConfig(config);
|
|
4115
|
+
settingsStatus.textContent = "Codex \u6A21\u578B\u5217\u8868\u5DF2\u540C\u6B65\u3002";
|
|
3258
4116
|
authStatus.textContent = "Codex \u6A21\u578B\u5217\u8868\u5DF2\u540C\u6B65\u3002";
|
|
3259
4117
|
} catch (error) {
|
|
3260
|
-
|
|
4118
|
+
const message = error && error.message ? error.message : String(error);
|
|
4119
|
+
settingsStatus.textContent = message;
|
|
4120
|
+
authStatus.textContent = message;
|
|
3261
4121
|
} finally {
|
|
3262
4122
|
setBusy(button, false);
|
|
3263
4123
|
}
|
|
@@ -3278,6 +4138,7 @@ function renderAdminPage() {
|
|
|
3278
4138
|
const meta = endpointMeta[endpoint];
|
|
3279
4139
|
const button = document.getElementById("runTestBtn");
|
|
3280
4140
|
const tracker = createTimingTracker();
|
|
4141
|
+
const initialProfileId = state.config && state.config.profile ? state.config.profile.profileId : "";
|
|
3281
4142
|
setBusy(button, true);
|
|
3282
4143
|
setTesterResultTab("response");
|
|
3283
4144
|
testerMeta.textContent = "\u8BF7\u6C42\u4E2D: " + meta.method + " " + endpoint;
|
|
@@ -3359,6 +4220,13 @@ function renderAdminPage() {
|
|
|
3359
4220
|
testerMeta.textContent = "\u8BF7\u6C42\u5931\u8D25";
|
|
3360
4221
|
clearPreview();
|
|
3361
4222
|
} finally {
|
|
4223
|
+
if (initialProfileId) {
|
|
4224
|
+
await refreshConfig({
|
|
4225
|
+
silent: true,
|
|
4226
|
+
}).catch(function (error) {
|
|
4227
|
+
console.warn("[admin] refresh after gateway request failed", error && error.message ? error.message : String(error));
|
|
4228
|
+
});
|
|
4229
|
+
}
|
|
3362
4230
|
setBusy(button, false);
|
|
3363
4231
|
}
|
|
3364
4232
|
}
|
|
@@ -3392,7 +4260,27 @@ function renderAdminPage() {
|
|
|
3392
4260
|
contactModal.setAttribute("aria-hidden", "true");
|
|
3393
4261
|
}
|
|
3394
4262
|
|
|
4263
|
+
function openSettingsDrawer() {
|
|
4264
|
+
if (state.config && !state.settingsDirty) {
|
|
4265
|
+
renderSettingsFields(state.config, {
|
|
4266
|
+
force: true,
|
|
4267
|
+
});
|
|
4268
|
+
}
|
|
4269
|
+
settingsDrawerBackdrop.classList.add("is-open");
|
|
4270
|
+
settingsDrawerBackdrop.setAttribute("aria-hidden", "false");
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
function closeSettingsDrawer() {
|
|
4274
|
+
resetSettingsDraft();
|
|
4275
|
+
settingsDrawerBackdrop.classList.remove("is-open");
|
|
4276
|
+
settingsDrawerBackdrop.setAttribute("aria-hidden", "true");
|
|
4277
|
+
}
|
|
4278
|
+
|
|
3395
4279
|
document.getElementById("loginBtn").addEventListener("click", openAccountModal);
|
|
4280
|
+
document.getElementById("openSettingsBtn").addEventListener("click", openSettingsDrawer);
|
|
4281
|
+
document.querySelectorAll("[data-open-settings]").forEach(function (button) {
|
|
4282
|
+
button.addEventListener("click", openSettingsDrawer);
|
|
4283
|
+
});
|
|
3396
4284
|
document.getElementById("refreshBtn").addEventListener("click", function () {
|
|
3397
4285
|
authStatus.textContent = "\u6B63\u5728\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001...";
|
|
3398
4286
|
refreshConfig({
|
|
@@ -3412,9 +4300,14 @@ function renderAdminPage() {
|
|
|
3412
4300
|
contactBtn.addEventListener("click", openContactModal);
|
|
3413
4301
|
document.getElementById("closeContactBtn").addEventListener("click", closeContactModal);
|
|
3414
4302
|
document.getElementById("closeImagePreviewBtn").addEventListener("click", closeImagePreviewModal);
|
|
4303
|
+
document.getElementById("closeSettingsDrawerBtn").addEventListener("click", closeSettingsDrawer);
|
|
3415
4304
|
document.getElementById("refreshModelsBtn").addEventListener("click", refreshModels);
|
|
3416
|
-
|
|
3417
|
-
|
|
4305
|
+
testProxyBtn.addEventListener("click", testProxy);
|
|
4306
|
+
saveSettingsBtn.addEventListener("click", saveSettings);
|
|
4307
|
+
[document.getElementById("defaultModel"), proxyEnabled, proxyUrl, proxyNoProxy, autoSwitchEnabled].forEach(function (element) {
|
|
4308
|
+
element.addEventListener("input", markSettingsDirty);
|
|
4309
|
+
element.addEventListener("change", markSettingsDirty);
|
|
4310
|
+
});
|
|
3418
4311
|
runTestBtn.addEventListener("click", runTest);
|
|
3419
4312
|
document.querySelectorAll("[data-result-tab]").forEach(function (button) {
|
|
3420
4313
|
button.addEventListener("click", function () {
|
|
@@ -3445,6 +4338,18 @@ function renderAdminPage() {
|
|
|
3445
4338
|
return;
|
|
3446
4339
|
}
|
|
3447
4340
|
|
|
4341
|
+
if (action === "toggle-details") {
|
|
4342
|
+
if (state.expandedProfileIds[profileId]) {
|
|
4343
|
+
delete state.expandedProfileIds[profileId];
|
|
4344
|
+
} else {
|
|
4345
|
+
state.expandedProfileIds[profileId] = true;
|
|
4346
|
+
}
|
|
4347
|
+
if (state.config) {
|
|
4348
|
+
renderProfiles(state.config);
|
|
4349
|
+
}
|
|
4350
|
+
return;
|
|
4351
|
+
}
|
|
4352
|
+
|
|
3448
4353
|
runProfileAction(action, profileId, button);
|
|
3449
4354
|
});
|
|
3450
4355
|
|
|
@@ -3544,6 +4449,12 @@ function renderAdminPage() {
|
|
|
3544
4449
|
}
|
|
3545
4450
|
});
|
|
3546
4451
|
|
|
4452
|
+
settingsDrawerBackdrop.addEventListener("click", function (event) {
|
|
4453
|
+
if (event.target === settingsDrawerBackdrop) {
|
|
4454
|
+
closeSettingsDrawer();
|
|
4455
|
+
}
|
|
4456
|
+
});
|
|
4457
|
+
|
|
3547
4458
|
imagePreviewModal.addEventListener("click", function (event) {
|
|
3548
4459
|
if (event.target === imagePreviewModal) {
|
|
3549
4460
|
closeImagePreviewModal();
|
|
@@ -3560,10 +4471,14 @@ function renderAdminPage() {
|
|
|
3560
4471
|
if (event.key === "Escape" && accountModal.classList.contains("is-open")) {
|
|
3561
4472
|
closeAccountModal();
|
|
3562
4473
|
}
|
|
4474
|
+
if (event.key === "Escape" && settingsDrawerBackdrop.classList.contains("is-open")) {
|
|
4475
|
+
closeSettingsDrawer();
|
|
4476
|
+
}
|
|
3563
4477
|
});
|
|
3564
4478
|
|
|
3565
4479
|
setTesterResultTab(state.testerResultTab);
|
|
3566
4480
|
scheduleRuntimeRefresh();
|
|
4481
|
+
scheduleActiveProfileRefresh();
|
|
3567
4482
|
refreshConfig().catch(function (error) {
|
|
3568
4483
|
authStatus.textContent = error && error.message ? error.message : String(error);
|
|
3569
4484
|
testerMeta.textContent = "\u52A0\u8F7D\u5931\u8D25";
|