(credInfo, manager)
| 631 | // 凭证卡片创建(通用) |
| 632 | // ===================================================================== |
| 633 | function createCredCard(credInfo, manager) { |
| 634 | const div = document.createElement('div'); |
| 635 | const { status, filename } = credInfo; |
| 636 | const managerType = manager.type; |
| 637 | |
| 638 | // 卡片样式 |
| 639 | div.className = status.disabled ? 'cred-card disabled' : 'cred-card'; |
| 640 | |
| 641 | // 状态徽章 |
| 642 | let statusBadges = ''; |
| 643 | statusBadges += status.disabled |
| 644 | ? '<span class="status-badge disabled">已禁用</span>' |
| 645 | : '<span class="status-badge enabled">已启用</span>'; |
| 646 | |
| 647 | if (status.error_codes && status.error_codes.length > 0) { |
| 648 | statusBadges += `<span class="error-codes">错误码: ${status.error_codes.join(', ')}</span>`; |
| 649 | const autoBan = status.error_codes.filter(c => c === 400 || c === 403); |
| 650 | if (autoBan.length > 0 && status.disabled) { |
| 651 | statusBadges += '<span class="status-badge" style="background-color: #e74c3c; color: white;">AUTO_BAN</span>'; |
| 652 | } |
| 653 | } else { |
| 654 | statusBadges += '<span class="status-badge" style="background-color: #28a745; color: white;">无错误</span>'; |
| 655 | } |
| 656 | |
| 657 | // Preview状态显示 (仅对geminicli模式显示) |
| 658 | if (managerType !== 'antigravity' && credInfo.preview !== undefined) { |
| 659 | if (credInfo.preview) { |
| 660 | statusBadges += '<span class="status-badge" style="background-color: #28a745; color: white;" title="该凭证支持Preview模型">Preview: ON</span>'; |
| 661 | } else { |
| 662 | statusBadges += '<span class="status-badge" style="background-color: #8aa5a2; color: white;" title="该凭证不支持Preview模型">Preview: OFF</span>'; |
| 663 | } |
| 664 | } |
| 665 | |
| 666 | // tier 状态显示 (geminicli 和 antigravity 都显示) |
| 667 | const tier = (credInfo.tier || 'pro').toString().toLowerCase(); |
| 668 | const tierLabel = tier.toUpperCase(); |
| 669 | const tierColor = tier === 'ultra' ? '#ff9800' : (tier === 'free' ? '#607d8b' : '#2e7d32'); |
| 670 | statusBadges += `<span class="status-badge" style="background-color: ${tierColor}; color: white;" title="凭证等级: ${tierLabel}">Tier: ${tierLabel}</span>`; |
| 671 | |
| 672 | // Credit 状态显示(仅 antigravity) |
| 673 | if (managerType === 'antigravity') { |
| 674 | if (credInfo.enable_credit) { |
| 675 | statusBadges += '<span class="status-badge" style="background-color: #2e7d32; color: white;" title="当前已开启Credit模式">Credit: ON</span>'; |
| 676 | } else { |
| 677 | statusBadges += '<span class="status-badge" style="background-color: #616161; color: white;" title="当前已关闭Credit模式">Credit: OFF</span>'; |
| 678 | } |
| 679 | } |
| 680 | |
| 681 | // 模型级冷却状态 |
| 682 | if (credInfo.model_cooldowns && Object.keys(credInfo.model_cooldowns).length > 0) { |
| 683 | const currentTime = Date.now() / 1000; |
| 684 | const activeCooldowns = Object.entries(credInfo.model_cooldowns) |
| 685 | .filter(([, until]) => until > currentTime) |
| 686 | .map(([model, until]) => { |
| 687 | const remaining = Math.max(0, Math.floor(until - currentTime)); |
| 688 | const shortModel = model.replace('gemini-', '').replace('-exp', '') |
| 689 | .replace('2.0-', '2-').replace('1.5-', '1.5-'); |
| 690 | return { |
no test coverage detected