ai-zero-token 1.0.2 → 1.0.3
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 +14 -0
- package/README.md +9 -0
- package/dist/cli/commands/help.js +2 -1
- package/dist/cli/commands/models.js +14 -3
- package/dist/cli/index.js +1 -1
- package/dist/core/context.js +3 -0
- package/dist/core/models/openai-codex-models.js +89 -0
- package/dist/core/providers/http-client.js +41 -6
- package/dist/core/services/auth-service.js +36 -0
- package/dist/core/services/config-service.js +4 -4
- package/dist/core/services/image-service.js +119 -74
- package/dist/core/services/model-service.js +31 -6
- package/dist/core/services/version-service.js +97 -0
- package/dist/server/admin-page.js +641 -91
- package/dist/server/app.js +40 -3
- package/docs/API_USAGE.md +120 -0
- package/package.json +3 -1
|
@@ -208,11 +208,24 @@ function renderAdminPage() {
|
|
|
208
208
|
gap: 10px;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
.service-list.compact {
|
|
212
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
213
|
+
gap: 10px 12px;
|
|
214
|
+
}
|
|
215
|
+
|
|
211
216
|
.service-row {
|
|
212
217
|
display: grid;
|
|
213
218
|
gap: 4px;
|
|
214
219
|
}
|
|
215
220
|
|
|
221
|
+
.service-row.compact {
|
|
222
|
+
padding: 10px 12px;
|
|
223
|
+
border-radius: 14px;
|
|
224
|
+
border: 1px solid var(--line);
|
|
225
|
+
background: var(--panel-soft);
|
|
226
|
+
min-width: 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
216
229
|
.service-row label {
|
|
217
230
|
color: var(--text-muted);
|
|
218
231
|
font-size: 12px;
|
|
@@ -272,6 +285,54 @@ function renderAdminPage() {
|
|
|
272
285
|
gap: 14px;
|
|
273
286
|
}
|
|
274
287
|
|
|
288
|
+
.update-panel {
|
|
289
|
+
display: none;
|
|
290
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
291
|
+
align-items: center;
|
|
292
|
+
gap: 18px;
|
|
293
|
+
padding: 18px;
|
|
294
|
+
border-radius: 18px;
|
|
295
|
+
border: 1px solid rgba(245, 158, 11, 0.32);
|
|
296
|
+
background:
|
|
297
|
+
linear-gradient(135deg, rgba(255, 247, 237, 0.98), rgba(255, 251, 235, 0.92)),
|
|
298
|
+
var(--panel);
|
|
299
|
+
box-shadow: 0 18px 42px rgba(180, 83, 9, 0.12);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.update-panel.is-visible {
|
|
303
|
+
display: grid;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.update-copy {
|
|
307
|
+
display: grid;
|
|
308
|
+
gap: 7px;
|
|
309
|
+
min-width: 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.update-copy strong {
|
|
313
|
+
color: #9a3412;
|
|
314
|
+
font-size: 16px;
|
|
315
|
+
line-height: 1.35;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.update-copy span {
|
|
319
|
+
color: #7c2d12;
|
|
320
|
+
font-size: 13px;
|
|
321
|
+
line-height: 1.55;
|
|
322
|
+
overflow-wrap: anywhere;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.update-command {
|
|
326
|
+
padding: 10px 12px;
|
|
327
|
+
border-radius: 12px;
|
|
328
|
+
border: 1px solid rgba(180, 83, 9, 0.22);
|
|
329
|
+
background: rgba(255, 255, 255, 0.78);
|
|
330
|
+
color: #7c2d12;
|
|
331
|
+
font-size: 12px;
|
|
332
|
+
line-height: 1.4;
|
|
333
|
+
white-space: nowrap;
|
|
334
|
+
}
|
|
335
|
+
|
|
275
336
|
.summary-card {
|
|
276
337
|
border-radius: 16px;
|
|
277
338
|
padding: 18px;
|
|
@@ -309,7 +370,7 @@ function renderAdminPage() {
|
|
|
309
370
|
|
|
310
371
|
.main-grid {
|
|
311
372
|
display: grid;
|
|
312
|
-
grid-template-columns: minmax(0, 1fr) minmax(
|
|
373
|
+
grid-template-columns: minmax(0, 1fr) minmax(460px, 560px);
|
|
313
374
|
gap: 20px;
|
|
314
375
|
align-items: start;
|
|
315
376
|
}
|
|
@@ -588,17 +649,33 @@ function renderAdminPage() {
|
|
|
588
649
|
|
|
589
650
|
.account-grid {
|
|
590
651
|
display: grid;
|
|
591
|
-
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
592
652
|
grid-auto-rows: 1fr;
|
|
593
653
|
gap: 16px;
|
|
654
|
+
justify-content: start;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.account-grid.profile-count-1 {
|
|
658
|
+
grid-template-columns: minmax(300px, 440px);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.account-grid.profile-count-2 {
|
|
662
|
+
grid-template-columns: repeat(2, minmax(280px, 360px));
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.account-grid.profile-count-3 {
|
|
666
|
+
grid-template-columns: repeat(3, minmax(260px, 320px));
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.account-grid.profile-count-many {
|
|
670
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 300px));
|
|
594
671
|
}
|
|
595
672
|
|
|
596
673
|
.account-card {
|
|
597
|
-
border-radius:
|
|
598
|
-
padding:
|
|
674
|
+
border-radius: 16px;
|
|
675
|
+
padding: 14px;
|
|
599
676
|
display: grid;
|
|
600
677
|
grid-template-rows: auto auto auto 1fr auto;
|
|
601
|
-
gap:
|
|
678
|
+
gap: 12px;
|
|
602
679
|
min-width: 0;
|
|
603
680
|
height: 100%;
|
|
604
681
|
}
|
|
@@ -612,34 +689,34 @@ function renderAdminPage() {
|
|
|
612
689
|
|
|
613
690
|
.account-title {
|
|
614
691
|
display: grid;
|
|
615
|
-
gap:
|
|
692
|
+
gap: 6px;
|
|
616
693
|
min-width: 0;
|
|
617
694
|
}
|
|
618
695
|
|
|
619
696
|
.account-name {
|
|
620
697
|
display: flex;
|
|
621
698
|
align-items: center;
|
|
622
|
-
gap:
|
|
699
|
+
gap: 8px;
|
|
623
700
|
min-width: 0;
|
|
624
701
|
}
|
|
625
702
|
|
|
626
703
|
.avatar {
|
|
627
|
-
width:
|
|
628
|
-
height:
|
|
704
|
+
width: 24px;
|
|
705
|
+
height: 24px;
|
|
629
706
|
border-radius: 999px;
|
|
630
707
|
background: var(--panel-soft);
|
|
631
708
|
border: 1px solid var(--line);
|
|
632
709
|
display: grid;
|
|
633
710
|
place-items: center;
|
|
634
|
-
font-size:
|
|
711
|
+
font-size: 11px;
|
|
635
712
|
color: var(--brand);
|
|
636
713
|
font-weight: 700;
|
|
637
714
|
flex: 0 0 auto;
|
|
638
715
|
}
|
|
639
716
|
|
|
640
717
|
.account-name strong {
|
|
641
|
-
font-size:
|
|
642
|
-
line-height: 1.
|
|
718
|
+
font-size: 13px;
|
|
719
|
+
line-height: 1.35;
|
|
643
720
|
min-width: 0;
|
|
644
721
|
display: -webkit-box;
|
|
645
722
|
-webkit-line-clamp: 2;
|
|
@@ -653,17 +730,17 @@ function renderAdminPage() {
|
|
|
653
730
|
.badge-row {
|
|
654
731
|
display: flex;
|
|
655
732
|
flex-wrap: wrap;
|
|
656
|
-
gap:
|
|
733
|
+
gap: 6px;
|
|
657
734
|
}
|
|
658
735
|
|
|
659
736
|
.badge {
|
|
660
737
|
display: inline-flex;
|
|
661
738
|
align-items: center;
|
|
662
739
|
justify-content: center;
|
|
663
|
-
min-height:
|
|
664
|
-
padding: 0
|
|
740
|
+
min-height: 22px;
|
|
741
|
+
padding: 0 8px;
|
|
665
742
|
border-radius: 999px;
|
|
666
|
-
font-size:
|
|
743
|
+
font-size: 11px;
|
|
667
744
|
font-weight: 600;
|
|
668
745
|
white-space: nowrap;
|
|
669
746
|
}
|
|
@@ -695,26 +772,36 @@ function renderAdminPage() {
|
|
|
695
772
|
|
|
696
773
|
.account-metrics {
|
|
697
774
|
display: grid;
|
|
698
|
-
gap:
|
|
775
|
+
gap: 10px;
|
|
699
776
|
}
|
|
700
777
|
|
|
701
778
|
.quota-row {
|
|
702
779
|
display: grid;
|
|
703
|
-
gap:
|
|
780
|
+
gap: 6px;
|
|
704
781
|
}
|
|
705
782
|
|
|
706
783
|
.quota-line {
|
|
707
784
|
display: flex;
|
|
708
785
|
align-items: center;
|
|
709
786
|
justify-content: space-between;
|
|
710
|
-
gap:
|
|
787
|
+
gap: 10px;
|
|
711
788
|
color: var(--text-soft);
|
|
789
|
+
font-size: 11px;
|
|
790
|
+
line-height: 1.45;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.quota-line span {
|
|
794
|
+
min-width: 0;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.quota-line strong {
|
|
798
|
+
flex-shrink: 0;
|
|
799
|
+
color: var(--text);
|
|
712
800
|
font-size: 12px;
|
|
713
|
-
line-height: 1.5;
|
|
714
801
|
}
|
|
715
802
|
|
|
716
803
|
.progress-track {
|
|
717
|
-
height:
|
|
804
|
+
height: 5px;
|
|
718
805
|
width: 100%;
|
|
719
806
|
border-radius: 999px;
|
|
720
807
|
background: #eef2f7;
|
|
@@ -746,26 +833,26 @@ function renderAdminPage() {
|
|
|
746
833
|
.meta-grid {
|
|
747
834
|
display: grid;
|
|
748
835
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
749
|
-
gap:
|
|
836
|
+
gap: 8px 12px;
|
|
750
837
|
}
|
|
751
838
|
|
|
752
839
|
.meta-item {
|
|
753
840
|
display: grid;
|
|
754
|
-
gap:
|
|
841
|
+
gap: 3px;
|
|
755
842
|
min-width: 0;
|
|
756
843
|
}
|
|
757
844
|
|
|
758
845
|
.meta-item label {
|
|
759
846
|
color: var(--text-muted);
|
|
760
|
-
font-size:
|
|
847
|
+
font-size: 10px;
|
|
761
848
|
line-height: 1.4;
|
|
762
849
|
}
|
|
763
850
|
|
|
764
851
|
.meta-item strong,
|
|
765
852
|
.meta-item span,
|
|
766
853
|
.meta-item code {
|
|
767
|
-
font-size:
|
|
768
|
-
line-height: 1.
|
|
854
|
+
font-size: 11px;
|
|
855
|
+
line-height: 1.45;
|
|
769
856
|
color: var(--text-soft);
|
|
770
857
|
word-break: break-word;
|
|
771
858
|
overflow-wrap: anywhere;
|
|
@@ -774,13 +861,30 @@ function renderAdminPage() {
|
|
|
774
861
|
.account-actions {
|
|
775
862
|
display: flex;
|
|
776
863
|
flex-wrap: wrap;
|
|
777
|
-
gap:
|
|
864
|
+
gap: 8px;
|
|
778
865
|
margin-top: auto;
|
|
779
866
|
}
|
|
780
867
|
|
|
781
868
|
.account-actions .btn-secondary,
|
|
782
869
|
.account-actions .btn-danger {
|
|
783
870
|
flex: 1 1 120px;
|
|
871
|
+
min-height: 36px;
|
|
872
|
+
padding: 0 12px;
|
|
873
|
+
border-radius: 10px;
|
|
874
|
+
font-size: 12px;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
.account-status {
|
|
878
|
+
display: inline-flex;
|
|
879
|
+
align-items: center;
|
|
880
|
+
min-height: 36px;
|
|
881
|
+
padding: 0 12px;
|
|
882
|
+
border-radius: 10px;
|
|
883
|
+
background: var(--panel-soft);
|
|
884
|
+
border: 1px solid var(--line);
|
|
885
|
+
color: var(--text-muted);
|
|
886
|
+
font-size: 12px;
|
|
887
|
+
font-weight: 600;
|
|
784
888
|
}
|
|
785
889
|
|
|
786
890
|
.empty-state {
|
|
@@ -889,7 +993,8 @@ function renderAdminPage() {
|
|
|
889
993
|
.pre {
|
|
890
994
|
margin: 0;
|
|
891
995
|
padding: 14px;
|
|
892
|
-
min-height:
|
|
996
|
+
min-height: 280px;
|
|
997
|
+
max-height: 460px;
|
|
893
998
|
overflow: auto;
|
|
894
999
|
background: #0f172a;
|
|
895
1000
|
border-color: #0f172a;
|
|
@@ -908,9 +1013,44 @@ function renderAdminPage() {
|
|
|
908
1013
|
line-height: 1.6;
|
|
909
1014
|
}
|
|
910
1015
|
|
|
1016
|
+
.tester-result {
|
|
1017
|
+
display: grid;
|
|
1018
|
+
gap: 12px;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
.tester-result-tabs {
|
|
1022
|
+
display: flex;
|
|
1023
|
+
flex-wrap: wrap;
|
|
1024
|
+
gap: 8px;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.tester-result-tabs .tab-btn {
|
|
1028
|
+
border: 1px solid var(--line);
|
|
1029
|
+
background: #fff;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.tester-panel {
|
|
1033
|
+
display: none;
|
|
1034
|
+
gap: 12px;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
.tester-panel.is-active {
|
|
1038
|
+
display: grid;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
.preview-empty {
|
|
1042
|
+
border: 1px dashed var(--line-strong);
|
|
1043
|
+
border-radius: 14px;
|
|
1044
|
+
padding: 18px;
|
|
1045
|
+
background: var(--panel-soft);
|
|
1046
|
+
color: var(--text-muted);
|
|
1047
|
+
font-size: 13px;
|
|
1048
|
+
line-height: 1.7;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
911
1051
|
.preview-grid {
|
|
912
1052
|
display: grid;
|
|
913
|
-
grid-template-columns: repeat(auto-fit, minmax(
|
|
1053
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
914
1054
|
gap: 12px;
|
|
915
1055
|
}
|
|
916
1056
|
|
|
@@ -927,11 +1067,12 @@ function renderAdminPage() {
|
|
|
927
1067
|
.preview-card img {
|
|
928
1068
|
display: block;
|
|
929
1069
|
width: 100%;
|
|
930
|
-
aspect-ratio:
|
|
931
|
-
object-fit:
|
|
1070
|
+
aspect-ratio: 4 / 3;
|
|
1071
|
+
object-fit: contain;
|
|
932
1072
|
border-radius: 10px;
|
|
933
1073
|
border: 1px solid var(--line);
|
|
934
1074
|
background: var(--panel-soft);
|
|
1075
|
+
cursor: zoom-in;
|
|
935
1076
|
}
|
|
936
1077
|
|
|
937
1078
|
.preview-card figcaption {
|
|
@@ -961,6 +1102,48 @@ function renderAdminPage() {
|
|
|
961
1102
|
font-weight: 600;
|
|
962
1103
|
}
|
|
963
1104
|
|
|
1105
|
+
.preview-modal-card {
|
|
1106
|
+
width: min(1120px, calc(100vw - 32px));
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.preview-modal-body {
|
|
1110
|
+
padding: 18px 20px 20px;
|
|
1111
|
+
display: grid;
|
|
1112
|
+
gap: 16px;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
.preview-modal-stage {
|
|
1116
|
+
display: grid;
|
|
1117
|
+
place-items: center;
|
|
1118
|
+
min-height: 420px;
|
|
1119
|
+
max-height: calc(100vh - 240px);
|
|
1120
|
+
overflow: auto;
|
|
1121
|
+
border: 1px solid var(--line);
|
|
1122
|
+
border-radius: 20px;
|
|
1123
|
+
background:
|
|
1124
|
+
linear-gradient(135deg, rgba(99, 91, 255, 0.06), transparent 42%),
|
|
1125
|
+
var(--panel-soft);
|
|
1126
|
+
padding: 16px;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
.preview-modal-stage img {
|
|
1130
|
+
display: block;
|
|
1131
|
+
max-width: 100%;
|
|
1132
|
+
max-height: calc(100vh - 280px);
|
|
1133
|
+
width: auto;
|
|
1134
|
+
height: auto;
|
|
1135
|
+
border-radius: 14px;
|
|
1136
|
+
background: #fff;
|
|
1137
|
+
box-shadow: var(--shadow);
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
.preview-modal-meta {
|
|
1141
|
+
color: var(--text-soft);
|
|
1142
|
+
font-size: 13px;
|
|
1143
|
+
line-height: 1.7;
|
|
1144
|
+
word-break: break-word;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
964
1147
|
.log-table-wrap {
|
|
965
1148
|
border-radius: 20px;
|
|
966
1149
|
overflow: hidden;
|
|
@@ -1061,6 +1244,11 @@ function renderAdminPage() {
|
|
|
1061
1244
|
|
|
1062
1245
|
.summary-grid,
|
|
1063
1246
|
.account-grid,
|
|
1247
|
+
.account-grid.profile-count-1,
|
|
1248
|
+
.account-grid.profile-count-2,
|
|
1249
|
+
.account-grid.profile-count-3,
|
|
1250
|
+
.account-grid.profile-count-many,
|
|
1251
|
+
.preview-grid,
|
|
1064
1252
|
.meta-grid,
|
|
1065
1253
|
.trend-labels {
|
|
1066
1254
|
grid-template-columns: 1fr;
|
|
@@ -1150,13 +1338,21 @@ function renderAdminPage() {
|
|
|
1150
1338
|
<div class="top-actions">
|
|
1151
1339
|
<a class="btn-link" href="https://github.com/fchangjun/AI-Zero-Token" target="_blank" rel="noreferrer">GitHub \u4ED3\u5E93</a>
|
|
1152
1340
|
<button class="btn-secondary" id="contactBtn" type="button">\u4EA4\u6D41\u53CD\u9988</button>
|
|
1153
|
-
<button class="btn-secondary" id="toggleEmailBtn" type="button">\
|
|
1341
|
+
<button class="btn-secondary" id="toggleEmailBtn" type="button">\u8131\u654F\u6A21\u5F0F</button>
|
|
1154
1342
|
<button class="btn-primary" id="loginBtn" type="button">+ \u65B0\u589E\u8D26\u53F7</button>
|
|
1155
1343
|
<button class="btn-secondary" id="refreshBtn" type="button">\u5237\u65B0\u72B6\u6001</button>
|
|
1156
1344
|
<button class="btn-danger" id="logoutBtn" type="button">\u6E05\u7A7A\u8D26\u53F7</button>
|
|
1157
1345
|
</div>
|
|
1158
1346
|
</header>
|
|
1159
1347
|
|
|
1348
|
+
<section class="update-panel" id="updatePanel" aria-live="polite">
|
|
1349
|
+
<div class="update-copy">
|
|
1350
|
+
<strong id="updatePanelTitle">\u53D1\u73B0\u65B0\u7248\u672C</strong>
|
|
1351
|
+
<span id="updatePanelDetail"></span>
|
|
1352
|
+
</div>
|
|
1353
|
+
<code class="update-command" id="updatePanelCommand">npm install -g ai-zero-token@latest</code>
|
|
1354
|
+
</section>
|
|
1355
|
+
|
|
1160
1356
|
<section class="summary-grid" id="summaryGrid"></section>
|
|
1161
1357
|
|
|
1162
1358
|
<section class="main-grid">
|
|
@@ -1183,7 +1379,7 @@ function renderAdminPage() {
|
|
|
1183
1379
|
</select>
|
|
1184
1380
|
<select class="control" id="profileSort">
|
|
1185
1381
|
<option value="quota-desc">\u6309\u4E3B\u989D\u5EA6\u6392\u5E8F</option>
|
|
1186
|
-
<option value="latency-asc">\u6309\
|
|
1382
|
+
<option value="latency-asc">\u6309\u989D\u5EA6\u66F4\u65B0\u65F6\u95F4</option>
|
|
1187
1383
|
<option value="expiry-asc">\u6309\u8FC7\u671F\u65F6\u95F4</option>
|
|
1188
1384
|
<option value="name-asc">\u6309\u90AE\u7BB1\u6392\u5E8F</option>
|
|
1189
1385
|
</select>
|
|
@@ -1262,7 +1458,9 @@ function renderAdminPage() {
|
|
|
1262
1458
|
<label for="defaultModel">\u9ED8\u8BA4\u6A21\u578B</label>
|
|
1263
1459
|
<select class="control" id="defaultModel"></select>
|
|
1264
1460
|
<p class="hint">\u5207\u6362\u540E\u4F1A\u5F71\u54CD\u672A\u663E\u5F0F\u4F20 <code>model</code> \u7684\u8BF7\u6C42\u3002</p>
|
|
1461
|
+
<p class="hint" id="modelCatalogHint"></p>
|
|
1265
1462
|
<div class="actions">
|
|
1463
|
+
<button class="btn-secondary" id="refreshModelsBtn" type="button">\u540C\u6B65 Codex \u6A21\u578B</button>
|
|
1266
1464
|
<button class="btn-primary" id="saveModelBtn" type="button">\u4FDD\u5B58\u9ED8\u8BA4\u6A21\u578B</button>
|
|
1267
1465
|
</div>
|
|
1268
1466
|
</div>
|
|
@@ -1284,33 +1482,72 @@ function renderAdminPage() {
|
|
|
1284
1482
|
|
|
1285
1483
|
<p class="status-inline" id="authStatus"></p>
|
|
1286
1484
|
|
|
1287
|
-
<div class="
|
|
1288
|
-
<
|
|
1289
|
-
|
|
1290
|
-
|
|
1485
|
+
<div class="tester-result">
|
|
1486
|
+
<div class="tester-result-tabs">
|
|
1487
|
+
<button class="tab-btn is-active" type="button" data-result-tab="response">\u54CD\u5E94 JSON</button>
|
|
1488
|
+
<button class="tab-btn" type="button" data-result-tab="timing">\u8017\u65F6\u65E5\u5FD7</button>
|
|
1489
|
+
<button class="tab-btn" type="button" data-result-tab="preview">\u56FE\u7247\u9884\u89C8</button>
|
|
1490
|
+
</div>
|
|
1291
1491
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1492
|
+
<div class="tester-panel is-active" data-result-panel="response">
|
|
1493
|
+
<div class="field">
|
|
1494
|
+
<label for="responseBody">\u54CD\u5E94\u7ED3\u679C</label>
|
|
1495
|
+
<pre class="pre" id="responseBody">\u7B49\u5F85\u8BF7\u6C42\u2026</pre>
|
|
1496
|
+
</div>
|
|
1497
|
+
</div>
|
|
1296
1498
|
|
|
1297
|
-
|
|
1499
|
+
<div class="tester-panel" data-result-panel="timing">
|
|
1500
|
+
<div class="field">
|
|
1501
|
+
<label for="timingBody">\u8017\u65F6\u65E5\u5FD7</label>
|
|
1502
|
+
<pre class="pre" id="timingBody">\u7B49\u5F85\u8BF7\u6C42\u2026</pre>
|
|
1503
|
+
</div>
|
|
1504
|
+
</div>
|
|
1505
|
+
|
|
1506
|
+
<div class="tester-panel" data-result-panel="preview">
|
|
1507
|
+
<div class="field">
|
|
1508
|
+
<label>\u56FE\u7247\u9884\u89C8</label>
|
|
1509
|
+
<div class="preview-empty" id="responsePreviewEmpty">\u56FE\u7247\u7ED3\u679C\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002\u70B9\u51FB\u7F29\u7565\u56FE\u53EF\u67E5\u770B\u5927\u56FE\u3002</div>
|
|
1510
|
+
<div class="preview-grid" id="responsePreview"></div>
|
|
1511
|
+
</div>
|
|
1512
|
+
</div>
|
|
1513
|
+
</div>
|
|
1298
1514
|
</section>
|
|
1299
1515
|
|
|
1300
|
-
<section class="card">
|
|
1516
|
+
<section class="card service-card">
|
|
1301
1517
|
<div class="section-head" style="margin-bottom: 12px;">
|
|
1302
1518
|
<div>
|
|
1303
|
-
<h2>\u63A5\
|
|
1519
|
+
<h2>\u8FDE\u63A5\u4FE1\u606F</h2>
|
|
1304
1520
|
<p>\u7BA1\u7406\u9875\u548C API Base \u53EF\u76F4\u63A5\u590D\u5236\u5230 SDK \u6216\u6D4B\u8BD5\u5DE5\u5177\u3002</p>
|
|
1305
1521
|
</div>
|
|
1306
1522
|
</div>
|
|
1307
|
-
<div class="service-list" id="endpointInfo"></div>
|
|
1523
|
+
<div class="service-list compact" id="endpointInfo"></div>
|
|
1308
1524
|
</section>
|
|
1309
1525
|
</aside>
|
|
1310
1526
|
</section>
|
|
1311
1527
|
</main>
|
|
1312
1528
|
</div>
|
|
1313
1529
|
|
|
1530
|
+
<div class="modal-backdrop" id="imagePreviewModal" aria-hidden="true">
|
|
1531
|
+
<section class="modal-card preview-modal-card" role="dialog" aria-modal="true" aria-labelledby="imagePreviewTitle">
|
|
1532
|
+
<div class="modal-head">
|
|
1533
|
+
<div>
|
|
1534
|
+
<h3 id="imagePreviewTitle">\u56FE\u7247\u9884\u89C8</h3>
|
|
1535
|
+
<p>\u67E5\u770B\u751F\u56FE\u7ED3\u679C\u7684\u66F4\u5927\u7248\u672C\uFF0C\u907F\u514D\u5728\u4FA7\u680F\u5185\u6EDA\u52A8\u67E5\u770B\u3002</p>
|
|
1536
|
+
</div>
|
|
1537
|
+
<div class="actions">
|
|
1538
|
+
<a class="btn-secondary" id="downloadPreviewBtn" href="#" download="generated-image.png">\u4E0B\u8F7D\u56FE\u7247</a>
|
|
1539
|
+
<button class="btn-secondary" id="closeImagePreviewBtn" type="button">\u5173\u95ED</button>
|
|
1540
|
+
</div>
|
|
1541
|
+
</div>
|
|
1542
|
+
<div class="preview-modal-body">
|
|
1543
|
+
<div class="preview-modal-stage">
|
|
1544
|
+
<img id="previewModalImage" src="" alt="\u751F\u6210\u56FE\u7247\u9884\u89C8" />
|
|
1545
|
+
</div>
|
|
1546
|
+
<div class="preview-modal-meta" id="previewModalMeta">\u7B49\u5F85\u56FE\u7247\u7ED3\u679C\u2026</div>
|
|
1547
|
+
</div>
|
|
1548
|
+
</section>
|
|
1549
|
+
</div>
|
|
1550
|
+
|
|
1314
1551
|
<div class="modal-backdrop" id="contactModal" aria-hidden="true">
|
|
1315
1552
|
<section class="modal-card" role="dialog" aria-modal="true" aria-labelledby="contactModalTitle">
|
|
1316
1553
|
<div class="modal-head">
|
|
@@ -1344,6 +1581,8 @@ function renderAdminPage() {
|
|
|
1344
1581
|
</div>
|
|
1345
1582
|
|
|
1346
1583
|
<script>
|
|
1584
|
+
const RUNTIME_AUTO_REFRESH_MS = 10 * 60 * 1000;
|
|
1585
|
+
|
|
1347
1586
|
const state = {
|
|
1348
1587
|
config: null,
|
|
1349
1588
|
recentRequests: [],
|
|
@@ -1353,6 +1592,7 @@ function renderAdminPage() {
|
|
|
1353
1592
|
status: "all",
|
|
1354
1593
|
sort: "quota-desc",
|
|
1355
1594
|
},
|
|
1595
|
+
testerResultTab: "response",
|
|
1356
1596
|
};
|
|
1357
1597
|
|
|
1358
1598
|
const endpointMeta = {
|
|
@@ -1382,6 +1622,7 @@ function renderAdminPage() {
|
|
|
1382
1622
|
const requestBody = document.getElementById("requestBody");
|
|
1383
1623
|
const responseBody = document.getElementById("responseBody");
|
|
1384
1624
|
const responsePreview = document.getElementById("responsePreview");
|
|
1625
|
+
const responsePreviewEmpty = document.getElementById("responsePreviewEmpty");
|
|
1385
1626
|
const timingBody = document.getElementById("timingBody");
|
|
1386
1627
|
const testerMeta = document.getElementById("testerMeta");
|
|
1387
1628
|
const authStatus = document.getElementById("authStatus");
|
|
@@ -1389,7 +1630,11 @@ function renderAdminPage() {
|
|
|
1389
1630
|
const runTestBtn = document.getElementById("runTestBtn");
|
|
1390
1631
|
const toggleEmailBtn = document.getElementById("toggleEmailBtn");
|
|
1391
1632
|
const contactModal = document.getElementById("contactModal");
|
|
1633
|
+
const imagePreviewModal = document.getElementById("imagePreviewModal");
|
|
1392
1634
|
const contactBtn = document.getElementById("contactBtn");
|
|
1635
|
+
const previewModalImage = document.getElementById("previewModalImage");
|
|
1636
|
+
const previewModalMeta = document.getElementById("previewModalMeta");
|
|
1637
|
+
const downloadPreviewBtn = document.getElementById("downloadPreviewBtn");
|
|
1393
1638
|
const profileSearch = document.getElementById("profileSearch");
|
|
1394
1639
|
const profileStatusFilter = document.getElementById("profileStatusFilter");
|
|
1395
1640
|
const profileSort = document.getElementById("profileSort");
|
|
@@ -1496,6 +1741,81 @@ function renderAdminPage() {
|
|
|
1496
1741
|
: "unknown";
|
|
1497
1742
|
}
|
|
1498
1743
|
|
|
1744
|
+
function getQuotaSnapshotTime(profile) {
|
|
1745
|
+
return profile && profile.quota && typeof profile.quota.capturedAt === "number"
|
|
1746
|
+
? profile.quota.capturedAt
|
|
1747
|
+
: 0;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
function describeQuotaSnapshot(profile) {
|
|
1751
|
+
const capturedAt = getQuotaSnapshotTime(profile);
|
|
1752
|
+
return capturedAt > 0 ? formatTime(capturedAt) : "\u672A\u540C\u6B65";
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
function describeQuotaLimit(profile) {
|
|
1756
|
+
const quota = profile && profile.quota ? profile.quota : null;
|
|
1757
|
+
if (!quota) {
|
|
1758
|
+
return "\u7B49\u5F85\u5237\u65B0\u989D\u5EA6";
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
const parts = [];
|
|
1762
|
+
if (typeof quota.activeLimit === "string" && quota.activeLimit) {
|
|
1763
|
+
parts.push(quota.activeLimit);
|
|
1764
|
+
}
|
|
1765
|
+
if (typeof quota.creditsBalance === "string" && quota.creditsBalance) {
|
|
1766
|
+
parts.push("\u4F59\u989D " + quota.creditsBalance);
|
|
1767
|
+
}
|
|
1768
|
+
if (typeof quota.primaryOverSecondaryLimitPercent === "number") {
|
|
1769
|
+
parts.push("\u5171\u4EAB\u4E0A\u9650 " + Math.round(quota.primaryOverSecondaryLimitPercent) + "%");
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
return parts.length > 0 ? parts.join(" \xB7 ") : "\u6765\u81EA Codex \u54CD\u5E94\u5934";
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
function getVersionValue(config) {
|
|
1776
|
+
if (!config || !config.versionStatus) {
|
|
1777
|
+
return "--";
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
return config.versionStatus.currentVersion || "--";
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
function getVersionDetail(config) {
|
|
1784
|
+
if (!config || !config.versionStatus) {
|
|
1785
|
+
return "\u7248\u672C\u72B6\u6001\u672A\u77E5";
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
const versionStatus = config.versionStatus;
|
|
1789
|
+
if (versionStatus.status === "update-available" && versionStatus.latestVersion) {
|
|
1790
|
+
return "\u53EF\u66F4\u65B0\u5230 " + versionStatus.latestVersion;
|
|
1791
|
+
}
|
|
1792
|
+
if (versionStatus.status === "ok" && versionStatus.latestVersion) {
|
|
1793
|
+
return "\u5DF2\u68C0\u67E5\uFF0C\u5F53\u524D\u5DF2\u662F\u6700\u65B0\u7248\u672C";
|
|
1794
|
+
}
|
|
1795
|
+
return versionStatus.error
|
|
1796
|
+
? "\u7248\u672C\u68C0\u67E5\u5931\u8D25: " + versionStatus.error
|
|
1797
|
+
: "\u6682\u672A\u62FF\u5230\u8FDC\u7AEF\u7248\u672C\u4FE1\u606F";
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
function renderUpdatePanel(config) {
|
|
1801
|
+
const panel = document.getElementById("updatePanel");
|
|
1802
|
+
const title = document.getElementById("updatePanelTitle");
|
|
1803
|
+
const detail = document.getElementById("updatePanelDetail");
|
|
1804
|
+
const command = document.getElementById("updatePanelCommand");
|
|
1805
|
+
const versionStatus = config && config.versionStatus ? config.versionStatus : null;
|
|
1806
|
+
|
|
1807
|
+
if (!versionStatus || !versionStatus.needsUpdate || !versionStatus.latestVersion) {
|
|
1808
|
+
panel.classList.remove("is-visible");
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
title.textContent = "\u53D1\u73B0\u65B0\u7248\u672C\u53EF\u66F4\u65B0";
|
|
1813
|
+
detail.textContent = "\u5F53\u524D\u7248\u672C " + versionStatus.currentVersion + "\uFF0C\u6700\u65B0\u7248\u672C "
|
|
1814
|
+
+ 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";
|
|
1815
|
+
command.textContent = "npm install -g " + versionStatus.packageName + "@latest";
|
|
1816
|
+
panel.classList.add("is-visible");
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1499
1819
|
function supportsImageGeneration(profile) {
|
|
1500
1820
|
return getPlanType(profile) !== "free";
|
|
1501
1821
|
}
|
|
@@ -1547,6 +1867,23 @@ function renderAdminPage() {
|
|
|
1547
1867
|
return local.slice(0, 2) + "***" + local.slice(-1) + "@" + domain;
|
|
1548
1868
|
}
|
|
1549
1869
|
|
|
1870
|
+
function maskIdentifier(value) {
|
|
1871
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
1872
|
+
return value || "";
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
const trimmed = value.trim();
|
|
1876
|
+
const parts = trimmed.split(":");
|
|
1877
|
+
const suffix = parts.length > 1 ? parts.pop() || "" : trimmed;
|
|
1878
|
+
const prefix = parts.length > 0 ? parts.join(":") + ":" : "";
|
|
1879
|
+
|
|
1880
|
+
if (suffix.length <= 10) {
|
|
1881
|
+
return prefix + suffix.slice(0, 2) + "****";
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
return prefix + suffix.slice(0, 5) + "****" + suffix.slice(-5);
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1550
1887
|
function getProfileDisplayLabel(profile) {
|
|
1551
1888
|
if (!profile) {
|
|
1552
1889
|
return "\u672A\u767B\u5F55";
|
|
@@ -1554,11 +1891,12 @@ function renderAdminPage() {
|
|
|
1554
1891
|
if (profile.email) {
|
|
1555
1892
|
return state.showEmails ? profile.email : maskEmail(profile.email);
|
|
1556
1893
|
}
|
|
1557
|
-
|
|
1894
|
+
const fallback = profile.accountId || profile.profileId || "\u672A\u547D\u540D\u8D26\u53F7";
|
|
1895
|
+
return state.showEmails ? fallback : maskIdentifier(fallback);
|
|
1558
1896
|
}
|
|
1559
1897
|
|
|
1560
1898
|
function updateEmailToggleButton() {
|
|
1561
|
-
toggleEmailBtn.textContent = state.showEmails ? "\
|
|
1899
|
+
toggleEmailBtn.textContent = state.showEmails ? "\u660E\u6587\u6A21\u5F0F" : "\u8131\u654F\u6A21\u5F0F";
|
|
1562
1900
|
}
|
|
1563
1901
|
|
|
1564
1902
|
function getProfileInitial(profile) {
|
|
@@ -1573,7 +1911,8 @@ function renderAdminPage() {
|
|
|
1573
1911
|
if (item.accountEmail) {
|
|
1574
1912
|
return state.showEmails ? item.accountEmail : maskEmail(item.accountEmail);
|
|
1575
1913
|
}
|
|
1576
|
-
|
|
1914
|
+
const fallback = item.accountFallback || item.account || "\u672A\u767B\u5F55";
|
|
1915
|
+
return state.showEmails ? fallback : maskIdentifier(fallback);
|
|
1577
1916
|
}
|
|
1578
1917
|
|
|
1579
1918
|
function getPrimaryUsage(profile) {
|
|
@@ -1590,16 +1929,6 @@ function renderAdminPage() {
|
|
|
1590
1929
|
return Math.max(0, Math.min(100, value));
|
|
1591
1930
|
}
|
|
1592
1931
|
|
|
1593
|
-
function getEstimatedLatencySeconds(profile) {
|
|
1594
|
-
if (!profile || !profile.quota) {
|
|
1595
|
-
return 0;
|
|
1596
|
-
}
|
|
1597
|
-
const primary = getPrimaryUsage(profile);
|
|
1598
|
-
const secondary = getSecondaryUsage(profile);
|
|
1599
|
-
const baseline = 0.62 + primary / 110 + secondary / 260;
|
|
1600
|
-
return Math.round(baseline * 100) / 100;
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
1932
|
function getProfileHealth(profile) {
|
|
1604
1933
|
const now = Date.now();
|
|
1605
1934
|
if (profile && profile.expiresAt && profile.expiresAt <= now) {
|
|
@@ -1655,10 +1984,31 @@ function renderAdminPage() {
|
|
|
1655
1984
|
return "\u672A\u77E5";
|
|
1656
1985
|
}
|
|
1657
1986
|
|
|
1658
|
-
function
|
|
1987
|
+
function getQuotaWindowLabel(profile, slot) {
|
|
1659
1988
|
const quota = profile && profile.quota ? profile.quota : null;
|
|
1989
|
+
if (!quota) {
|
|
1990
|
+
return "\u672A\u540C\u6B65\u989D\u5EA6";
|
|
1991
|
+
}
|
|
1660
1992
|
const field = slot === "primary" ? "primaryWindowMinutes" : "secondaryWindowMinutes";
|
|
1661
|
-
return
|
|
1993
|
+
return formatWindowLabel(quota && quota[field]);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
function formatQuotaUsage(percent, profile, slot) {
|
|
1997
|
+
if (!profile || !profile.quota) {
|
|
1998
|
+
return "\u7B49\u5F85\u5237\u65B0";
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
const used = Math.round(percent);
|
|
2002
|
+
const remaining = Math.max(0, 100 - used);
|
|
2003
|
+
return getQuotaWindowLabel(profile, slot) + " \xB7 \u5DF2\u7528 " + used + "% / \u5269\u4F59 " + remaining + "%";
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
function formatQuotaRemaining(percent, profile) {
|
|
2007
|
+
if (!profile || !profile.quota) {
|
|
2008
|
+
return "--";
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
return "\u5269\u4F59 " + String(Math.max(0, 100 - Math.round(percent))) + "%";
|
|
1662
2012
|
}
|
|
1663
2013
|
|
|
1664
2014
|
function createTimingTracker() {
|
|
@@ -1722,9 +2072,37 @@ function renderAdminPage() {
|
|
|
1722
2072
|
return result;
|
|
1723
2073
|
}
|
|
1724
2074
|
|
|
2075
|
+
function setTesterResultTab(tab) {
|
|
2076
|
+
state.testerResultTab = tab;
|
|
2077
|
+
document.querySelectorAll("[data-result-tab]").forEach(function (button) {
|
|
2078
|
+
button.classList.toggle("is-active", button.getAttribute("data-result-tab") === tab);
|
|
2079
|
+
});
|
|
2080
|
+
document.querySelectorAll("[data-result-panel]").forEach(function (panel) {
|
|
2081
|
+
panel.classList.toggle("is-active", panel.getAttribute("data-result-panel") === tab);
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
function openImagePreviewModal(src, meta, filename) {
|
|
2086
|
+
previewModalImage.src = src;
|
|
2087
|
+
previewModalMeta.textContent = meta || "\u56FE\u7247\u9884\u89C8";
|
|
2088
|
+
downloadPreviewBtn.href = src;
|
|
2089
|
+
downloadPreviewBtn.download = filename || "generated-image.png";
|
|
2090
|
+
imagePreviewModal.classList.add("is-open");
|
|
2091
|
+
imagePreviewModal.setAttribute("aria-hidden", "false");
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
function closeImagePreviewModal() {
|
|
2095
|
+
imagePreviewModal.classList.remove("is-open");
|
|
2096
|
+
imagePreviewModal.setAttribute("aria-hidden", "true");
|
|
2097
|
+
previewModalImage.src = "";
|
|
2098
|
+
previewModalMeta.textContent = "\u7B49\u5F85\u56FE\u7247\u7ED3\u679C\u2026";
|
|
2099
|
+
downloadPreviewBtn.href = "#";
|
|
2100
|
+
downloadPreviewBtn.download = "generated-image.png";
|
|
2101
|
+
}
|
|
2102
|
+
|
|
1725
2103
|
function clearPreview() {
|
|
1726
|
-
responsePreview.hidden = true;
|
|
1727
2104
|
responsePreview.innerHTML = "";
|
|
2105
|
+
responsePreviewEmpty.hidden = false;
|
|
1728
2106
|
}
|
|
1729
2107
|
|
|
1730
2108
|
function renderPreview(payload) {
|
|
@@ -1755,9 +2133,6 @@ function renderAdminPage() {
|
|
|
1755
2133
|
const image = document.createElement("img");
|
|
1756
2134
|
image.alt = "\u751F\u6210\u56FE\u7247 " + String(index + 1);
|
|
1757
2135
|
image.src = "data:" + mime + ";base64," + item.b64_json;
|
|
1758
|
-
card.appendChild(image);
|
|
1759
|
-
|
|
1760
|
-
const caption = document.createElement("figcaption");
|
|
1761
2136
|
const lines = [
|
|
1762
2137
|
"\u56FE\u7247 " + String(index + 1),
|
|
1763
2138
|
payload.size ? "\u5C3A\u5BF8: " + payload.size : "",
|
|
@@ -1765,12 +2140,36 @@ function renderAdminPage() {
|
|
|
1765
2140
|
item.b64_json ? "base64 \u957F\u5EA6: " + String(item.b64_json.length) : "",
|
|
1766
2141
|
item.revised_prompt ? "\u91CD\u5199\u63D0\u793A\u8BCD: " + item.revised_prompt : "",
|
|
1767
2142
|
].filter(Boolean);
|
|
1768
|
-
|
|
2143
|
+
const captionText = lines.join(" | ");
|
|
2144
|
+
image.addEventListener("click", function () {
|
|
2145
|
+
openImagePreviewModal(
|
|
2146
|
+
image.src,
|
|
2147
|
+
captionText,
|
|
2148
|
+
"generated-image-" + String(index + 1) + "." + format,
|
|
2149
|
+
);
|
|
2150
|
+
});
|
|
2151
|
+
card.appendChild(image);
|
|
2152
|
+
|
|
2153
|
+
const caption = document.createElement("figcaption");
|
|
2154
|
+
caption.textContent = captionText;
|
|
1769
2155
|
card.appendChild(caption);
|
|
1770
2156
|
|
|
1771
2157
|
const actions = document.createElement("div");
|
|
1772
2158
|
actions.className = "preview-actions";
|
|
1773
2159
|
|
|
2160
|
+
const view = document.createElement("button");
|
|
2161
|
+
view.type = "button";
|
|
2162
|
+
view.className = "btn-secondary";
|
|
2163
|
+
view.textContent = "\u67E5\u770B\u5927\u56FE";
|
|
2164
|
+
view.addEventListener("click", function () {
|
|
2165
|
+
openImagePreviewModal(
|
|
2166
|
+
image.src,
|
|
2167
|
+
captionText,
|
|
2168
|
+
"generated-image-" + String(index + 1) + "." + format,
|
|
2169
|
+
);
|
|
2170
|
+
});
|
|
2171
|
+
actions.appendChild(view);
|
|
2172
|
+
|
|
1774
2173
|
const download = document.createElement("a");
|
|
1775
2174
|
download.href = image.src;
|
|
1776
2175
|
download.download = "generated-image-" + String(index + 1) + "." + format;
|
|
@@ -1781,7 +2180,7 @@ function renderAdminPage() {
|
|
|
1781
2180
|
responsePreview.appendChild(card);
|
|
1782
2181
|
});
|
|
1783
2182
|
|
|
1784
|
-
|
|
2183
|
+
responsePreviewEmpty.hidden = true;
|
|
1785
2184
|
}
|
|
1786
2185
|
|
|
1787
2186
|
function buildExample(endpoint) {
|
|
@@ -1844,6 +2243,12 @@ function renderAdminPage() {
|
|
|
1844
2243
|
detail: "\u672A\u663E\u5F0F\u6307\u5B9A model \u65F6\u751F\u6548",
|
|
1845
2244
|
compact: true,
|
|
1846
2245
|
},
|
|
2246
|
+
{
|
|
2247
|
+
label: "\u5F53\u524D\u7248\u672C",
|
|
2248
|
+
value: getVersionValue(config),
|
|
2249
|
+
detail: getVersionDetail(config),
|
|
2250
|
+
compact: true,
|
|
2251
|
+
},
|
|
1847
2252
|
{
|
|
1848
2253
|
label: "\u4ECA\u65E5\u8BF7\u6C42\u6570",
|
|
1849
2254
|
value: String(requests.length),
|
|
@@ -1913,9 +2318,9 @@ function renderAdminPage() {
|
|
|
1913
2318
|
|
|
1914
2319
|
filtered.sort(function (a, b) {
|
|
1915
2320
|
if (sort === "latency-asc") {
|
|
1916
|
-
const
|
|
1917
|
-
const
|
|
1918
|
-
return
|
|
2321
|
+
const aCapturedAt = getQuotaSnapshotTime(a) || 0;
|
|
2322
|
+
const bCapturedAt = getQuotaSnapshotTime(b) || 0;
|
|
2323
|
+
return bCapturedAt - aCapturedAt;
|
|
1919
2324
|
}
|
|
1920
2325
|
if (sort === "expiry-asc") {
|
|
1921
2326
|
const aExpiry = a.expiresAt || Number.MAX_SAFE_INTEGER;
|
|
@@ -1934,6 +2339,16 @@ function renderAdminPage() {
|
|
|
1934
2339
|
function renderProfiles(config) {
|
|
1935
2340
|
const container = document.getElementById("profileList");
|
|
1936
2341
|
const profiles = getFilteredProfiles(config);
|
|
2342
|
+
const gridClass = profiles.length <= 0
|
|
2343
|
+
? ""
|
|
2344
|
+
: profiles.length === 1
|
|
2345
|
+
? "profile-count-1"
|
|
2346
|
+
: profiles.length === 2
|
|
2347
|
+
? "profile-count-2"
|
|
2348
|
+
: profiles.length === 3
|
|
2349
|
+
? "profile-count-3"
|
|
2350
|
+
: "profile-count-many";
|
|
2351
|
+
container.className = gridClass ? "account-grid " + gridClass : "account-grid";
|
|
1937
2352
|
|
|
1938
2353
|
if (profiles.length === 0) {
|
|
1939
2354
|
container.innerHTML = '<div class="empty-state">\u5F53\u524D\u7B5B\u9009\u6761\u4EF6\u4E0B\u6CA1\u6709\u5339\u914D\u8D26\u53F7\u3002\u4F60\u53EF\u4EE5\u6E05\u7A7A\u7B5B\u9009\uFF0C\u6216\u8005\u5148\u65B0\u589E\u4E00\u4E2A\u8D26\u53F7\u3002</div>';
|
|
@@ -1941,6 +2356,7 @@ function renderAdminPage() {
|
|
|
1941
2356
|
}
|
|
1942
2357
|
|
|
1943
2358
|
container.innerHTML = profiles.map(function (profile) {
|
|
2359
|
+
const isSingleProfile = profiles.length === 1;
|
|
1944
2360
|
const health = getProfileHealth(profile);
|
|
1945
2361
|
const planType = getPlanType(profile);
|
|
1946
2362
|
const imageCapability = getImageCapability(profile);
|
|
@@ -1949,7 +2365,9 @@ function renderAdminPage() {
|
|
|
1949
2365
|
const primaryClass = health.barClass || "blue";
|
|
1950
2366
|
const secondaryClass = secondary >= 85 ? "orange" : "blue";
|
|
1951
2367
|
const actionButton = profile.isActive
|
|
1952
|
-
?
|
|
2368
|
+
? (isSingleProfile
|
|
2369
|
+
? '<span class="account-status">\u5F53\u524D\u4F7F\u7528\u4E2D</span>'
|
|
2370
|
+
: '<button class="btn-secondary" type="button" disabled>\u5F53\u524D\u4F7F\u7528\u4E2D</button>')
|
|
1953
2371
|
: '<button class="btn-secondary" type="button" data-profile-action="activate" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5207\u6362</button>';
|
|
1954
2372
|
|
|
1955
2373
|
return ""
|
|
@@ -1970,11 +2388,11 @@ function renderAdminPage() {
|
|
|
1970
2388
|
+ "</div>"
|
|
1971
2389
|
+ '<div class="account-metrics">'
|
|
1972
2390
|
+ '<div class="quota-row">'
|
|
1973
|
-
+ '<div class="quota-line"><span>' + escapeHtml(
|
|
2391
|
+
+ '<div class="quota-line"><span>' + escapeHtml(formatQuotaUsage(primary, profile, "primary")) + '</span><strong>' + escapeHtml(formatQuotaRemaining(primary, profile)) + "</strong></div>"
|
|
1974
2392
|
+ '<div class="progress-track"><div class="progress-bar ' + escapeHtml(primaryClass) + '" style="width:' + escapeHtml(String(primary)) + '%"></div></div>'
|
|
1975
2393
|
+ "</div>"
|
|
1976
2394
|
+ '<div class="quota-row">'
|
|
1977
|
-
+ '<div class="quota-line"><span>' + escapeHtml(
|
|
2395
|
+
+ '<div class="quota-line"><span>' + escapeHtml(formatQuotaUsage(secondary, profile, "secondary")) + '</span><strong>' + escapeHtml(formatQuotaRemaining(secondary, profile)) + "</strong></div>"
|
|
1978
2396
|
+ '<div class="progress-track"><div class="progress-bar ' + escapeHtml(secondaryClass) + '" style="width:' + escapeHtml(String(secondary)) + '%"></div></div>'
|
|
1979
2397
|
+ "</div>"
|
|
1980
2398
|
+ "</div>"
|
|
@@ -1982,8 +2400,9 @@ function renderAdminPage() {
|
|
|
1982
2400
|
+ '<div class="meta-item"><label>\u5957\u9910</label><strong>' + escapeHtml(planType) + "</strong></div>"
|
|
1983
2401
|
+ '<div class="meta-item"><label>\u751F\u56FE\u80FD\u529B</label><strong>' + escapeHtml(imageCapability.detail) + "</strong></div>"
|
|
1984
2402
|
+ '<div class="meta-item"><label>\u91CD\u7F6E\u65F6\u95F4</label><strong>' + escapeHtml(describeReset(profile, "primary")) + "</strong></div>"
|
|
1985
|
-
+ '<div class="meta-item"><label>\
|
|
1986
|
-
+ '<div class="meta-item"><label
|
|
2403
|
+
+ '<div class="meta-item"><label>\u989D\u5EA6\u5FEB\u7167</label><strong>' + escapeHtml(describeQuotaSnapshot(profile)) + "</strong></div>"
|
|
2404
|
+
+ '<div class="meta-item"><label>\u989D\u5EA6\u9650\u5236</label><strong>' + escapeHtml(describeQuotaLimit(profile)) + "</strong></div>"
|
|
2405
|
+
+ '<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>"
|
|
1987
2406
|
+ '<div class="meta-item"><label>\u8FC7\u671F\u65F6\u95F4</label><span>' + escapeHtml(formatTime(profile.expiresAt)) + "</span></div>"
|
|
1988
2407
|
+ "</div>"
|
|
1989
2408
|
+ '<div class="account-actions">'
|
|
@@ -2148,6 +2567,7 @@ function renderAdminPage() {
|
|
|
2148
2567
|
["Base URL", config.baseUrl],
|
|
2149
2568
|
["Provider", config.status.activeProvider || "openai-codex"],
|
|
2150
2569
|
["\u9ED8\u8BA4\u6A21\u578B", config.settings.defaultModel],
|
|
2570
|
+
["\u5F53\u524D\u7248\u672C", getVersionValue(config)],
|
|
2151
2571
|
["\u5F53\u524D\u5957\u9910", config.profile ? getPlanType(config.profile) : "\u672A\u767B\u5F55"],
|
|
2152
2572
|
["\u751F\u56FE\u80FD\u529B", getImageCapability(config.profile).detail],
|
|
2153
2573
|
["\u8D26\u53F7\u72B6\u6001", loggedIn ? "\u5DF2\u767B\u5F55" : "\u672A\u767B\u5F55"],
|
|
@@ -2162,19 +2582,19 @@ function renderAdminPage() {
|
|
|
2162
2582
|
}).join("");
|
|
2163
2583
|
|
|
2164
2584
|
const endpointRows = [
|
|
2165
|
-
["\u7BA1\u7406\u9875\u5730\u5740", config.adminUrl],
|
|
2166
2585
|
["API Base URL", config.baseUrl],
|
|
2167
|
-
["\u517C\u5BB9\u63A5\u53E3", config.supportedEndpoints.map(function (item) { return item.path; }).join("\uFF0C")],
|
|
2168
2586
|
["\u5F53\u524D\u8D26\u53F7", getProfileDisplayLabel(config.profile)],
|
|
2587
|
+
["\u9ED8\u8BA4\u6A21\u578B", config.settings.defaultModel],
|
|
2588
|
+
["\u7248\u672C\u72B6\u6001", getVersionDetail(config)],
|
|
2169
2589
|
["\u5F53\u524D\u5957\u9910", config.profile ? getPlanType(config.profile) : "\u672A\u767B\u5F55"],
|
|
2170
2590
|
["\u751F\u56FE\u80FD\u529B", getImageCapability(config.profile).detail],
|
|
2171
|
-
["
|
|
2172
|
-
["
|
|
2591
|
+
["\u517C\u5BB9\u63A5\u53E3", config.supportedEndpoints.map(function (item) { return item.path; }).join("\uFF0C")],
|
|
2592
|
+
["\u4EE4\u724C\u9884\u89C8", config.profile ? config.profile.accessTokenPreview : "\u672A\u767B\u5F55"],
|
|
2173
2593
|
];
|
|
2174
2594
|
|
|
2175
2595
|
endpointInfo.innerHTML = endpointRows.map(function (row) {
|
|
2176
2596
|
return ""
|
|
2177
|
-
+ '<div class="service-row">'
|
|
2597
|
+
+ '<div class="service-row compact">'
|
|
2178
2598
|
+ "<label>" + escapeHtml(row[0]) + "</label>"
|
|
2179
2599
|
+ '<code class="mono">' + escapeHtml(row[1]) + "</code>"
|
|
2180
2600
|
+ "</div>";
|
|
@@ -2201,6 +2621,25 @@ function renderAdminPage() {
|
|
|
2201
2621
|
}).join("");
|
|
2202
2622
|
}
|
|
2203
2623
|
|
|
2624
|
+
function renderModelCatalogStatus(config) {
|
|
2625
|
+
const hint = document.getElementById("modelCatalogHint");
|
|
2626
|
+
if (!config || !config.modelCatalog) {
|
|
2627
|
+
hint.textContent = "\u6A21\u578B\u76EE\u5F55\u72B6\u6001\u672A\u77E5\u3002";
|
|
2628
|
+
return;
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
const parts = [
|
|
2632
|
+
config.modelCatalog.source === "codex-cache" ? "\u5F53\u524D\u8BFB\u53D6 Codex \u672C\u5730\u6A21\u578B\u7F13\u5B58" : "\u5F53\u524D\u4F7F\u7528\u9879\u76EE\u5185\u7F6E\u6A21\u578B\u56DE\u9000\u5217\u8868",
|
|
2633
|
+
"\u5171 " + String(config.modelCatalog.modelCount) + " \u4E2A\u6A21\u578B",
|
|
2634
|
+
];
|
|
2635
|
+
|
|
2636
|
+
if (config.modelCatalog.fetchedAt) {
|
|
2637
|
+
parts.push("Codex \u66F4\u65B0\u65F6\u95F4 " + new Date(config.modelCatalog.fetchedAt).toLocaleString("zh-CN", { hour12: false }));
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
hint.textContent = parts.join("\uFF0C") + "\u3002";
|
|
2641
|
+
}
|
|
2642
|
+
|
|
2204
2643
|
function syncHero(config) {
|
|
2205
2644
|
const profileText = config.profile
|
|
2206
2645
|
? "\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"
|
|
@@ -2236,6 +2675,8 @@ function renderAdminPage() {
|
|
|
2236
2675
|
renderOverview(config);
|
|
2237
2676
|
renderProfiles(config);
|
|
2238
2677
|
renderModelOptions(config);
|
|
2678
|
+
renderModelCatalogStatus(config);
|
|
2679
|
+
renderUpdatePanel(config);
|
|
2239
2680
|
renderEndpoints(config);
|
|
2240
2681
|
renderServiceInfo(config);
|
|
2241
2682
|
renderTrend(config);
|
|
@@ -2287,23 +2728,76 @@ function renderAdminPage() {
|
|
|
2287
2728
|
return body;
|
|
2288
2729
|
}
|
|
2289
2730
|
|
|
2290
|
-
async function refreshConfig() {
|
|
2291
|
-
|
|
2292
|
-
const
|
|
2731
|
+
async function refreshConfig(options) {
|
|
2732
|
+
const syncRuntime = !!(options && options.syncRuntime);
|
|
2733
|
+
const silent = !!(options && options.silent);
|
|
2734
|
+
const url = syncRuntime ? "/_gateway/admin/runtime-refresh" : "/_gateway/admin/config";
|
|
2735
|
+
const requestOptions = syncRuntime ? { method: "POST" } : undefined;
|
|
2736
|
+
|
|
2737
|
+
if (!silent) {
|
|
2738
|
+
testerMeta.textContent = syncRuntime ? "\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001" : "\u5237\u65B0\u7BA1\u7406\u72B6\u6001";
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
const config = await fetchJson(url, requestOptions);
|
|
2293
2742
|
renderConfig(config);
|
|
2294
|
-
|
|
2743
|
+
|
|
2744
|
+
if (!silent) {
|
|
2745
|
+
testerMeta.textContent = "\u51C6\u5907\u5C31\u7EEA";
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
return config;
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
function scheduleRuntimeRefresh() {
|
|
2752
|
+
window.setInterval(function () {
|
|
2753
|
+
if (document.hidden) {
|
|
2754
|
+
return;
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
refreshConfig({
|
|
2758
|
+
syncRuntime: true,
|
|
2759
|
+
silent: true,
|
|
2760
|
+
}).catch(function (error) {
|
|
2761
|
+
console.warn("[admin] auto runtime refresh failed", error && error.message ? error.message : String(error));
|
|
2762
|
+
});
|
|
2763
|
+
}, RUNTIME_AUTO_REFRESH_MS);
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
async function syncQuotaAfterProfileChange(config, sourceLabel) {
|
|
2767
|
+
if (!config || !config.profile || config.profile.quota) {
|
|
2768
|
+
return config;
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
authStatus.textContent = "\u6B63\u5728\u540C\u6B65\u65B0\u8D26\u53F7\u7684\u989D\u5EA6\u4FE1\u606F...";
|
|
2772
|
+
try {
|
|
2773
|
+
const refreshedConfig = await fetchJson("/_gateway/admin/profiles/sync-quota", {
|
|
2774
|
+
method: "POST",
|
|
2775
|
+
});
|
|
2776
|
+
renderConfig(refreshedConfig);
|
|
2777
|
+
authStatus.textContent = refreshedConfig.profile && refreshedConfig.profile.quota
|
|
2778
|
+
? sourceLabel + "\uFF0C\u989D\u5EA6\u4FE1\u606F\u5DF2\u540C\u6B65\u3002"
|
|
2779
|
+
: sourceLabel + "\uFF0C\u4F46\u6682\u672A\u83B7\u53D6\u5230\u989D\u5EA6\u5934\u4FE1\u606F\u3002";
|
|
2780
|
+
return refreshedConfig;
|
|
2781
|
+
} catch (error) {
|
|
2782
|
+
authStatus.textContent = sourceLabel + "\uFF0C\u4F46\u989D\u5EA6\u540C\u6B65\u5931\u8D25: " + (error && error.message ? error.message : String(error));
|
|
2783
|
+
return config;
|
|
2784
|
+
}
|
|
2295
2785
|
}
|
|
2296
2786
|
|
|
2297
2787
|
async function login() {
|
|
2298
2788
|
const button = document.getElementById("loginBtn");
|
|
2299
2789
|
setBusy(button, true);
|
|
2300
|
-
authStatus.textContent = "\u6B63\u5728\u65B0\u589E\u8D26\u53F7\
|
|
2790
|
+
authStatus.textContent = "\u6B63\u5728\u65B0\u589E\u8D26\u53F7\u3001\u7B49\u5F85 OAuth \u5B8C\u6210\uFF0C\u5E76\u540C\u6B65\u989D\u5EA6\u4FE1\u606F...";
|
|
2301
2791
|
try {
|
|
2302
|
-
|
|
2792
|
+
let config = await fetchJson("/_gateway/admin/login", {
|
|
2303
2793
|
method: "POST",
|
|
2304
2794
|
});
|
|
2305
2795
|
renderConfig(config);
|
|
2306
|
-
|
|
2796
|
+
const baseMessage = "\u8D26\u53F7\u5DF2\u4FDD\u5B58\uFF0C\u5E76\u5DF2\u5207\u6362\u4E3A\u5F53\u524D\u4F7F\u7528\u8D26\u53F7: " + getProfileDisplayLabel(config.profile);
|
|
2797
|
+
config = await syncQuotaAfterProfileChange(config, baseMessage);
|
|
2798
|
+
if (config.profile && config.profile.quota) {
|
|
2799
|
+
authStatus.textContent = "\u8D26\u53F7\u5DF2\u4FDD\u5B58\uFF0C\u5DF2\u5207\u6362\u4E3A\u5F53\u524D\u4F7F\u7528\u8D26\u53F7\u5E76\u540C\u6B65\u989D\u5EA6\u4FE1\u606F: " + getProfileDisplayLabel(config.profile);
|
|
2800
|
+
}
|
|
2307
2801
|
} catch (error) {
|
|
2308
2802
|
authStatus.textContent = error.message;
|
|
2309
2803
|
} finally {
|
|
@@ -2333,7 +2827,7 @@ function renderAdminPage() {
|
|
|
2333
2827
|
setBusy(button, true);
|
|
2334
2828
|
authStatus.textContent = action === "activate" ? "\u6B63\u5728\u5207\u6362\u5F53\u524D\u8D26\u53F7..." : "\u6B63\u5728\u5220\u9664\u8D26\u53F7...";
|
|
2335
2829
|
try {
|
|
2336
|
-
|
|
2830
|
+
let config = await fetchJson(
|
|
2337
2831
|
action === "activate" ? "/_gateway/admin/profiles/activate" : "/_gateway/admin/profiles/remove",
|
|
2338
2832
|
{
|
|
2339
2833
|
method: "POST",
|
|
@@ -2346,9 +2840,15 @@ function renderAdminPage() {
|
|
|
2346
2840
|
},
|
|
2347
2841
|
);
|
|
2348
2842
|
renderConfig(config);
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2843
|
+
if (action === "activate") {
|
|
2844
|
+
const baseMessage = "\u5F53\u524D\u8D26\u53F7\u5DF2\u5207\u6362\u4E3A: " + getProfileDisplayLabel(config.profile);
|
|
2845
|
+
config = await syncQuotaAfterProfileChange(config, baseMessage);
|
|
2846
|
+
if (config.profile && config.profile.quota) {
|
|
2847
|
+
authStatus.textContent = baseMessage + "\uFF0C\u989D\u5EA6\u4FE1\u606F\u5DF2\u540C\u6B65\u3002";
|
|
2848
|
+
}
|
|
2849
|
+
} else {
|
|
2850
|
+
authStatus.textContent = "\u8D26\u53F7\u5DF2\u5220\u9664\u3002";
|
|
2851
|
+
}
|
|
2352
2852
|
} catch (error) {
|
|
2353
2853
|
authStatus.textContent = error.message;
|
|
2354
2854
|
} finally {
|
|
@@ -2380,6 +2880,24 @@ function renderAdminPage() {
|
|
|
2380
2880
|
}
|
|
2381
2881
|
}
|
|
2382
2882
|
|
|
2883
|
+
async function refreshModels() {
|
|
2884
|
+
const button = document.getElementById("refreshModelsBtn");
|
|
2885
|
+
setBusy(button, true);
|
|
2886
|
+
authStatus.textContent = "\u6B63\u5728\u540C\u6B65 Codex \u6A21\u578B\u5217\u8868...";
|
|
2887
|
+
try {
|
|
2888
|
+
await fetchJson("/_gateway/models/refresh", {
|
|
2889
|
+
method: "POST",
|
|
2890
|
+
});
|
|
2891
|
+
const config = await fetchJson("/_gateway/admin/config");
|
|
2892
|
+
renderConfig(config);
|
|
2893
|
+
authStatus.textContent = "Codex \u6A21\u578B\u5217\u8868\u5DF2\u540C\u6B65\u3002";
|
|
2894
|
+
} catch (error) {
|
|
2895
|
+
authStatus.textContent = error.message;
|
|
2896
|
+
} finally {
|
|
2897
|
+
setBusy(button, false);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2383
2901
|
function extractModelFromPayload(payload) {
|
|
2384
2902
|
if (!payload || typeof payload !== "object") {
|
|
2385
2903
|
return state.config ? state.config.settings.defaultModel : "-";
|
|
@@ -2396,6 +2914,7 @@ function renderAdminPage() {
|
|
|
2396
2914
|
const button = document.getElementById("runTestBtn");
|
|
2397
2915
|
const tracker = createTimingTracker();
|
|
2398
2916
|
setBusy(button, true);
|
|
2917
|
+
setTesterResultTab("response");
|
|
2399
2918
|
testerMeta.textContent = "\u8BF7\u6C42\u4E2D: " + meta.method + " " + endpoint;
|
|
2400
2919
|
responseBody.textContent = "\u8BF7\u6C42\u53D1\u9001\u4E2D...";
|
|
2401
2920
|
timingBody.textContent = "\u8BF7\u6C42\u53D1\u9001\u4E2D...";
|
|
@@ -2440,6 +2959,10 @@ function renderAdminPage() {
|
|
|
2440
2959
|
tracker,
|
|
2441
2960
|
["HTTP \u72B6\u6001: " + response.status + " " + response.statusText],
|
|
2442
2961
|
);
|
|
2962
|
+
if (typeof parsed !== "string" && parsed && Array.isArray(parsed.data)
|
|
2963
|
+
&& parsed.data.some(function (item) { return item && typeof item.b64_json === "string" && item.b64_json.length > 0; })) {
|
|
2964
|
+
setTesterResultTab("preview");
|
|
2965
|
+
}
|
|
2443
2966
|
testerMeta.textContent = (response.ok ? "\u6210\u529F" : "\u5931\u8D25") + ": HTTP " + response.status + " " + meta.method + " " + endpoint;
|
|
2444
2967
|
|
|
2445
2968
|
upsertRequestLog({
|
|
@@ -2495,12 +3018,28 @@ function renderAdminPage() {
|
|
|
2495
3018
|
}
|
|
2496
3019
|
|
|
2497
3020
|
document.getElementById("loginBtn").addEventListener("click", login);
|
|
2498
|
-
document.getElementById("refreshBtn").addEventListener("click",
|
|
3021
|
+
document.getElementById("refreshBtn").addEventListener("click", function () {
|
|
3022
|
+
authStatus.textContent = "\u6B63\u5728\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001...";
|
|
3023
|
+
refreshConfig({
|
|
3024
|
+
syncRuntime: true,
|
|
3025
|
+
}).then(function () {
|
|
3026
|
+
authStatus.textContent = "\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001\u5DF2\u5237\u65B0\u3002";
|
|
3027
|
+
}).catch(function (error) {
|
|
3028
|
+
authStatus.textContent = error && error.message ? error.message : String(error);
|
|
3029
|
+
});
|
|
3030
|
+
});
|
|
2499
3031
|
document.getElementById("logoutBtn").addEventListener("click", logout);
|
|
2500
3032
|
contactBtn.addEventListener("click", openContactModal);
|
|
2501
3033
|
document.getElementById("closeContactBtn").addEventListener("click", closeContactModal);
|
|
3034
|
+
document.getElementById("closeImagePreviewBtn").addEventListener("click", closeImagePreviewModal);
|
|
3035
|
+
document.getElementById("refreshModelsBtn").addEventListener("click", refreshModels);
|
|
2502
3036
|
document.getElementById("saveModelBtn").addEventListener("click", saveModel);
|
|
2503
3037
|
runTestBtn.addEventListener("click", runTest);
|
|
3038
|
+
document.querySelectorAll("[data-result-tab]").forEach(function (button) {
|
|
3039
|
+
button.addEventListener("click", function () {
|
|
3040
|
+
setTesterResultTab(button.getAttribute("data-result-tab"));
|
|
3041
|
+
});
|
|
3042
|
+
});
|
|
2504
3043
|
toggleEmailBtn.addEventListener("click", function () {
|
|
2505
3044
|
state.showEmails = !state.showEmails;
|
|
2506
3045
|
updateEmailToggleButton();
|
|
@@ -2595,12 +3134,23 @@ function renderAdminPage() {
|
|
|
2595
3134
|
}
|
|
2596
3135
|
});
|
|
2597
3136
|
|
|
3137
|
+
imagePreviewModal.addEventListener("click", function (event) {
|
|
3138
|
+
if (event.target === imagePreviewModal) {
|
|
3139
|
+
closeImagePreviewModal();
|
|
3140
|
+
}
|
|
3141
|
+
});
|
|
3142
|
+
|
|
2598
3143
|
document.addEventListener("keydown", function (event) {
|
|
3144
|
+
if (event.key === "Escape" && imagePreviewModal.classList.contains("is-open")) {
|
|
3145
|
+
closeImagePreviewModal();
|
|
3146
|
+
}
|
|
2599
3147
|
if (event.key === "Escape" && contactModal.classList.contains("is-open")) {
|
|
2600
3148
|
closeContactModal();
|
|
2601
3149
|
}
|
|
2602
3150
|
});
|
|
2603
3151
|
|
|
3152
|
+
setTesterResultTab(state.testerResultTab);
|
|
3153
|
+
scheduleRuntimeRefresh();
|
|
2604
3154
|
refreshConfig().catch(function (error) {
|
|
2605
3155
|
authStatus.textContent = error && error.message ? error.message : String(error);
|
|
2606
3156
|
testerMeta.textContent = "\u52A0\u8F7D\u5931\u8D25";
|