1<!DOCTYPE html> 2<html lang="zh-CN"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>GCLI2API æ§å¶é¢æ¿</title> 8 <style> 9 body { 10 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; 11 max-width: 1000px; 12 margin: 0 auto; 13 padding: 20px; 14 background-color: #f8f9fa; 15 } 16 17 .container { 18 background-color: white; 19 padding: 30px; 20 border-radius: 10px; 21 box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); 22 box-sizing: border-box; 23 overflow-x: auto; 24 } 25 26 h1 { 27 color: #333; 28 text-align: center; 29 } 30 31 .form-group { 32 margin-bottom: 20px; 33 } 34 35 label { 36 display: block; 37 margin-bottom: 5px; 38 font-weight: bold; 39 color: #555; 40 } 41 42 input[type="text"] { 43 width: 100%; 44 padding: 10px; 45 border: 2px solid #ddd; 46 border-radius: 5px; 47 font-size: 16px; 48 box-sizing: border-box; 49 } 50 51 input[type="text"]:focus { 52 border-color: #4285f4; 53 outline: none; 54 } 55 56 .btn { 57 background-color: #28a745; 58 color: white; 59 padding: 12px 30px; 60 border: none; 61 border-radius: 5px; 62 font-size: 16px; 63 cursor: pointer; 64 width: 100%; 65 margin-bottom: 10px; 66 } 67 68 .btn:hover { 69 background-color: #218838; 70 } 71 72 .btn:disabled { 73 background-color: #ccc; 74 cursor: not-allowed; 75 } 76 77 .auth-url { 78 background-color: #f8f9fa; 79 border: 1px solid #e1e4e8; 80 border-radius: 5px; 81 padding: 15px; 82 margin: 20px 0; 83 word-break: break-all; 84 } 85 86 .auth-url a { 87 color: #4285f4; 88 text-decoration: none; 89 } 90 91 .auth-url a:hover { 92 text-decoration: underline; 93 } 94 95 .credentials { 96 background-color: #f0f8ff; 97 border: 1px solid #b0d4ff; 98 border-radius: 5px; 99 padding: 15px; 100 margin: 20px 0; 101 font-family: monospace; 102 font-size: 12px; 103 white-space: pre-wrap; 104 word-break: break-all; 105 max-height: 400px; 106 overflow-y: auto; 107 } 108 109 /* Toast åºå®å®ä½å¨å³ä¸è§ */ 110 #statusSection { 111 position: fixed; 112 top: 20px; 113 right: 20px; 114 left: auto; 115 transform: none; 116 z-index: 9999; 117 width: auto; 118 max-width: 400px; 119 min-width: 250px; 120 } 121 122 /* Toast ä¸ç¨æ ·å¼ - åªå¨ #statusSection å çæ */ 123 #statusSection .status { 124 padding: 12px 20px; 125 border-radius: 8px; 126 margin: 0; 127 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); 128 opacity: 0; 129 transform: translateX(100%); 130 transition: opacity 0.3s ease, transform 0.3s ease; 131 } 132 133 #statusSection .status.show { 134 opacity: 1; 135 transform: translateX(0); 136 } 137 138 #statusSection .status.fade-out { 139 opacity: 0; 140 transform: translateX(100%); 141 } 142 143 #statusSection .status.success { 144 background-color: #28a745; 145 border: none; 146 color: white; 147 } 148 149 #statusSection .status.error { 150 background-color: #dc3545; 151 border: none; 152 color: white; 153 } 154 155 #statusSection .status.warning { 156 background-color: #ffc107; 157 border: none; 158 color: #212529; 159 } 160 161 #statusSection .status.info { 162 background-color: #17a2b8; 163 border: none; 164 color: white; 165 } 166 167 /* 页é¢å åµç status æ ·å¼ - ä¿æåæé£æ ¼ */ 168 .status { 169 padding: 10px; 170 border-radius: 5px; 171 margin: 10px 0; 172 } 173 174 .status.success { 175 background-color: #d4edda; 176 border: 1px solid #c3e6cb; 177 color: #155724; 178 } 179 180 .status.error {
181 background-color: #f8d7da; 182 border: 1px solid #f5c6cb; 183 color: #721c24; 184 } 185 186 .status.info { 187 background-color: #d1ecf1; 188 border: 1px solid #bee5eb; 189 color: #0c5460; 190 } 191 192 .hidden { 193 display: none; 194 } 195 196 .loading { 197 text-align: center; 198 color: #666; 199 } 200 201 .login-form { 202 text-align: center; 203 padding: 50px 0; 204 } 205 206 .login-form input[type="password"] { 207 width: 300px; 208 padding: 12px; 209 border: 2px solid #ddd; 210 border-radius: 5px; 211 font-size: 16px; 212 margin-bottom: 20px; 213 box-sizing: border-box; 214 } 215 216 .tabs { 217 display: inline-flex; 218 background: linear-gradient(145deg, #f5f5f7, #e8e8ed); 219 padding: 6px; 220 border-radius: 14px; 221 margin-bottom: 25px; 222 border-bottom: none; 223 gap: 3px; 224 overflow-x: auto; 225 max-width: 100%; 226 user-select: none; 227 box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06), 228 0 1px 2px rgba(255, 255, 255, 0.9); 229 position: relative; 230 } 231 232 /* æ»åæç¤ºå¨ */ 233 .tab-slider { 234 position: absolute; 235 top: 6px; 236 left: 0; 237 right: 0; 238 height: calc(100% - 12px); 239 background: white; 240 border-radius: 10px; 241 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), 242 0 1px 3px rgba(0, 0, 0, 0.06), 243 inset 0 -1px 0 rgba(0, 0, 0, 0.02); 244 transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1), 245 right 0.3s cubic-bezier(0.4, 0, 0.2, 1); 246 z-index: 0; 247 pointer-events: none; 248 } 249 250 /* æ»åå¾®å ææ */ 251 .tab-slider::after { 252 content: ''; 253 position: absolute; 254 top: 0; 255 left: 0; 256 right: 0; 257 height: 50%; 258 background: linear-gradient(180deg, 259 rgba(255, 255, 255, 0.8) 0%, 260 rgba(255, 255, 255, 0) 100%); 261 border-radius: 10px 10px 0 0; 262 pointer-events: none; 263 opacity: 0.5; 264 } 265 266 .tabs::-webkit-scrollbar {
267 height: 4px; 268 } 269 270 .tabs::-webkit-scrollbar-track { 271 background: transparent; 272 } 273 274 .tabs::-webkit-scrollbar-thumb { 275 background: rgba(0, 0, 0, 0.15); 276 border-radius: 2px; 277 } 278 279 .tabs::-webkit-scrollbar-thumb:hover { 280 background: rgba(0, 0, 0, 0.25); 281 } 282 283 .tab { 284 padding: 10px 18px; 285 cursor: pointer; 286 border: none; 287 background: transparent; 288 border-radius: 10px; 289 color: #666; 290 font-size: 14px; 291 font-weight: 450; 292 transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); 293 white-space: nowrap; 294 position: relative; 295 overflow: hidden; 296 z-index: 1; 297 } 298 299 /* ç¹å»æ³¢çº¹ææ */ 300 .tab::before { 301 content: ''; 302 position: absolute; 303 top: 50%; 304 left: 50%; 305 width: 0; 306 height: 0; 307 border-radius: 50%; 308 background: rgba(66, 133, 244, 0.15); 309 transform: translate(-50%, -50%); 310 transition: width 0.4s ease, height 0.4s ease; 311 z-index: -1; 312 } 313 314 .tab:active::before { 315 width: 200%; 316 height: 200%; 317 } 318 319 .tab.active { 320 color: #1a1a1a; 321 font-weight: 550; 322 transform: translateY(0); 323 /* èæ¯åé´å½±ç±æ»åæä¾ */ 324 } 325 326 .tab:hover:not(.active) { 327 background: rgba(255, 255, 255, 0.6); 328 color: #333; 329 transform: translateY(-1px); 330 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04); 331 } 332 333 /* æåææ */ 334 .tab:active { 335 transform: scale(0.97) translateY(0); 336 transition: transform 0.1s ease; 337 } 338 339 .tab.active:active { 340 transform: scale(0.98); 341 box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08), 342 inset 0 1px 2px rgba(0, 0, 0, 0.02); 343 } 344 345 /* ç¦ç¹ç¶æï¼é®ç导èªï¼ */ 346 .tab:focus { 347 outline: none; 348 } 349 350 .tab:focus-visible { 351 outline: 2px solid rgba(66, 133, 244, 0.5); 352 outline-offset: 2px; 353 } 354 355 .tab-content { 356 display: none; 357 width: 100%; 358 box-sizing: border-box; 359 /* å¨ç»ç± JavaScript æ§å¶ï¼é¿å å²çª */ 360 } 361 362 .tab-content.active { 363 display: block; 364 } 365 366 .upload-area { 367 border: 2px dashed #ddd; 368 border-radius: 5px; 369 padding: 40px; 370 text-align: center; 371 background-color: #fafafa; 372 margin: 20px 0; 373 cursor: pointer; 374 transition: border-color 0.3s; 375 } 376 377 .upload-area:hover { 378 border-color: #4285f4; 379 } 380 381 .upload-area.dragover { 382 border-color: #4285f4; 383 background-color: #f0f8ff; 384 } 385 386 .file-list { 387 margin: 20px 0; 388 } 389 390 .file-item { 391 background-color: #f8f9fa; 392 border: 1px solid #e1e4e8; 393 border-radius: 3px; 394 padding: 10px; 395 margin: 5px 0; 396 display: flex; 397 justify-content: space-between; 398 align-items: center; 399 } 400 401 .file-item .file-name { 402 font-family: monospace; 403 color: #333; 404 } 405 406 .file-item .file-size { 407 color: #666; 408 font-size: 12px; 409 } 410 411 .file-item .remove-btn { 412 background: #dc3545; 413 color: white; 414 border: none; 415 border-radius: 3px; 416 padding: 2px 8px; 417 cursor: pointer; 418 font-size: 12px; 419 } 420 421 .upload-progress { 422 background-color: #f8f9fa; 423 border: 1px solid #e1e4e8; 424 border-radius: 5px; 425 padding: 15px; 426 margin: 20px 0; 427 } 428 429 .progress-bar { 430 width: 100%; 431 height: 20px; 432 background-color: #e9ecef; 433 border-radius: 10px; 434 overflow: hidden; 435 margin: 10px 0; 436 } 437 438 .progress-fill { 439 height: 100%; 440 background-color: #28a745; 441 transition: width 0.3s ease; 442 } 443 444 /* æä»¶ç®¡çæ ·å¼ */ 445 .cred-card { 446 background-color: #f8f9fa; 447 border: 1px solid #e1e4e8; 448 border-radius: 8px; 449 padding: 15px; 450 margin: 10px 0; 451 position: relative; 452 width: 100%; 453 box-sizing: border-box; 454 } 455 456 .cred-card.disabled { 457 background-color: #f5f5f5; 458 border-color: #ccc; 459 opacity: 0.7; 460 } 461 462 .cred-header { 463 display: flex; 464 justify-content: space-between; 465 align-items: flex-start; 466 margin-bottom: 10px; 467 gap: 20px; 468 } 469 470 .cred-filename { 471 font-family: monospace; 472 font-weight: bold; 473 color: #333; 474 font-size: 14px; 475 white-space: nowrap; 476 overflow: hidden; 477 text-overflow: ellipsis; 478 min-width: 300px; 479 } 480 481 .cred-status { 482 display: flex; 483 gap: 5px; 484 } 485 486 .status-badge { 487 padding: 2px 8px; 488 border-radius: 12px; 489 font-size: 12px; 490 color: white; 491 } 492 493 .status-badge.enabled { 494 background-color: #28a745; 495 } 496 497 .status-badge.disabled { 498 background-color: #6c757d; 499 } 500 501 .error-codes { 502 background-color: #f8d7da; 503 color: #721c24; 504 padding: 2px 8px; 505 border-radius: 12px; 506 font-size: 12px; 507 } 508 509 .cooldown-badge { 510 background-color: #ffc107; 511 color: #856404; 512 padding: 2px 8px; 513 border-radius: 12px; 514 font-size: 12px; 515 font-weight: bold; 516 } 517 518 .cooldown-badge.ready { 519 background-color: #28a745; 520 color: white; 521 } 522
523 .model-cooldown-details { 524 background-color: #e3f2fd; 525 border: 1px solid #90caf9; 526 border-radius: 4px; 527 padding: 8px; 528 margin-top: 8px; 529 font-size: 11px; 530 color: #1976d2; 531 } 532 533 .model-cooldown-item { 534 display: inline-block; 535 background-color: #64b5f6; 536 color: white; 537 padding: 2px 6px; 538 border-radius: 10px; 539 margin: 2px; 540 font-size: 10px; 541 } 542 543 .cred-actions { 544 display: flex; 545 gap: 5px; 546 flex-wrap: wrap; 547 } 548 549 .cred-btn { 550 padding: 4px 12px; 551 border: none; 552 border-radius: 4px; 553 font-size: 12px; 554 cursor: pointer; 555 transition: background-color 0.2s; 556 background-color: #28a745; 557 color: white; 558 } 559 560 .cred-btn:hover { 561 background-color: #218838; 562 } 563 564 .cred-btn.enable { 565 background-color: #28a745; 566 color: white; 567 } 568 569 .cred-btn.disable { 570 background-color: #28a745; 571 color: white; 572 } 573 574 .cred-btn.delete { 575 background-color: #dc3545; 576 color: white; 577 } 578 579 .cred-btn.delete:hover { 580 background-color: #c82333; 581 } 582 583 .cred-btn.download { 584 background-color: #28a745; 585 color: white; 586 } 587 588 .cred-btn.view { 589 background-color: #28a745; 590 color: white; 591 } 592 593 .cred-details { 594 margin-top: 10px; 595 display: none; 596 } 597 598 .cred-details.show { 599 display: block; 600 } 601 602 .cred-content { 603 background-color: #f0f8ff; 604 border: 1px solid #b0d4ff; 605 border-radius: 4px; 606 padding: 10px; 607 font-family: monospace; 608 font-size: 11px; 609 white-space: pre-wrap; 610 word-break: break-all; 611 max-height: 200px; 612 overflow-y: auto; 613 } 614 615 /* é¢åº¦ä¿¡æ¯æ¾ç¤ºæ ·å¼ */ 616 .cred-quota-details { 617 margin-top: 10px; 618 animation: slideDown 0.3s ease-out; 619 } 620 621 @keyframes slideDown { 622 from { 623 opacity: 0; 624 transform: translateY(-10px); 625 } 626 627 to { 628 opacity: 1; 629 transform: translateY(0); 630 } 631 } 632 633 .cred-quota-content { 634 background: linear-gradient(to bottom, #ffffff, #f8f9fa); 635 border: 2px solid #17a2b8; 636 border-radius: 8px; 637 padding: 10px; 638 box-shadow: 0 2px 8px rgba(23, 162, 184, 0.15); 639 } 640 641 .manage-actions { 642 margin-bottom: 20px; 643 display: flex; 644 gap: 10px; 645 flex-wrap: wrap; 646 } 647 648 /* æä»¶ç®¡çæ°å¢æ ·å¼ */ 649 .stats-container { 650 display: flex; 651 gap: 15px; 652 margin-bottom: 20px; 653 flex-wrap: wrap; 654 } 655 656 .stat-item { 657 background: linear-gradient(45deg, #f8f9fa, #e9ecef); 658 border: 1px solid #dee2e6; 659 border-radius: 8px; 660 padding: 12px 20px; 661 text-align: center; 662 min-width: 120px; 663 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 664 } 665 666 .stat-number { 667 font-size: 24px; 668 font-weight: bold; 669 color: #333; 670 display: block; 671 } 672 673 .stat-label { 674 font-size: 12px; 675 color: #666; 676 text-transform: uppercase; 677 margin-top: 4px; 678 } 679 680 .stat-item.total { 681 border-left: 4px solid #007bff; 682 } 683 684 .stat-item.normal { 685 border-left: 4px solid #28a745; 686 } 687 688 .stat-item.disabled { 689 border-left: 4px solid #6c757d; 690 } 691 692 .filter-container { 693 display: flex; 694 gap: 10px; 695 margin-bottom: 20px; 696 align-items: center; 697 flex-wrap: wrap; 698 } 699 700 .filter-select { 701 padding: 8px 12px; 702 border: 2px solid #ddd; 703 border-radius: 4px; 704 font-size: 14px; 705 background-color: white; 706 } 707 708 .filter-select:focus { 709 border-color: #4285f4; 710 outline: none; 711 } 712 713 .pagination-container { 714 display: flex; 715 justify-content: center; 716 align-items: center; 717 gap: 10px; 718 margin: 20px 0; 719 flex-wrap: wrap; 720 } 721 722 .pagination-info { 723 color: #666; 724 font-size: 14px; 725 } 726 727 .pagination-btn { 728 padding: 8px 12px; 729 border: 1px solid #ddd; 730 background: white; 731 cursor: pointer; 732 border-radius: 4px; 733 font-size: 14px; 734 } 735 736 .pagination-btn:hover:not(:disabled) { 737 background: #f8f9fa; 738 border-color: #4285f4; 739 } 740 741 .pagination-btn:disabled { 742 background: #f5f5f5; 743 color: #ccc;
744 cursor: not-allowed; 745 } 746 747 .pagination-btn.active { 748 background: #4285f4; 749 color: white; 750 border-color: #4285f4; 751 } 752 753 .page-size-select { 754 padding: 6px 10px; 755 border: 1px solid #ddd; 756 border-radius: 4px; 757 font-size: 14px; 758 } 759 760 .refresh-btn { 761 background-color: #28a745; 762 color: white; 763 padding: 8px 16px; 764 border: none; 765 border-radius: 4px; 766 cursor: pointer; 767 } 768 769 .download-all-btn { 770 background-color: #28a745; 771 color: white; 772 padding: 8px 16px; 773 border: none; 774 border-radius: 4px; 775 cursor: pointer; 776 } 777 778 .refresh-btn:hover, 779 .download-all-btn:hover { 780 background-color: #218838; 781 } 782 783 /* æ¹éæä½æ ·å¼ */ 784 .batch-controls { 785 background-color: #f8f9fa; 786 border: 1px solid #e1e4e8; 787 border-radius: 8px; 788 padding: 15px; 789 margin-bottom: 20px; 790 } 791 792 .checkbox-container { 793 display: flex; 794 align-items: center; 795 margin-right: 15px; 796 } 797 798 .batch-actions { 799 display: flex; 800 gap: 10px; 801 flex-wrap: wrap; 802 align-items: center; 803 margin-top: 10px; 804 } 805 806 .batch-btn { 807 padding: 6px 12px; 808 border: none; 809 border-radius: 4px; 810 font-size: 12px; 811 cursor: pointer; 812 transition: background-color 0.2s; 813 background-color: #28a745; 814 color: white; 815 } 816 817 .batch-btn:hover:not(:disabled) { 818 background-color: #218838; 819 } 820 821 .batch-btn.batch-enable { 822 background-color: #28a745; 823 color: white; 824 } 825 826 .batch-btn.batch-disable { 827 background-color: #28a745; 828 color: white; 829 } 830 831 .batch-btn.batch-delete { 832 background-color: #dc3545; 833 color: white; 834 } 835 836 .batch-btn.batch-email { 837 background-color: #28a745; 838 color: white; 839 } 840 841 .batch-btn:disabled { 842 background-color: #e9ecef; 843 color: #6c757d; 844 cursor: not-allowed; 845 } 846 847 848 .cred-btn.email { 849 background-color: #28a745; 850 color: white; 851 } 852 853 .selected-count { 854 font-weight: bold; 855 color: #007bff; 856 margin-right: 10px; 857 } 858 859 .select-all-checkbox { 860 margin-right: 8px; 861 transform: scale(1.2); 862 } 863 864 /* é误ç çéå¢å¼º */ 865 .error-filter-container { 866 display: flex; 867 gap: 10px; 868 align-items: center; 869 flex-wrap: wrap; 870 } 871 872 .error-code-badge { 873 display: inline-block; 874 background-color: #dc3545; 875 color: white; 876 padding: 2px 6px; 877 border-radius: 10px; 878 font-size: 11px; 879 margin: 1px; 880 cursor: pointer; 881 transition: background-color 0.2s; 882 } 883 884 .error-code-badge:hover { 885 background-color: #c82333; 886 } 887 888 .error-code-badge.selected { 889 background-color: #007bff; 890 } 891 892 /* é ç½®ç®¡çæ ·å¼ */ 893 .config-group { 894 background-color: #f8f9fa; 895 border: 1px solid #e1e4e8; 896 border-radius: 8px; 897 padding: 20px; 898 margin: 15px 0; 899 } 900 901 .config-group h4 { 902 margin-top: 0; 903 margin-bottom: 15px; 904 color: #333; 905 border-bottom: 1px solid #e1e4e8; 906 padding-bottom: 8px; 907 } 908 909 .config-input { 910 width: 100%; 911 padding: 8px 12px; 912 border: 2px solid #ddd; 913 border-radius: 4px; 914 font-size: 14px; 915 box-sizing: border-box; 916 margin-bottom: 5px; 917 } 918 919 .config-input:focus { 920 border-color: #4285f4; 921 outline: none; 922 } 923 924 .config-input:disabled { 925 background-color: #f5f5f5; 926 color: #666;
927 cursor: not-allowed; 928 } 929 930 .config-checkbox { 931 margin-right: 8px; 932 transform: scale(1.2); 933 } 934 935 .config-note { 936 display: block; 937 color: #666; 938 font-size: 12px; 939 margin-bottom: 10px; 940 font-style: italic; 941 } 942 943 .config-info { 944 background-color: #e3f2fd; 945 border: 1px solid #1976d2; 946 border-radius: 4px; 947 padding: 12px; 948 margin-top: 8px; 949 font-size: 13px; 950 color: #1565c0; 951 } 952 953 .config-info ul { 954 margin: 8px 0 4px 0; 955 color: #424242; 956 } 957 958 .config-info li { 959 margin: 3px 0; 960 } 961 962 .env-locked { 963 position: relative; 964 } 965 966 .env-locked::after { 967 content: "ð ç¯å¢åééå®"; 968 position: absolute; 969 right: 10px; 970 top: 50%; 971 transform: translateY(-50%); 972 background-color: #ffc107; 973 color: #212529; 974 padding: 2px 6px; 975 border-radius: 3px; 976 font-size: 11px; 977 pointer-events: none; 978 } 979 980 /* 使ç¨ç»è®¡æ ·å¼ */ 981 .usage-card { 982 background-color: #f8f9fa; 983 border: 1px solid #e1e4e8; 984 border-radius: 8px; 985 padding: 15px; 986 margin: 10px 0; 987 position: relative; 988 } 989 990 .usage-header { 991 display: flex; 992 justify-content: space-between; 993 align-items: center; 994 margin-bottom: 15px; 995 } 996 997 .usage-filename { 998 font-family: monospace; 999 font-weight: bold; 1000 color: #333; 1001 font-size: 14px; 1002 } 1003 1004 .usage-progress { 1005 margin: 10px 0; 1006 } 1007 1008 .usage-progress-label { 1009 display: flex; 1010 justify-content: space-between; 1011 align-items: center; 1012 margin-bottom: 5px; 1013 font-size: 12px; 1014 } 1015 1016 .usage-progress-bar { 1017 width: 100%; 1018 height: 20px; 1019 background-color: #e9ecef; 1020 border-radius: 10px; 1021 overflow: hidden; 1022 position: relative; 1023 } 1024 1025 .usage-progress-fill { 1026 height: 100%; 1027 transition: width 0.3s ease; 1028 } 1029 1030 .usage-progress-fill.gemini { 1031 background-color: #ff6b35; 1032 } 1033 1034 .usage-progress-fill.total { 1035 background-color: #007bff; 1036 } 1037 1038 .usage-progress-fill.warning { 1039 background-color: #ffc107; 1040 } 1041 1042 .usage-progress-fill.danger { 1043 background-color: #dc3545; 1044 } 1045 1046 .usage-actions { 1047 display: flex; 1048 gap: 5px; 1049 margin-top: 10px; 1050 } 1051 1052 .usage-btn { 1053 padding: 4px 8px; 1054 border: none; 1055 border-radius: 4px; 1056 font-size: 11px; 1057 cursor: pointer; 1058 transition: background-color 0.2s; 1059 } 1060 1061 .usage-btn.reset { 1062 background-color: #6c757d; 1063 color: white; 1064 } 1065 1066 .usage-btn.limits { 1067 background-color: #17a2b8; 1068 color: white; 1069 } 1070 1071 .usage-info { 1072 display: grid; 1073 grid-template-columns: 1fr 1fr; 1074 gap: 10px; 1075 margin-top: 10px; 1076 font-size: 12px; 1077 } 1078 1079 .usage-info-item { 1080 background-color: #ffffff; 1081 padding: 8px; 1082 border-radius: 4px; 1083 border: 1px solid #dee2e6; 1084 } 1085 1086 .usage-info-label { 1087 font-weight: bold; 1088 color: #666; 1089 display: block; 1090 margin-bottom: 2px; 1091 } 1092 1093 .usage-info-value { 1094 color: #333; 1095 } 1096 1097 .reset-time { 1098 font-size: 11px; 1099 color: #666; 1100 font-style: italic; 1101 margin-top: 5px; 1102 } 1103 1104 /* éå¶è®¾ç½®å¼¹çªæ ·å¼ */ 1105 .modal { 1106 display: none; 1107 position: fixed; 1108 z-index: 1000; 1109 left: 0; 1110 top: 0; 1111 width: 100%; 1112 height: 100%; 1113 background-color: rgba(0, 0, 0, 0.5); 1114 } 1115
1116 .modal-content { 1117 background-color: #fefefe; 1118 margin: 15% auto; 1119 padding: 20px; 1120 border-radius: 8px; 1121 width: 400px; 1122 max-width: 90%; 1123 } 1124 1125 .modal-header { 1126 display: flex; 1127 justify-content: space-between; 1128 align-items: center; 1129 margin-bottom: 15px; 1130 padding-bottom: 10px; 1131 border-bottom: 1px solid #dee2e6; 1132 } 1133 1134 .modal-title { 1135 margin: 0; 1136 font-size: 16px; 1137 color: #333; 1138 } 1139 1140 .modal-close { 1141 background: none; 1142 border: none; 1143 font-size: 20px; 1144 cursor: pointer; 1145 color: #999; 1146 } 1147 1148 .modal-close:hover { 1149 color: #333; 1150 } 1151 1152 .modal-body { 1153 margin-bottom: 15px; 1154 } 1155 1156 .modal-footer { 1157 display: flex; 1158 gap: 10px; 1159 justify-content: flex-end; 1160 } 1161 1162 /* æ¶æ¯æ¨¡ææ¡æ ·å¼ */ 1163 .message-modal-overlay { 1164 position: fixed; 1165 top: 0; 1166 left: 0; 1167 width: 100%; 1168 height: 100%; 1169 background-color: rgba(0, 0, 0, 0.5); 1170 display: flex; 1171 justify-content: center; 1172 align-items: center; 1173 z-index: 10000; 1174 animation: fadeIn 0.2s ease-in; 1175 } 1176 1177 @keyframes fadeIn { 1178 from { 1179 opacity: 0; 1180 } 1181 1182 to { 1183 opacity: 1; 1184 } 1185 } 1186 1187 .message-modal { 1188 background: white; 1189 border-radius: 8px; 1190 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); 1191 max-width: 600px; 1192 width: 90%; 1193 max-height: 80vh; 1194 display: flex; 1195 flex-direction: column; 1196 animation: slideIn 0.3s ease-out; 1197 } 1198 1199 @keyframes slideIn { 1200 from { 1201 transform: translateY(-50px); 1202 opacity: 0; 1203 } 1204 1205 to { 1206 transform: translateY(0); 1207 opacity: 1; 1208 } 1209 } 1210 1211 .message-modal-header { 1212 display: flex; 1213 justify-content: space-between; 1214 align-items: center; 1215 padding: 20px 24px; 1216 border-bottom: 1px solid #e0e0e0; 1217 } 1218 1219 .message-modal.success .message-modal-header { 1220 background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); 1221 color: white; 1222 border-radius: 8px 8px 0 0; 1223 } 1224 1225 .message-modal.error .message-modal-header { 1226 background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%); 1227 color: white; 1228 border-radius: 8px 8px 0 0; 1229 } 1230 1231 .message-modal.info .message-modal-header { 1232 background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%); 1233 color: white; 1234 border-radius: 8px 8px 0 0; 1235 } 1236 1237 .message-modal-header h3 { 1238 margin: 0; 1239 font-size: 20px; 1240 font-weight: 600; 1241 } 1242 1243 .message-modal-close { 1244 background: none; 1245 border: none; 1246 font-size: 28px; 1247 cursor: pointer; 1248 color: inherit; 1249 opacity: 0.8; 1250 transition: opacity 0.2s; 1251 padding: 0; 1252 width: 32px; 1253 height: 32px; 1254 display: flex; 1255 align-items: center; 1256 justify-content: center; 1257 } 1258 1259 .message-modal-close:hover { 1260 opacity: 1; 1261 } 1262 1263 .message-modal-body { 1264 padding: 24px; 1265 overflow-y: auto; 1266 line-height: 1.6; 1267 color: #333; 1268 font-size: 14px; 1269 white-space: pre-wrap; 1270 word-break: break-word; 1271 } 1272 1273 .message-modal-footer { 1274 padding: 16px 24px; 1275 border-top: 1px solid #e0e0e0; 1276 display: flex; 1277 justify-content: flex-end; 1278 gap: 10px; 1279 } 1280 1281 .message-modal-btn { 1282 padding: 10px 24px; 1283 border: none; 1284 border-radius: 4px; 1285 font-size: 14px; 1286 font-weight: 500; 1287 cursor: pointer; 1288 transition: all 0.2s; 1289 background-color: #4285f4; 1290 color: white; 1291 } 1292 1293 .message-modal-btn:hover { 1294 background-color: #3367d6; 1295 transform: translateY(-1px); 1296 box-shadow: 0 2px 8px rgba(66, 133, 244, 0.3); 1297 } 1298 1299 /* æ¶æ¯ä¸ç龿¥æ ·å¼ */ 1300 .message-link { 1301 color: #1976d2; 1302 text-decoration: none; 1303 font-weight: 500; 1304 padding: 2px 4px; 1305 border-radius: 3px; 1306 background-color: rgba(25, 118, 210, 0.1); 1307 transition: all 0.2s; 1308 display: inline-block; 1309 word-break: break-all; 1310 } 1311 1312 .message-link:hover { 1313 background-color: rgba(25, 118, 210, 0.2); 1314 text-decoration: underline; 1315 transform: translateY(-1px); 1316 } 1317 1318 .message-link:active { 1319 transform: translateY(0); 1320 } 1321 1322 /* ç§»å¨ç«¯éé */ 1323 @media (max-width: 768px) { 1324 .message-modal { 1325 max-width: 95%; 1326 max-height: 90vh; 1327 } 1328 1329 .message-modal-header { 1330 padding: 16px 20px; 1331 } 1332 1333 .message-modal-body { 1334 padding: 20px; 1335 font-size: 13px; 1336 } 1337 1338 .message-modal-footer { 1339 padding: 12px 20px; 1340 } 1341 } 1342 </style> 1343</head> 1344 1345<body> 1346 <div class="container"> 1347 1348 <!-- ç»å½çé¢ --> 1349 <div id="loginSection" class="login-form"> 1350 <h1>GCLI2API 管ç颿¿</h1> 1351 <p>请è¾å ¥è®¿é®å¯ç ï¼</p> 1352 <input type="password" id="loginPassword" placeholder="è¾å ¥å¯ç " onkeypress="handlePasswordEnter(event)" /> 1353 <br> 1354 <button class="btn" onclick="login()">ç»å½</button> 1355 </div> 1356 1357 <!-- 主çé¢ --> 1358 <div id="mainSection" class="hidden"> 1359 <div 1360 style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 10px;"> 1361 <div style="display: flex; align-items: center; gap: 15px; flex-wrap: wrap;"> 1362 <h1 style="margin: 0;">GCLI2API 管ç颿¿</h1>
1363 <span id="versionInfo" style="font-size: 12px; color: #666;"> 1364 <span id="versionText">å è½½ä¸...</span> 1365 </span> 1366 <button onclick="checkForUpdates()" id="checkUpdateBtn" 1367 style="padding: 4px 12px; background-color: #17a2b8; color: white; border: none; border-radius: 4px; font-size: 12px; cursor: pointer; white-space: nowrap;"> 1368 æ£æ¥æ´æ° 1369 </button> 1370 </div> 1371 <button onclick="logout()" 1372 style="padding: 8px 20px; background-color: #dc3545; color: white; border: none; border-radius: 5px; font-size: 14px; cursor: pointer;"> 1373 éåºç»å½ 1374 </button> 1375 </div> 1376 1377 <!-- æ ç¾é¡µ --> 1378 <div class="tabs"> 1379 <div class="tab-slider"></div> 1380 <button class="tab active" onclick="switchTab('oauth')">OAuth认è¯</button> 1381 <button class="tab" onclick="switchTab('antigravity')">Antigravity认è¯</button> 1382 <button class="tab" onclick="switchTab('upload')">æ¹éä¸ä¼ </button> 1383 <button class="tab" onclick="switchTab('manage')">GCLIåè¯ç®¡ç</button> 1384 <button class="tab" onclick="switchTab('antigravity-manage')">Antigravityåè¯ç®¡ç</button> 1385 <button class="tab" onclick="switchTab('config')">é 置管ç</button> 1386 <button class="tab" onclick="switchTab('logs')">宿¶æ¥å¿</button> 1387 <button class="tab" onclick="switchTab('about')">项ç®ä¿¡æ¯</button> 1388 </div> 1389 1390 <!-- OAuthè®¤è¯æ ç¾é¡µ --> 1391 <div id="oauthTab" class="tab-content active"> 1392 <!-- API èªå¨å¯ç¨è¯´æ --> 1393 <div class="status success" style="margin-bottom: 20px;"> 1394 <strong>⨠èªå¨åä¼åï¼</strong> ç³»ç»ç°å¨ä¼å¨è®¤è¯æååèªå¨ä¸ºæ¨ç项ç®å¯ç¨å¿ éçAPIæå¡ 1395 <ul style="margin: 10px 0; padding-left: 20px;"> 1396 <li><strong>Gemini Cloud Assist API</strong></li> 1397 <li><strong>Gemini for Google Cloud API</strong></li> 1398 </ul> 1399 <p style="margin: 10px 0; color: #155724;"><strong>说æï¼</strong>æ éæå¨å¯ç¨APIï¼ç³»ç»ä¼èªå¨å¤çè¿äºé ç½®æ¥éª¤ï¼è®©è®¤è¯æµç¨æ´å 顺ç ã 1400 </p> 1401 </div> 1402 1403 <!-- æå å¼ Project ID è¾å ¥æ¡ --> 1404 <div class="form-group"> 1405 <div style="cursor: pointer; user-select: none; padding: 12px; border: 2px solid #ddd; border-radius: 5px; background: #f8f9fa; display: flex; justify-content: space-between; align-items: center;" 1406 onclick="toggleProjectIdSection()"> 1407 <span style="font-weight: bold; color: #555;">ð é«çº§é项ï¼Google Cloud Project ID 1408 (ä¸ç¨ç®¡ï¼ç´æ¥ç¹å»è·å龿¥å³å¯)</span> 1409 <span id="projectIdToggleIcon" 1410 style="font-size: 14px; color: #666; transition: transform 0.3s ease;">â¶</span> 1411 </div> 1412 <div id="projectIdSection" 1413 style="display: none; margin-top: 15px; padding: 15px; border: 2px solid #ddd; border-top: none; border-radius: 0 0 5px 5px; background: #ffffff;"> 1414 <label for="projectId" 1415 style="display: block; margin-bottom: 5px; font-weight: bold; color: #555;">Google Cloud 1416 Project ID (å¯é):</label> 1417 <input type="text" id="projectId" 1418 style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px; box-sizing: border-box;" 1419 placeholder="ç空å°å°è¯èªå¨æ£æµï¼ææå¨è¾å ¥é¡¹ç®ID" /> 1420 <small style="color: #666; font-size: 12px; margin-top: 5px; display: block;"> 1421 ð¡ æç¤ºï¼å¦æä½ ä¸æè¿æ¯ä»ä¹ï¼å¯ä»¥ç空æ¤å段让系ç»èªå¨æ£æµé¡¹ç®ID 1422 </small> 1423 </div> 1424 </div> 1425 1426 <button class="btn" id="getAuthBtn" onclick="startAuth()">è·å认è¯é¾æ¥</button> 1427 1428 <div id="authUrlSection" class="hidden"> 1429 <h3>认è¯é¾æ¥ï¼</h3> 1430 <div class="auth-url"> 1431 <a id="authUrl" href="#" target="_blank">
1431ç¹å»æ¤é¾æ¥è¿è¡è®¤è¯</a> 1432 </div> 1433 <div class="status info"> 1434 <strong>éè¦è¯´æï¼</strong> 1435 <ol style="margin: 10px 0; padding-left: 20px;"> 1436 <li>ç¹å»ä¸æ¹è®¤è¯é¾æ¥ï¼ä¼å¨æ°çªå£ä¸æå¼Google OAuth页é¢</li> 1437 <li>宿Googleè´¦å·ç»å½åææ</li> 1438 <li>æææååä¼è·³è½¬å°localhost:11451æ¾ç¤ºæå页é¢</li> 1439 <li>å ³éOAuthçªå£ï¼è¿åæ¬é¡µé¢</li> 1440 <li>ç¹å»ä¸æ¹"è·åè®¤è¯æä»¶"æé®å®ææµç¨</li> 1441 </ol> 1442 </div> 1443 1444 <!-- å¿«æ·åè°URLè¾å ¥é项 --> 1445 <div class="form-group" 1446 style="margin: 20px 0; padding: 15px; border: 2px solid #e8f4fd; border-radius: 8px; background: #f8fcff;"> 1447 <div style="cursor: pointer; user-select: none; display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;" 1448 onclick="toggleCallbackUrlSection()"> 1449 <span style="font-weight: bold; color: #0066cc;">ð æ æ³åæºï¼è¯è¯å¿«æ·æ¹å¼</span> 1450 <span id="callbackUrlToggleIcon" 1451 style="font-size: 14px; color: #666; transition: transform 0.3s ease;">â¼</span> 1452 </div> 1453 <div id="callbackUrlSection" style="display: none;"> 1454 <div 1455 style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 12px; margin-bottom: 12px;"> 1456 <div style="color: #856404; font-size: 14px; font-weight: bold; margin-bottom: 6px;">ð 1457 éç¨åºæ¯ï¼</div> 1458 <ul 1459 style="color: #856404; font-size: 13px; margin: 0; padding-left: 18px; line-height: 1.5;"> 1460 <li>äºæå¡å¨ãVPSç鿬å°ç¯å¢</li> 1461 <li>é²ç«å¢é»æ¢äº11451端å£è®¿é®</li> 1462 <li>ç½ç»ç¯å¢æ æ³æ£å¸¸åæºå°localhost</li> 1463 <li>Docker容å¨å è¿è¡ï¼ç«¯å£æ å°é®é¢</li> 1464 </ul> 1465 </div> 1466 <div style="color: #666; font-size: 13px; margin-bottom: 12px; line-height: 1.6;"> 1467 <strong style="color: #0066cc;">ð ä»ä¹æ¯åè°URLï¼</strong><br> 1468 宿Google OAuthææåï¼æµè§å¨å°åæ æ¾ç¤ºç宿´URLï¼é常çèµ·æ¥åè¿æ ·ï¼<br> 1469 <code 1470 style="background: #f1f3f4; padding: 2px 6px; border-radius: 3px; font-size: 12px; word-break: break-all;"> 1471 http://localhost:11451/?state=abc123...&code=4/0AVMBsJ...&scope=email%20profile... 1472 </code> 1473 </div> 1474 <div 1475 style="background: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 6px; padding: 10px; margin-bottom: 12px;"> 1476 <div style="color: #0066cc; font-size: 13px; font-weight: bold; margin-bottom: 4px;">ð 1477 ä½¿ç¨æ¥éª¤ï¼</div> 1478 <ol 1479 style="color: #0066cc; font-size: 12px; margin: 0; padding-left: 18px; line-height: 1.4;"> 1480 <li>ç¹å»ä¸æ¹è®¤è¯é¾æ¥ï¼å®æGoogleææ</li> 1481 <li>æææååï¼å¤å¶æµè§å¨å°åæ ç<strong>宿´URL</strong></li> 1482 <li>ç²è´´å°ä¸æ¹è¾å ¥æ¡ï¼ç¹å»è·ååè¯å³å¯</li> 1483 </ol> 1484 </div> 1485 <div class="input-group"> 1486 <input type="url" id="callbackUrlInput" 1487 placeholder="ç²è´´å®æ´çåè°URLï¼ä¾å¦ï¼http://localhost:11451/?state=xxx&code=xxx&scope=xxx..." 1488 style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 4px; font-size: 13px;"> 1489 </div> 1490 <button class="btn" style="margin-top: 10px;" onclick="processCallbackUrl()"> 1491 ä»åè°URLè·ååè¯ 1492 </button> 1493 </div> 1494 </div> 1495 1496 <button class="btn" id="getCredsBtn" onclick="getCredentials()">è·åè®¤è¯æä»¶</button> 1497 </div> 1498 1499 <div id="credentialsSection" class="hidden"> 1500 <h3>è®¤è¯æä»¶å 容ï¼</h3> 1501 <div class="credentials" id="credentialsContent"></div> 1502 </div> 1503 </div> 1504 1505 <!-- Antigravity è®¤è¯æ ç¾é¡µ --> 1506 <div id="antigravityTab" class="tab-content"> 1507 <div class="status info" style="margin-bottom: 20px;"> 1508 <strong>ð Antigravity è®¤è¯æ¨¡å¼</strong> 1509 <p style="margin: 10px 0;"> 1510 è·åè°·æAntigravity åè¯ 1511 </p> 1512 </div> 1513 1514 <button class="btn" id="getAntigravityAuthBtn">è·å Antigravity 认è¯é¾æ¥</button> 1515 1516 <div id="antigravityAuthUrlSection" class="hidden"> 1517 <h3>
1517Antigravity 认è¯é¾æ¥ï¼</h3> 1518 <div class="auth-url"> 1519 <a id="antigravityAuthUrl" href="#" target="_blank">ç¹å»æ¤é¾æ¥è¿è¡è®¤è¯</a> 1520 </div> 1521 <div class="status info"> 1522 <strong>使ç¨è¯´æï¼</strong> 1523 <ol style="margin: 10px 0; padding-left: 20px;"> 1524 <li>ç¹å»ä¸æ¹è®¤è¯é¾æ¥ï¼å¨æ°çªå£ä¸å®æ Google ææ</li> 1525 <li>æææååä¼è·³è½¬å° localhost æ¾ç¤ºæå页é¢</li> 1526 <li>å ³é OAuth çªå£ï¼è¿åæ¬é¡µé¢</li> 1527 <li>ç¹å»ä¸æ¹"è·ååè¯"æé®å®ææµç¨</li> 1528 </ol> 1529 </div> 1530 1531 <!-- å¿«æ·åè°URLè¾å ¥é项 --> 1532 <div class="form-group" 1533 style="margin: 20px 0; padding: 15px; border: 2px solid #e8f4fd; border-radius: 8px; background: #f8fcff;"> 1534 <div style="cursor: pointer; user-select: none; display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;" 1535 onclick="toggleAntigravityCallbackUrlSection()"> 1536 <span style="font-weight: bold; color: #0066cc;">ð æ æ³åæºï¼è¯è¯å¿«æ·æ¹å¼</span> 1537 <span id="antigravityCallbackUrlToggleIcon" 1538 style="font-size: 14px; color: #666; transition: transform 0.3s ease;">â¼</span> 1539 </div> 1540 <div id="antigravityCallbackUrlSection" style="display: none;"> 1541 <div 1542 style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 12px; margin-bottom: 12px;"> 1543 <div style="color: #856404; font-size: 14px; font-weight: bold; margin-bottom: 6px;">ð 1544 éç¨åºæ¯ï¼</div> 1545 <ul 1546 style="color: #856404; font-size: 13px; margin: 0; padding-left: 18px; line-height: 1.5;"> 1547 <li>äºæå¡å¨ãVPSç鿬å°ç¯å¢</li> 1548 <li>é²ç«å¢é»æ¢äº11451端å£è®¿é®</li> 1549 <li>ç½ç»ç¯å¢æ æ³æ£å¸¸åæºå°localhost</li> 1550 <li>Docker容å¨å è¿è¡ï¼ç«¯å£æ å°é®é¢</li> 1551 </ul> 1552 </div> 1553 <div style="color: #666; font-size: 13px; margin-bottom: 12px; line-height: 1.6;"> 1554 <strong style="color: #0066cc;">ð ä»ä¹æ¯åè°URLï¼</strong><br> 1555 宿Google OAuthææåï¼æµè§å¨å°åæ æ¾ç¤ºç宿´URLï¼é常çèµ·æ¥åè¿æ ·ï¼<br> 1556 <code 1557 style="background: #f1f3f4; padding: 2px 6px; border-radius: 3px; font-size: 12px; word-break: break-all;"> 1558 http://localhost:11451/?state=abc123...&code=4/0AVMBsJ...&scope=email%20profile... 1559 </code> 1560 </div> 1561 <div 1562 style="background: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 6px; padding: 10px; margin-bottom: 12px;"> 1563 <div style="color: #0066cc; font-size: 13px; font-weight: bold; margin-bottom: 4px;">ð 1564 ä½¿ç¨æ¥éª¤ï¼</div> 1565 <ol 1566 style="color: #0066cc; font-size: 12px; margin: 0; padding-left: 18px; line-height: 1.4;"> 1567 <li>ç¹å»ä¸æ¹è®¤è¯é¾æ¥ï¼å®æGoogleææ</li> 1568 <li>æææååï¼å¤å¶æµè§å¨å°åæ ç<strong>宿´URL</strong></li> 1569 <li>ç²è´´å°ä¸æ¹è¾å ¥æ¡ï¼ç¹å»è·ååè¯å³å¯</li> 1570 </ol> 1571 </div> 1572 <div class="input-group"> 1573 <input type="url" id="antigravityCallbackUrlInput" 1574 placeholder="ç²è´´å®æ´çåè°URLï¼ä¾å¦ï¼http://localhost:11451/?state=xxx&code=xxx&scope=xxx..." 1575 style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 4px; font-size: 13px;"> 1576 </div> 1577 <button class="btn" style="margin-top: 10px;" onclick="processAntigravityCallbackUrl()"> 1578 ä»åè°URLè·ååè¯ 1579 </button> 1580 </div> 1581 </div> 1582 1583 <button class="btn" id="getAntigravityCredsBtn" onclick="getAntigravityCredentials()">è·å Antigravity 1584 åè¯</button> 1585 1586 <div id="antigravityCredsSection" class="hidden"> 1587 <h3>
1587Antigravity åè¯å 容ï¼</h3> 1588 <div class="credentials"> 1589 <pre id="antigravityCredsContent"></pre> 1590 </div> 1591 <button class="btn" onclick="downloadAntigravityCredentials()">ä¸è½½åè¯æä»¶</button> 1592 </div> 1593 </div> 1594 </div> 1595 1596 <!-- æ¹éä¸ä¼ æ ç¾é¡µ --> 1597 <div id="uploadTab" class="tab-content"> 1598 <h3>æ¹éä¸ä¼ è®¤è¯æä»¶</h3> 1599 <p>æ¯ææ¹éä¸ä¼ GCLI å Antigravity è®¤è¯æä»¶</p> 1600 1601 <!-- GCLIåè¯ä¸ä¼ åºå --> 1602 <div 1603 style="margin-bottom: 30px; padding: 20px; border: 2px solid #e1e4e8; border-radius: 8px; background: #f8f9fa;"> 1604 <h4 style="margin-top: 0; color: #007bff; border-bottom: 2px solid #007bff; padding-bottom: 10px;"> 1605 ð¤ GCLI åè¯æ¹éä¸ä¼ </h4> 1606 1607 <div class="upload-area" id="uploadArea" onclick="document.getElementById('fileInput').click()"> 1608 <p>ç¹å»éæ©æä»¶æææ½æä»¶å°æ¤åºå</p> 1609 <p style="color: #666; font-size: 14px;">æ¯æ .json å .zip æ ¼å¼æä»¶</p> 1610 <p style="color: #888; font-size: 12px;">ZIPæä»¶ä¼èªå¨è§£åæåå ¶ä¸çJSONåè¯</p> 1611 </div> 1612 1613 <input type="file" id="fileInput" multiple accept=".json,.zip" style="display: none;" 1614 onchange="handleFileSelect(event)" /> 1615 1616 <div id="fileListSection" class="hidden"> 1617 <h4>éæ©çæä»¶ï¼</h4> 1618 <div class="file-list" id="fileList"></div> 1619 <button class="btn" onclick="uploadFiles()">ä¸ä¼ æä»¶</button> 1620 <button class="btn" onclick="clearFiles()">æ¸ ç©ºå表</button> 1621 </div> 1622 1623 <div id="uploadProgressSection" class="hidden"> 1624 <div class="upload-progress"> 1625 <h4>ä¸ä¼ è¿åº¦ï¼</h4> 1626 <div class="progress-bar"> 1627 <div class="progress-fill" id="progressFill" style="width: 0%"></div> 1628 </div> 1629 <p id="progressText">0%</p> 1630 </div> 1631 </div> 1632 </div> 1633 1634 <!-- Antigravityåè¯ä¸ä¼ åºå --> 1635 <div style="padding: 20px; border: 2px solid #e1e4e8; border-radius: 8px; background: #f8f9fa;"> 1636 <h4 style="margin-top: 0; color: #28a745; border-bottom: 2px solid #28a745; padding-bottom: 10px;"> 1637 ð¤ Antigravity åè¯æ¹éä¸ä¼ </h4> 1638 1639 <div class="upload-area" style="border-color: #28a745;" 1640 onclick="document.getElementById('antigravityFileInput').click()" 1641 ondragover="event.preventDefault(); this.style.borderColor='#28a745'; this.style.backgroundColor='#e7f9e7';" 1642 ondragleave="this.style.borderColor='#ddd'; this.style.backgroundColor='#fafafa';" 1643 ondrop="handleAntigravityFileDrop(event)"> 1644 <p>ç¹å»éæ©æä»¶æææ½æä»¶å°æ¤åºå</p> 1645 <p style="color: #666; font-size: 14px;">æ¯æ .json å .zip æ ¼å¼æä»¶</p> 1646 <p style="color: #888; font-size: 12px;">ZIPæä»¶ä¼èªå¨è§£åæåå ¶ä¸çJSONåè¯</p> 1647 </div> 1648 1649 <input type="file" id="antigravityFileInput" multiple accept=".json,.zip" style="display: none;" 1650 onchange="handleAntigravityFileSelect(event)" /> 1651 1652 <div id="antigravityFileListSection" class="hidden"> 1653 <h4>éæ©çæä»¶ï¼</h4> 1654 <div class="file-list" id="antigravityFileList"></div> 1655 <button class="btn" onclick="uploadAntigravityFiles()">ä¸ä¼ æä»¶</button> 1656 <button class="btn" onclick="clearAntigravityFiles()">æ¸ ç©ºå表</button> 1657 </div> 1658 1659 <div id="antigravityUploadProgressSection" class="hidden"> 1660 <div class="upload-progress"> 1661 <h4>ä¸ä¼ è¿åº¦ï¼</h4> 1662 <div class="progress-bar"> 1663 <div class="progress-fill" id="antigravityProgressFill" style="width: 0%"></div> 1664 </div> 1665 <p id="antigravityProgressText">0%</p> 1666 </div> 1667 </div> 1668 </div> 1669 </div> 1670 1671 <!-- GCLIåè¯ç®¡çæ ç¾é¡µ --> 1672 <div id="manageTab" class="tab-content"> 1673 <h3>GCLIåè¯æä»¶ç®¡ç</h3> 1674 <p>ç®¡çææGCLIè®¤è¯æä»¶ï¼æ¥çç¶æåæ§è¡æä½</p> 1675 <div 1676 style="background:#f0f7ff;border:1px solid #b8d4f0;border-radius:6px;padding:10px 14px;margin:8px 0;font-size:13px;"> 1677 <strong>ð¡ APIå°åï¼ç¹å»å¤å¶ï¼ï¼</strong> 1678 <table style="margin-top:6px;border-collapse:collapse;width:100%;"> 1679 <tr> 1680 <td style="color:#666;width:90px;">OpenAIæ ¼å¼</td> 1681 <td><code id="gcliOpenaiUrl" onclick="cpUrl(this)" title="ç¹å»å¤å¶" 1682 style="background:#e8f0fe;padding:2px 6px;border-radius:3px;
1682cursor:pointer;"></code> 1683 </td> 1684 </tr> 1685 <tr> 1686 <td style="color:#666;">Claudeæ ¼å¼</td> 1687 <td><code id="gcliClaudeUrl" onclick="cpUrl(this)" title="ç¹å»å¤å¶" 1688 style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> 1689 </td> 1690 </tr> 1691 <tr> 1692 <td style="color:#666;">Geminiæ ¼å¼</td> 1693 <td><code id="gcliGeminiUrl" onclick="cpUrl(this)" title="ç¹å»å¤å¶" 1694 style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> 1695 </td> 1696 </tr> 1697 </table> 1698
1698<script> 1699 (function () { var o = window.location.origin; document.getElementById('gcliOpenaiUrl').textContent = o + '/v1'; document.getElementById('gcliClaudeUrl').textContent = o + '/v1'; document.getElementById('gcliGeminiUrl').textContent = o; })(); 1700 function cpUrl(el) { navigator.clipboard.writeText(el.textContent).then(function () { var s = el.style.background; el.style.background = '#b7f0b7'; setTimeout(function () { el.style.background = s; }, 800); }); } 1701 </script>
1701 1702 </div> 1703 1704 <!-- æ£éªåè½è¯´æ --> 1705 <div class="status info" style="margin-bottom: 20px;"> 1706 <strong>ð¡ æ£éªåè½è¯´æï¼</strong> 1707 <p style="margin: 10px 0;"> 1708 ç¹å»æ¯ä¸ªåè¯ç"æ£éª"æé®å¯ä»¥éæ°è·åProject ID, å¹¶æ¥çè´¦å·çtier(free/pro/ultra)ã<br> 1709 <strong style="color: #0c5460;">â æ£éªæåå¯ä»¥æ¢å¤403é误</strong>ï¼è®©åè¯éæ°æ£å¸¸å·¥ä½ã<br> 1710 建议å¨éå°403é误æ¶ä½¿ç¨æ¤åè½ã 1711 </p> 1712 <strong>ð¡ 设置é¢è§åè½è¯´æï¼</strong> 1713 <p style="margin: 10px 0;"> 1714 ç¹å»æ¯ä¸ªåè¯ç"设置é¢è§"æé®å¯ä»¥é ç½®Previewééã<br> 1715 <strong style="color: #0c5460;">â 设置é¢è§å¯ä»¥è§£å³é¨ååè¯è°ç¨previewæ¨¡åæ¶404çé®é¢</strong>ã<br> 1716 建议å¨è°ç¨gemini-3-pro-previewçæ¨¡åéå°404é误æ¶ä½¿ç¨æ¤åè½ã 1717 </p> 1718 </div> 1719 1720 <!-- ç¶æç»è®¡ --> 1721 <div class="stats-container" id="statsContainer"> 1722 <div class="stat-item total"> 1723 <span class="stat-number" id="statTotal">0</span> 1724 <span class="stat-label">æ»è®¡</span> 1725 </div> 1726 <div class="stat-item normal"> 1727 <span class="stat-number" id="statNormal">0</span> 1728 <span class="stat-label">æ£å¸¸</span> 1729 </div> 1730 <div class="stat-item disabled"> 1731 <span class="stat-number" id="statDisabled">0</span> 1732 <span class="stat-label">ç¦ç¨</span> 1733 </div> 1734 </div> 1735 1736 <div class="manage-actions"> 1737 <button class="refresh-btn" onclick="refreshCredsStatus()">å·æ°ç¶æ</button> 1738 <button class="download-all-btn" onclick="downloadAllCreds()">æå ä¸è½½æææä»¶</button> 1739 </div> 1740 1741 <!-- æ¹éæä½æ§ä»¶ --> 1742 <div class="batch-controls"> 1743 <h4 style="margin-top: 0; margin-bottom: 10px;">æ¹éæä½</h4> 1744 <div class="batch-actions"> 1745 <div class="checkbox-container"> 1746 <input type="checkbox" id="selectAllCheckbox" class="select-all-checkbox" 1747 onchange="toggleSelectAll()"> 1748 <label for="selectAllCheckbox">å ¨é</label> 1749 </div> 1750 <span class="selected-count" id="selectedCount">已鿩 0 项</span> 1751 <button class="batch-btn batch-enable" id="batchEnableBtn" onclick="batchAction('enable')" 1752 disabled>æ¹éå¯ç¨</button> 1753 <button class="batch-btn batch-disable" id="batchDisableBtn" onclick="batchAction('disable')" 1754 disabled>æ¹éç¦ç¨</button> 1755 <button class="batch-btn batch-delete" id="batchDeleteBtn" onclick="batchAction('delete')" 1756 disabled>æ¹éå é¤</button> 1757 <button class="batch-btn" id="batchVerifyBtn" onclick="batchVerifyProjectIds()" 1758 disabled>æ¹éæ£éª</button> 1759 <button class="batch-btn" id="batchPreviewBtn" onclick="batchConfigurePreview()" 1760 disabled>æ¹é设置é¢è§</button> 1761 <button class="batch-btn batch-email" onclick="refreshAllEmails()">å·æ°ææé®ç®±</button> 1762 <button class="batch-btn" onclick="deduplicateByEmail()">åè¯ä¸é®å»é</button> 1763 </div> 1764 </div> 1765 1766 <!-- çéåå页æ§ä»¶ --> 1767 <div class="filter-container"> 1768 <label for="statusFilter">åè¯ç¶æï¼</label> 1769 <select id="statusFilter" class="filter-select" onchange="applyStatusFilter()"> 1770 <option value="all">å ¨é¨åè¯</option> 1771 <option value="enabled">ä» å¯ç¨</option> 1772 <option value="disabled">ä» ç¦ç¨</option> 1773 </select> 1774 1775 <label for="errorCodeFilter" style="margin-left: 20px;">é误ç ï¼</label> 1776 <select id="errorCodeFilter" class="filter-select" onchange="applyStatusFilter()"> 1777 <option value="all">å ¨é¨</option> 1778 <option value="none">æ é误</option> 1779 <option value="400">400</option> 1780 <option value="403">403</option> 1781 <option value="429">429</option> 1782 <option value="500">500</option> 1783 </select> 1784 1785 <label for="cooldownFilter" style="margin-left: 20px;">å·å´ç¶æï¼</label> 1786 <select id="cooldownFilter" class="filter-select" onchange="applyStatusFilter()"> 1787 <option value="all">å ¨é¨</option> 1788 <option value="in_cooldown">CDä¸</option> 1789 <option value="no_cooldown">æªCD</option> 1790 </select> 1791 1792 <label for="previewFilter" style="margin-left: 20px;">Previewï¼</label> 1793 <select id="previewFilter" class="filter-select" onchange="applyStatusFilter()"> 1794 <option value="all">å ¨é¨</option> 1795 <option value="preview">æ¯æ</option> 1796 <option value="no_preview">䏿¯æ</option> 1797 </select> 1798 1799 <label for="tierFilter" style="margin-left: 20px;">Tierï¼</label> 1800 <select id="tierFilter" class="filter-select" onchange="applyStatusFilter()"> 1801 <option value="all">å ¨é¨</option> 1802 <option value="free">Free</option> 1803 <option value="pro">Pro</option> 1804 <option value="ultra">Ultra</option> 1805 </select> 1806 1807 <label for="pageSizeSelect" style="margin-left: 20px;">æ¯é¡µæ¾ç¤ºï¼</label> 1808 <select id="pageSizeSelect" class="page-size-select" onchange="changePageSize()"> 1809 <option value="20">20</option> 1810 <option value="50">50</option> 1811 <option value="100">100</option> 1812 <option value="200">200</option> 1813 <option value="500">500</option> 1814 <option value="1000">1000</option> 1815 </select> 1816 </div> 1817 1818 <div id="credsListSection"> 1819 <div class="loading" id="credsLoading">æ£å¨å è½½åè¯æä»¶...</div> 1820 <div id="credsList"></div> 1821 1822 <!-- å页æ§ä»¶ --> 1823 <div class="pagination-container" id="paginationContainer" style="display: none;"> 1824 <button class="pagination-btn" id="prevPageBtn" onclick="changePage(-1)">ä¸ä¸é¡µ</button> 1825 <div class="pagination-info" id="paginationInfo">第 1 页ï¼å ± 1 页</div> 1826 <button class="pagination-btn" id="nextPageBtn" onclick="changePage(1)">ä¸ä¸é¡µ</button> 1827 </div> 1828 </div> 1829 </div> 1830 1831 <!-- Antigravity åè¯ç®¡çæ ç¾é¡µ --> 1832 <div id="antigravity-manageTab" class="tab-content"> 1833 <h3>
1833Antigravityåè¯æä»¶ç®¡ç</h3> 1834 <p>ç®¡çææAntigravityè®¤è¯æä»¶ï¼æ¥çç¶æåæ§è¡æä½</p> 1835 <div 1836 style="background:#f0f7ff;border:1px solid #b8d4f0;border-radius:6px;padding:10px 14px;margin:8px 0;font-size:13px;"> 1837 <strong>ð¡ APIå°åï¼ç¹å»å¤å¶ï¼ï¼</strong> 1838 <table style="margin-top:6px;border-collapse:collapse;width:100%;"> 1839 <tr> 1840 <td style="color:#666;width:90px;">OpenAIæ ¼å¼</td> 1841 <td><code id="antOpenaiUrl" onclick="cpUrl(this)" title="ç¹å»å¤å¶" 1842 style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> 1843 </td> 1844 </tr> 1845 <tr> 1846 <td style="color:#666;">Claudeæ ¼å¼</td> 1847 <td><code id="antClaudeUrl" onclick="cpUrl(this)" title="ç¹å»å¤å¶" 1848 style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> 1849 </td> 1850 </tr> 1851 <tr> 1852 <td style="color:#666;">Geminiæ ¼å¼</td> 1853 <td><code id="antGeminiUrl" onclick="cpUrl(this)" title="ç¹å»å¤å¶" 1854 style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> 1855 </td> 1856 </tr> 1857 </table> 1858
1858<script> 1859 (function () { var o2 = window.location.origin; document.getElementById('antOpenaiUrl').textContent = o2 + '/antigravity/v1'; document.getElementById('antClaudeUrl').textContent = o2 + '/antigravity/v1'; document.getElementById('antGeminiUrl').textContent = o2 + '/antigravity'; })(); 1860 </script>
1860 1861 </div> 1862 1863 <!-- æ£éªåè½è¯´æ --> 1864 <div class="status info" style="margin-bottom: 20px;"> 1865 <strong>ð¡ æ£éªåè½è¯´æï¼</strong> 1866 <p style="margin: 10px 0;"> 1867 ç¹å»æ¯ä¸ªåè¯ç"æ£éª"æé®å¯ä»¥éæ°è·åProject ID, å¹¶æ¥çè´¦å·çtier(free/pro/ultra)ã<br> 1868 <strong style="color: #0c5460;">â æ£éªæåå¯ä»¥æ¢å¤403é误</strong>ï¼è®©åè¯éæ°æ£å¸¸å·¥ä½ã<br> 1869 建议å¨éå°403é误æ¶ä½¿ç¨æ¤åè½ã 1870 </p> 1871 </div> 1872 1873 <!-- ç¶æç»è®¡ --> 1874 <div class="stats-container" id="antigravityStatsContainer"> 1875 <div class="stat-item total"> 1876 <span class="stat-number" id="antigravityStatTotal">0</span> 1877 <span class="stat-label">æ»è®¡</span> 1878 </div> 1879 <div class="stat-item normal"> 1880 <span class="stat-number" id="antigravityStatNormal">0</span> 1881 <span class="stat-label">æ£å¸¸</span> 1882 </div> 1883 <div class="stat-item disabled"> 1884 <span class="stat-number" id="antigravityStatDisabled">0</span> 1885 <span class="stat-label">ç¦ç¨</span> 1886 </div> 1887 </div> 1888 1889 <div class="manage-actions"> 1890 <button class="refresh-btn" onclick="refreshAntigravityCredsList()">å·æ°ç¶æ</button> 1891 <button class="download-all-btn" onclick="downloadAllAntigravityCreds()">æå ä¸è½½æææä»¶</button> 1892 </div> 1893 1894 <!-- æ¹éæä½æ§ä»¶ --> 1895 <div class="batch-controls"> 1896 <h4 style="margin-top: 0; margin-bottom: 10px;">æ¹éæä½</h4> 1897 <div class="batch-actions"> 1898 <div class="checkbox-container"> 1899 <input type="checkbox" id="selectAllAntigravityCheckbox" class="select-all-checkbox" 1900 onchange="toggleSelectAllAntigravity()"> 1901 <label for="selectAllAntigravityCheckbox">å ¨é</label> 1902 </div> 1903 <span class="selected-count" id="antigravitySelectedCount">已鿩 0 项</span> 1904 <button class="batch-btn batch-enable" id="antigravityBatchEnableBtn" 1905 onclick="batchAntigravityAction('enable')" disabled>æ¹éå¯ç¨</button> 1906 <button class="batch-btn batch-disable" id="antigravityBatchDisableBtn" 1907 onclick="batchAntigravityAction('disable')" disabled>æ¹éç¦ç¨</button> 1908 <button class="batch-btn batch-delete" id="antigravityBatchDeleteBtn" 1909 onclick="batchAntigravityAction('delete')" disabled>æ¹éå é¤</button> 1910 <button class="batch-btn" id="antigravityBatchEnableCreditBtn" 1911 onclick="batchAntigravityAction('enable_credit')" disabled>æ¹éå¼å¯ç§¯å</button> 1912 <button class="batch-btn" id="antigravityBatchDisableCreditBtn" 1913 onclick="batchAntigravityAction('disable_credit')" disabled>æ¹éå ³é积å</button> 1914 <button class="batch-btn" id="antigravityBatchVerifyBtn" 1915 onclick="batchVerifyAntigravityProjectIds()" disabled>æ¹éæ£éª</button> 1916 <button class="batch-btn batch-email" onclick="refreshAllAntigravityEmails()">å·æ°ææé®ç®±</button> 1917 <button class="batch-btn" onclick="deduplicateAntigravityByEmail()">åè¯ä¸é®å»é</button> 1918 </div> 1919 </div> 1920 1921 <!-- çéåå页æ§ä»¶ --> 1922 <div class="filter-container"> 1923 <label for="antigravityStatusFilter">åè¯ç¶æï¼</label> 1924 <select id="antigravityStatusFilter" class="filter-select" 1925 onchange="applyAntigravityStatusFilter()"> 1926 <option value="all">å ¨é¨åè¯</option> 1927 <option value="enabled">ä» å¯ç¨</option> 1928 <option value="disabled">ä» ç¦ç¨</option> 1929 </select> 1930 1931 <label for="antigravityErrorCodeFilter" style="margin-left: 20px;">é误ç ï¼</label> 1932 <select id="antigravityErrorCodeFilter" class="filter-select" 1933 onchange="applyAntigravityStatusFilter()"> 1934 <option value="all">å ¨é¨</option> 1935 <option value="none">æ é误</option> 1936 <option value="400">400</option> 1937 <option value="403">403</option> 1938 <option value="429">429</option> 1939 <option value="500">500</option> 1940 </select> 1941 1942 <label for="antigravityCooldownFilter" style="margin-left: 20px;">å·å´ç¶æï¼</label> 1943 <select id="antigravityCooldownFilter" class="filter-select" 1944 onchange="applyAntigravityStatusFilter()"> 1945 <option value="all">å ¨é¨</option> 1946 <option value="in_cooldown">CDä¸</option> 1947 <option value="no_cooldown">æªCD</option> 1948 </select> 1949 1950 <label for="antigravityTierFilter" style="margin-left: 20px;">Tierï¼</label> 1951 <select id="antigravityTierFilter" class="filter-select" onchange="applyAntigravityStatusFilter()"> 1952 <option value="all">å ¨é¨</option> 1953 <option value="free">Free</option> 1954 <option value="pro">Pro</option> 1955 <option value="ultra">Ultra</option> 1956 </select> 1957 1958 <label for="antigravityPageSizeSelect" style="margin-left: 20px;">æ¯é¡µæ¾ç¤ºï¼</label> 1959 <select id="antigravityPageSizeSelect" class="page-size-select" 1960 onchange="changeAntigravityPageSize()"> 1961 <option value="20">20</option> 1962 <option value="50">50</option> 1963 <option value="100">100</option> 1964 <option value="200">200</option> 1965 <option value="500">500</option> 1966 <option value="1000">1000</option> 1967 </select> 1968 </div> 1969 1970 <div id="antigravityCredsListSection"> 1971 <div class="loading" id="antigravityCredsLoading">æ£å¨å è½½åè¯æä»¶...</div> 1972 <div id="antigravityCredsList"></div> 1973 1974 <!-- å页æ§ä»¶ --> 1975 <div class="pagination-container" id="antigravityPaginationContainer" style="display: none;"> 1976 <button class="pagination-btn" id="antigravityPrevPageBtn" 1977 onclick="changeAntigravityPage(-1)">ä¸ä¸é¡µ</button> 1978 <div class="pagination-info" id="antigravityPaginationInfo">第 1 页ï¼å ± 1 页</div> 1979 <button class="pagination-btn" id="antigravityNextPageBtn" 1980 onclick="changeAntigravityPage(1)">ä¸ä¸é¡µ</button> 1981 </div> 1982 </div> 1983 </div> 1984 1985 <!-- é ç½®ç®¡çæ ç¾é¡µ --> 1986 <div id="configTab" class="tab-content"> 1987 <h3>é 置管ç</h3> 1988 <p>管çç³»ç»é ç½®åæ°ï¼ä¿®æ¹åç«å³çæ</p> 1989 1990 <div class="manage-actions"> 1991 <button class="refresh-btn" onclick="loadConfig()">å·æ°é ç½®</button> 1992 <button class="btn" onclick="saveConfig()">ä¿åé ç½®</button> 1993 </div> 1994 1995 <div id="configSection"> 1996 <div class="loading" id="configLoading">æ£å¨å è½½é ç½®...</div> 1997 <div id="configForm" class="hidden"> 1998 <div class="config-group"> 1999 <h4>æå¡å¨é ç½®</h4> 2000 2001 <div class="form-group"> 2002 <label for="host">æå¡å¨ä¸»æºå°å:</label> 2003 <input type="text" id="host" class="config-input"
2004 placeholder="ä¾å¦: 0.0.0.0, 127.0.0.1" /> 2005 <small class="config-note">æå¡å¨çå¬ç主æºå°åï¼0.0.0.0表示çå¬æææ¥å£</small> 2006 </div> 2007 2008 <div class="form-group"> 2009 <label for="port">æå¡å¨ç«¯å£:</label> 2010 <input type="number" id="port" class="config-input" min="1" max="65535" 2011 placeholder="7861" /> 2012 <small class="config-note">æå¡å¨çå¬ç端å£å·ï¼ä¿®æ¹åéè¦é坿å¡å¨</small> 2013 </div> 2014 2015 <div class="form-group"> 2016 <label for="configApiPassword">API访é®å¯ç :</label> 2017 <input type="text" id="configApiPassword" class="config-input" placeholder="pwd" /> 2018 <small class="config-note">è天API访é®å¯ç ï¼ç¨äºOpenAIåGemini API端ç¹ç认è¯</small> 2019 </div> 2020 2021 <div class="form-group"> 2022 <label for="configPanelPassword">æ§å¶é¢æ¿å¯ç :</label> 2023 <input type="text" id="configPanelPassword" class="config-input" placeholder="pwd" /> 2024 <small class="config-note">æ§å¶é¢æ¿è®¿é®å¯ç ï¼ç¨äºwebçé¢ç»å½è®¤è¯</small> 2025 </div> 2026 2027 <div class="form-group"> 2028 <label for="configPassword">éç¨å¯ç :</label> 2029 <input type="text" id="configPassword" class="config-input" placeholder="pwd" /> 2030 <small class="config-note">ï¼å ¼å®¹æ§ä¿çï¼è®¾ç½®åå°è¦çä¸è¿°ä¸¤ä¸ªå¯ç ï¼ç空å使ç¨åå¼çå¯ç 设置</small> 2031 </div> 2032 </div> 2033 2034 <div class="config-group"> 2035 <h4>åºç¡é ç½®</h4> 2036 2037 <div class="form-group"> 2038 <label for="credentialsDir">åè¯ç®å½è·¯å¾:</label> 2039 <input type="text" id="credentialsDir" class="config-input" /> 2040 <small class="config-note">åå¨è®¤è¯æä»¶çç®å½è·¯å¾</small> 2041 </div> 2042 2043 <div class="form-group"> 2044 <label for="proxy">代ç设置:</label> 2045 <input type="text" id="proxy" class="config-input"
2046 placeholder="ä¾å¦: http://proxy:11451 æ socks5://proxy:1080" /> 2047 <small class="config-note">HTTP/HTTPS/SOCKS5Endpointï¼ç空表示ä¸ä½¿ç¨ä»£ç</small> 2048 </div> 2049 </div> 2050 2051 <div class="config-group"> 2052 <h4>端ç¹é ç½®</h4> 2053 2054 <!-- å¿«éé ç½®æé® --> 2055 <div class="form-group"> 2056 <div style="display: flex; gap: 10px; margin-bottom: 15px; flex-wrap: wrap;"> 2057 <button type="button" class="btn" onclick="useMirrorUrls()" 2058 style="font-size: 14px;"> 2059 ð ä¸é®ä½¿ç¨éåç½å 2060 </button> 2061 <button type="button" class="btn" onclick="restoreOfficialUrls()" 2062 style="font-size: 14px;"> 2063 ð è¿å宿¹ç«¯ç¹ 2064 </button> 2065 </div> 2066 <small class="config-note">éåç½å主è¦è§£å³å¢å æ æ³è®¿é®å®æ¹ç«¯ç¹çé®é¢ï¼é¨åå°åºå¯è½æ æ³ä½¿ç¨</small> 2067 </div> 2068 2069 <div class="form-group"> 2070 <label for="codeAssistEndpoint">Code Assist Endpoint:</label> 2071 <input type="text" id="codeAssistEndpoint" class="config-input" /> 2072 <small class="config-note">Google Cloud Code Assist API端ç¹å°å</small> 2073 </div> 2074 <div class="form-group"> 2075 <label for="oauthProxyUrl">OAuth Endpoint:</label> 2076 <input type="text" id="oauthProxyUrl" class="config-input" 2077 placeholder="https://oauth2.googleapis.com" /> 2078 <small class="config-note">Google OAuth2 API端ç¹å°åï¼ç¨äºtokenè·ååå·æ°</small> 2079 </div> 2080 <div class="form-group"> 2081 <label for="googleapisProxyUrl">Google APIs Endpoint:</label> 2082 <input type="text" id="googleapisProxyUrl" class="config-input" 2083 placeholder="https://www.googleapis.com" /> 2084 <small class="config-note">Google APIs API端ç¹å°åï¼ç¨äºAPIæå¡è°ç¨</small> 2085 </div> 2086 <div class="form-group"> 2087 <label for="resourceManagerApiUrl">Resource Manager API Endpoint:</label> 2088 <input type="text" id="resourceManagerApiUrl" class="config-input" 2089 placeholder="https://cloudresourcemanager.googleapis.com" /> 2090 <small class="config-note">Google Cloud Resource Manager API端ç¹å°åï¼ç¨äºé¡¹ç®ç®¡ç</small> 2091 </div> 2092 <div class="form-group"> 2093 <label for="serviceUsageApiUrl">Service Usage API Endpoint:</label> 2094 <input type="text" id="serviceUsageApiUrl" class="config-input" 2095 placeholder="https://serviceusage.googleapis.com" /> 2096 <small class="config-note">Google Cloud Service Usage API端ç¹å°åï¼ç¨äºæå¡å¯ç¨ç®¡ç</small> 2097 </div> 2098 <div class="form-group"> 2099 <label for="antigravityApiUrl">Antigravity API Endpoint:</label> 2100 <input type="text" id="antigravityApiUrl" class="config-input" 2101 placeholder="https://daily-cloudcode-pa.googleapis.com" /> 2102 <small class="config-note">Google Antigravity API端ç¹å°åï¼ç¨äºåé忍¡å¼</small> 2103 </div> 2104 </div> 2105 2106 <div class="config-group"> 2107 <h4>èªå¨å°ç¦é ç½®</h4> 2108 2109 <div class="form-group"> 2110 <label> 2111 <input type="checkbox" id="autoBanEnabled" class="config-checkbox" /> 2112 å¯ç¨èªå¨å°ç¦ 2113 </label> 2114 <small class="config-note">éå°æå®éè¯¯ç æ¶èªå¨ç¦ç¨åè¯</small> 2115 </div> 2116 2117 <div class="form-group"> 2118 <label for="autoBanErrorCodes">èªå¨å°ç¦é误ç :</label> 2119 <input type="text" id="autoBanErrorCodes" class="config-input"
2120 placeholder="ä¾å¦: 400,403" /> 2121 <small class="config-note">ç¨éå·åéçé误ç å表</small> 2122 </div> 2123 </div> 2124 2125 <div class="config-group"> 2126 <h4>éè¯é ç½®</h4> 2127 2128 <div class="form-group"> 2129 <label> 2130 <input type="checkbox" id="retry429Enabled" class="config-checkbox" /> 2131 å¯ç¨é误éè¯ 2132 </label> 2133 <small class="config-note">éå°é误æ¶èªå¨éè¯</small> 2134 </div> 2135 2136 <div class="form-group"> 2137 <label for="retry429MaxRetries">é误éè¯æ¬¡æ°:</label> 2138 <input type="number" id="retry429MaxRetries" class="config-input" min="1" max="50" /> 2139 <small class="config-note">éå°é误æ¶çæå¤§éè¯æ¬¡æ°</small> 2140 </div> 2141 2142 <div class="form-group"> 2143 <label for="retry429Interval">é误éè¯é´é(ç§):</label> 2144 <input type="number" id="retry429Interval" class="config-input" min="0.01" max="10" 2145 step="0.01" /> 2146 <small class="config-note">éå°éè¯¯æ¶æ¯ä¸¤æ¬¡éè¯é´ççå¾ æ¶é´</small> 2147 </div> 2148 </div> 2149 2150 2151 <div class="config-group"> 2152 <h4>å ¼å®¹æ§é ç½®</h4> 2153 2154 <div class="form-group"> 2155 <label> 2156 <input type="checkbox" id="compatibilityModeEnabled" class="config-checkbox" /> 2157 å¯ç¨å ¼å®¹æ§æ¨¡å¼ 2158 </label> 2159 <small class="config-note">å¯ç¨åææsystemæ¶æ¯å ¨é¨è½¬æ¢æuserï¼åç¨system_instructions <span 2160 style="color: #28a745;">â æ¯æçæ´æ°</span></small> 2161 <div class="config-info" 2162 style="background-color: #fff3cd; border: 1px solid #ffc107; color: #856404;"> 2163 <strong>â ï¸ æ³¨æï¼</strong>该é项å¯è½ä¼é使¨¡åçè§£è½åï¼ä½æ¯è½é¿å æµå¼ç©ºåçæ åµã 2164 <br><strong>éç¨åºæ¯ï¼</strong>å½éå°æµå¼ä¼ è¾æ¶æ¨¡åä¸è¿åå 容æè¿å空ååºæ¶å¯ç¨æ¤é项ã 2165 </div> 2166 </div> 2167 2168 <div class="form-group"> 2169 <label> 2170 <input type="checkbox" id="returnThoughtsToFrontend" class="config-checkbox" /> 2171 è¿åæç»´é¾å°å端 2172 </label> 2173 <small class="config-note">å¯ç¨åï¼æ¨¡åçæç»´é¾ä¼å¨ååºä¸è¿åï¼ç¦ç¨åï¼æç»´é¾ä¼è¢«è¿æ»¤æ <span 2174 style="color: #28a745;">â æ¯æçæ´æ°</span></small> 2175 <div class="config-info" 2176 style="background-color: #e3f2fd; border: 1px solid #2196f3; color: #0d47a1;"> 2177 <strong>ð 说æï¼</strong>æäºæ¨¡åï¼å¦Gemini 2.0 2178 Proï¼æ¯æthinking模å¼ï¼ä¼å¨çæåçåå è¾åºæèè¿ç¨ãå¯ç¨åå¯ä»¥çå°æ¨¡åçæèè¿ç¨ï¼ç¦ç¨ååªæ¾ç¤ºæç»åçï¼è®©è¾åºæ´ç®æ´ã 2179 </div> 2180 </div> 2181 2182 <div class="form-group"> 2183 <label> 2184 <input type="checkbox" id="antigravityStream2nostream" class="config-checkbox" /> 2185 Antigravityæµå¼è½¬éæµå¼ 2186 </label> 2187 <small class="config-note">å¯ç¨åï¼éæµå¼è¯·æ±å°ä½¿ç¨æµå¼APIå¹¶æ¶éä¸ºå®æ´ååº <span style="color: #28a745;">â 2188 æ¯æçæ´æ°</span></small> 2189 <div class="config-info" 2190 style="background-color: #f3e5f5; border: 1px solid #9c27b0; color: #4a148c;"> 2191 <strong>ð 2192 说æï¼</strong>é对Antigravity模å¼çä¼åé项ãå¯ç¨åï¼å³ä½¿å®¢æ·ç«¯è¯·æ±éæµå¼ååºï¼å端ä¹ä¼ä½¿ç¨æµå¼APIè·åæ°æ®å¹¶æ¶é宿´ååè¿åã 2193 <br><strong>éç¨åºæ¯ï¼</strong>æäºæ åµä¸æµå¼APIæ¯éæµå¼APIæ´ç¨³å®ï¼å¯ç¨æ¤é项å¯ä»¥æé«ååºè´¨éã 2194 <br><strong>é»è®¤ï¼</strong>å·²å¯ç¨ 2195 </div> 2196 </div> 2197 2198 <div class="form-group"> 2199 <label> 2200 <input type="checkbox" id="antigravitySwitchCredentialEnabled" class="config-checkbox" /> 2201 Antigravity忢åè¯ 2202 </label> 2203 <small class="config-note">å¯ç¨åéè¯æ¶åæ¢åè¯ï¼ç¦ç¨æ¶ä¿æå½ååè¯ï¼ç´å°è¯¥åè¯å¯¹å½å模åè¿å ¥CDæè¢«ç¦ç¨ <span 2204 style="color: #28a745;">â æ¯æçæ´æ°</span></small> 2205 <div class="config-info" 2206 style="background-color: #e8f5e9; border: 1px solid #66bb6a; color: #1b5e20;"> 2207 <strong>â 说æï¼</strong>é»è®¤å ³éï¼ä¾¿äºè¿ç»ä½¿ç¨åä¸åè¯ï¼å½åçæ¨¡åCDæèªå¨ç¦ç¨æ¶ä»ä¼åæ¢ã 2208 </div> 2209 </div> 2210 </div> 2211 2212 <div class="config-group"> 2213 <h4>ææªæé ç½®</h4> 2214 2215 <div class="form-group"> 2216 <label for="antiTruncationMaxAttempts">ææªææå¤§éè¯æ¬¡æ°:</label> 2217 <input type="number" id="antiTruncationMaxAttempts" class="config-input" min="1" 2218 max="10" /> 2219 <small class="config-note">彿£æµå°è¾åºæªææ¶çæå¤§ç»ä¼ å°è¯æ¬¡æ°</small> 2220 </div> 2221 2222 <div class="form-group"> 2223 <div class="config-info"> 2224 <strong>注æï¼</strong>ææªæåè½ç°å¨éè¿æ¨¡ååæ§å¶ï¼ 2225 <ul style="margin: 5px 0; padding-left: 20px;"> 2226 <li>鿩另æ "-æµå¼ææªæ" åç¼ç模åå³å¯å¯ç¨</li> 2227 <li>该åè½ä» 卿µå¼ä¼ è¾æ¶çæ</li> 2228 <li>ä¾å¦: "gemini-2.5-pro-æµå¼ææªæ"</li> 2229 </ul> 2230 </div> 2231 </div> 2232 </div> 2233 2234 <div class="config-group"> 2235 <h4>ä¿æ´»é ç½®</h4> 2236 2237 <div class="form-group"> 2238 <label for="keepaliveUrl">ä¿æ´» URL:</label> 2239 <input type="text" id="keepaliveUrl" class="config-input" 2240 placeholder="ç空åä¸å¯ç¨ï¼ä¾å¦: https://your-app.example.com/keepalive" /> 2241 <small class="config-note">é ç½®åæå¡ä¼å®æå该 URL åé GET 请æ±ä»¥ä¿æå¨çº¿ï¼ç空åç¦ç¨ä¿æ´» <span 2242 style="color: #28a745;">â æ¯æçæ´æ°</span></small> 2243 <button type="button" onclick="autoSetKeepaliveUrl()" 2244 style="margin-top:6px; padding:4px 12px; font-size:13px; cursor:pointer;">ä¸é®è®¾ç½®ä¿æ´»</button> 2245 </div> 2246 2247 <div class="form-group"> 2248 <label for="keepaliveInterval">ä¿æ´»é´é (ç§):</label> 2249 <input type="number" id="keepaliveInterval" class="config-input" min="5" max="86400" /> 2250 <small class="config-note">ä¸¤æ¬¡ä¿æ´»è¯·æ±ä¹é´ççå¾ æ¶é´ï¼èå´ 5 - 86400 ç§ï¼é»è®¤ 60 <span 2251 style="color: #28a745;">â æ¯æçæ´æ°</span></small> 2252 </div> 2253 </div> 2254 2255 <div class="config-group"> 2256 <h4>é ç½®çæ´æ°è¯´æ</h4> 2257 2258 <div class="form-group"> 2259 <div class="config-info" 2260 style="background-color: #d4edda; border: 1px solid #c3e6cb; color: #155724;"> 2261 <strong>ð¥ çæ´æ°é ç½®ï¼ç«å³çæï¼ï¼</strong> 2262 <ul style="margin: 8px 0; padding-left: 20px; color: #212529;"> 2263 <li><strong>ç½ç»é ç½®ï¼</strong>代ç设置ã端ç¹é ç½®ãHTTPè¶ æ¶æ¶é´ãæå¤§è¿æ¥æ°</li> 2264 <li><strong>APIé ç½®ï¼</strong>åè¯è½®æ¢æ¬¡æ°ãé误éè¯è®¾ç½®ãèªå¨å°ç¦é ç½®</li> 2265 <li><strong>å¯ç é ç½®ï¼</strong>APIå¯ç ãæ§å¶é¢æ¿å¯ç ãéç¨å¯ç </li> 2266 <li><strong>åè½é ç½®ï¼</strong>ææªææå¤§éè¯æ¬¡æ°</li> 2267 </ul> 2268 </div> 2269 </div> 2270 2271 <div class="form-group"> 2272 <div class="config-info" 2273 style="background-color: #fff3cd; border: 1px solid #ffc107; color: #856404;"> 2274 <strong>ð éè¦éå¯çé ç½®ï¼</strong> 2275 <ul style="margin: 8px 0; padding-left: 20px; color: #212529;"> 2276 <li><strong>æå¡å¨é ç½®ï¼</strong>主æºå°åã端å£å·</li> 2277 <li><strong>ç®å½é ç½®ï¼</strong>åè¯ç®å½è·¯å¾ãCode Assist端ç¹</li> 2278 </ul> 2279 </div> 2280 </div> 2281 2282 </div> 2283 </div> 2284 </div> 2285 </div> 2286 2287 <!-- 宿¶æ¥å¿æ ç¾é¡µ --> 2288 <div id="logsTab" class="tab-content"> 2289 <h3>宿¶æ¥å¿</h3> 2290 <p>æ¥çç³»ç»å®æ¶æ¥å¿è¾åºï¼æ¯ææ¥å¿çéåèªå¨æ»å¨</p> 2291 2292 <div class="manage-actions"> 2293 <button class="refresh-btn" onclick="connectWebSocket()">è¿æ¥æ¥å¿æµ</button> 2294 <button class="btn" onclick="disconnectWebSocket()">æå¼è¿æ¥</button> 2295 <button class="btn" onclick="downloadLogs()">ä¸è½½æ¥å¿</button> 2296 <button class="btn" onclick="clearLogs()">æ¸ ç©ºæ¥å¿</button> 2297 </div> 2298 2299 <div class="filter-container"> 2300 <label for="logLevelFilter">æ¥å¿çº§å«çéï¼</label> 2301 <select id="logLevelFilter" class="filter-select" onchange="filterLogs()"> 2302 <option value="all">å ¨é¨</option> 2303 <option value="ERROR">é误</option> 2304 <option value="WARNING">
2304è¦å</option> 2305 <option value="INFO">ä¿¡æ¯</option> 2306 <option value="DEBUG">è°è¯</option> 2307 </select> 2308 2309 <label> 2310 <input type="checkbox" id="autoScroll" checked> èªå¨æ»å¨å°åºé¨ 2311 </label> 2312 </div> 2313 2314 <div id="logConnectionStatus" class="status info"> 2315 <strong>è¿æ¥ç¶æï¼</strong> <span id="connectionStatusText">æªè¿æ¥</span> 2316 </div> 2317 2318 <div id="logContainer" 2319 style="background-color: #1e1e1e; color: #ffffff; font-family: 'Courier New', monospace; font-size: 12px; height: 600px; overflow-y: auto; border: 1px solid #333; border-radius: 5px; padding: 15px; white-space: pre-wrap; word-break: break-all;"> 2320 <div id="logContent">çå¾ è¿æ¥æ¥å¿æµ...</div> 2321 </div> 2322 </div> 2323 2324 <!-- 项ç®ä¿¡æ¯æ ç¾é¡µ --> 2325 <div id="aboutTab" class="tab-content"> 2326 <h3>项ç®ä¿¡æ¯</h3> 2327 <p>å ³äºGCLI2API项ç®ç详ç»ä¿¡æ¯åæ¯ææ¹å¼</p> 2328 2329 <!-- 项ç®ä»ç» --> 2330 <div 2331 style="background-color: #f8f9fa; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #007bff;"> 2332 <h4 style="margin-top: 0; color: #007bff;">ð 项ç®ç®ä»</h4> 2333 <p style="margin: 10px 0; line-height: 1.6; color: #495057;"> 2334 GCLI2APIæ¯ä¸ä¸ªå°Google Gemini API转æ¢ä¸ºOpenAI åGEMINI APIæ ¼å¼ç代çå·¥å ·ï¼æ¯æå¤è´¦æ·ç®¡çãèªå¨è½®æ¢ã宿¶æ¥å¿çæ§çåè½ã 2335 </p> 2336 <div style="margin: 15px 0;"> 2337 <p style="margin: 5px 0;"><strong>ð 项ç®å°åï¼</strong> <a 2338 href="https://github.com/su-kaka/gcli2api" target="_blank" 2339 style="color: #007bff; text-decoration: none;">GitHub - su-kaka/gcli2api</a></p> 2340 <p style="margin: 5px 0;"><strong>â ï¸ ä½¿ç¨å£°æï¼</strong> <span 2341 style="color: #dc3545; font-weight: 500;">ç¦æ¢åä¸ç¨éååå - ä» ä¾å¦ä¹ 使ç¨</span></p> 2342 </div> 2343 </div> 2344 2345 <!-- åè½ç¹æ§ --> 2346 <div 2347 style="background-color: #e7f3ff; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #17a2b8;"> 2348 <h4 style="margin-top: 0; color: #17a2b8;">⨠主è¦åè½</h4> 2349 <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 15px;"> 2350 <div> 2351 <p><strong>ð å¤è´¦æ·ç®¡çï¼</strong> æ¯ææ¹éä¸ä¼ å管çå¤ä¸ªGoogleè´¦æ·</p> 2352 <p><strong>â¡ èªå¨è½®æ¢ï¼</strong> æºè½è½®æ¢è´¦æ·ï¼é¿å åè´¦æ·éé¢</p> 2353 <p><strong>ð 宿¶çæ§ï¼</strong> 使ç¨ç»è®¡ãéè¯¯çæ§ã宿¶æ¥å¿</p> 2354 </div> 2355 <div> 2356 <p><strong>ð¡ï¸ å®å ¨å¯é ï¼</strong> OAuth2认è¯ãèªå¨å°ç¦å¼å¸¸è´¦æ·</p> 2357 <p><strong>ðï¸ é ç½®çµæ´»ï¼</strong> æ¯æçæ´æ°é ç½®ã代ç设置</p> 2358 <p><strong>ð± çé¢å好ï¼</strong> ååºå¼è®¾è®¡ãç§»å¨ç«¯éé </p> 2359 </div> 2360 </div> 2361 </div> 2362 2363 <!-- 交æµç¾¤ --> 2364 <div 2365 style="background-color: #e7f3ff; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #4285f4; text-align: center;"> 2366 <h4 style="margin-top: 0; color: #1976d2;">ð¬ 交æµç¾¤</h4> 2367 <div style="color: #1565c0; line-height: 1.6;"> 2368 <p>欢è¿å å ¥ QQ 群交æµè®¨è®ºï¼</p> 2369 <p style="font-size: 18px; font-weight: bold; color: #4285f4;">QQ 群å·ï¼1083250744</p> 2370 </div> 2371 <div 2372 style="display: inline-block; background: white; padding: 15px; border-radius: 12px; box-shadow: 0 2px 15px rgba(0,0,0,0.1); margin-top: 10px;"> 2373 <img src="docs/qq群.jpg" alt="QQ群äºç»´ç " 2374 style="width: 200px; height: 200px; border-radius: 8px; display: block;"> 2375 <p 2376 style="color: #666; margin: 10px 0 0 0; font-size: 13px; font-weight: 600; text-align: center;"> 2377 æ«ç å å ¥QQ群</p> 2378 </div> 2379 </div> 2380 2381 <!-- èç³»ååé¦ --> 2382 <div 2383 style="background-color: #d1ecf1; padding: 20px; border-radius: 10px; margin: 20px 0; border-left: 4px solid #bee5eb;"> 2384 <h4 style="margin-top: 0; color: #0c5460;">ð èç³»æä»¬</h4> 2385 <div style="color: #0c5460; line-height: 1.6;"> 2386 <p>⢠<strong>é®é¢åé¦ï¼</strong> éè¿GitHub Issuesæäº¤é®é¢å建议</p> 2387 <p>⢠<strong>åè½è¯·æ±ï¼</strong> å¨GitHub Discussionsä¸è®¨è®ºæ°åè½</p> 2388 <p>⢠<strong>代ç è´¡ç®ï¼</strong> æ¬¢è¿æäº¤Pull Requestæ¹è¿é¡¹ç®</p> 2389 <p>⢠<strong>ææ¡£å®åï¼</strong> 叮婿¹è¿é¡¹ç®ææ¡£åä½¿ç¨æå</p> 2390 </div> 2391 </div> 2392 </div> 2393 2394 <div id="statusSection"></div> 2395 2396 <!-- 项ç®ä¿¡æ¯ --> 2397 <div 2398 style="background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px; padding: 12px; margin-top: 30px; text-align: center; border-left: 4px solid #007bff;"> 2399 <p style="margin: 5px 0; font-size: 14px; color: #495057;">GitHub: <a 2400 href="https://github.com/su-kaka/gcli2api" target="_blank" 2401 style="color: #007bff; text-decoration: none;">https://github.com/su-kaka/gcli2api</a></p> 2402 <p style="margin: 5px 0; font-size: 14px; color: #dc3545; font-weight: 500;">â ï¸ ç¦æ¢åä¸ç¨éååå - ä» ä¾å¦ä¹ ä½¿ç¨ â ï¸ 2403 </p> 2404 </div> 2405 </div> 2406 </div> 2407 2408 <!-- å¼å ¥å ¬å ±JavaScript模å --> 2409
2409<script src="./front/common.js"></script>
2409 2410 2411</body> 2412 2413</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.