app.html 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <!-- Login Modal -->
  2. <app-login-modal #loginModal (loginSuccess)="onLoginSuccess($event)"></app-login-modal>
  3. <!-- Header -->
  4. <div class="page-header">
  5. <div class="logo">BRAIN<span>HACK</span></div>
  6. <div class="subtitle">API 服务充值</div>
  7. <div class="user-bar" *ngIf="loggedInUser">
  8. <span class="user-badge">👤 已登录</span>
  9. </div>
  10. </div>
  11. <!-- Main -->
  12. <div class="main-container">
  13. <!-- API Info Card -->
  14. <div class="api-info-card neu-raised" *ngIf="!showSuccess && !needLogin">
  15. <div class="api-title" *ngIf="!apig">
  16. <span class="skeleton" style="display:inline-block;width:200px;height:24px;">&nbsp;</span>
  17. </div>
  18. <div class="api-title" *ngIf="apig">
  19. {{apig.title}}<span class="badge">HTTPS</span>
  20. </div>
  21. <div class="api-desc" *ngIf="!apig">
  22. <span class="skeleton" style="display:inline-block;width:100%;height:16px;margin-top:8px;">&nbsp;</span>
  23. </div>
  24. <div class="api-desc" *ngIf="apig">
  25. {{apig.content || '专业API数据服务'}}
  26. </div>
  27. <div class="api-stats" *ngIf="apig">
  28. <div class="stat-item">
  29. <span class="stat-label">当前余额</span>
  30. <span class="stat-value">{{apig.count != null ? apig.count + ' 次' : '—'}}</span>
  31. </div>
  32. <div class="stat-item">
  33. <span class="stat-label">服务状态</span>
  34. <span class="stat-value" style="color:var(--success);">正常</span>
  35. </div>
  36. </div>
  37. </div>
  38. <!-- Error -->
  39. <div class="error-bar" *ngIf="errorMsg">{{errorMsg}}</div>
  40. <!-- Tier Selection -->
  41. <ng-container *ngIf="!showSuccess && !needLogin">
  42. <div class="section-title">选择套餐</div>
  43. <div class="tier-grid" *ngIf="!apig || !apig.priceStep">
  44. <div class="tier-card neu-raised skeleton" style="height:100px;"></div>
  45. <div class="tier-card neu-raised skeleton" style="height:100px;"></div>
  46. <div class="tier-card neu-raised skeleton" style="height:100px;"></div>
  47. </div>
  48. <div class="tier-grid" *ngIf="apig && apig.priceStep">
  49. <div
  50. *ngFor="let tier of apig.priceStep; let i = index"
  51. class="tier-card"
  52. [class.neu-raised]="selectedIndex !== i"
  53. [class.neu-pressed]="selectedIndex === i"
  54. [class.active]="selectedIndex === i"
  55. (click)="selectTier(i)">
  56. <div class="tier-price"><span class="symbol">¥</span>{{tier.price}}</div>
  57. <div class="tier-count">含 {{tier.count}} {{unitLabel}}</div>
  58. <div class="tier-unit-price">≈ {{(tier.price / tier.count).toFixed(3)}} 元/{{unitLabel}}</div>
  59. </div>
  60. </div>
  61. <!-- Summary -->
  62. <div class="summary-bar neu-groove" *ngIf="selectedTier">
  63. <div>
  64. <div class="label">套餐配额</div>
  65. <div style="font-size:16px;font-weight:600;color:var(--text-bright);margin-top:2px;">
  66. {{selectedTier.count}} {{unitLabel}}
  67. </div>
  68. <div class="validity">有效期 730 天(自购买之日起)</div>
  69. </div>
  70. <div style="text-align:right;">
  71. <div class="label">应付金额</div>
  72. <div class="total"><span class="symbol">¥</span>{{selectedTier.price}}</div>
  73. </div>
  74. </div>
  75. <!-- Pay Button -->
  76. <button class="pay-btn" [disabled]="!apig || paying" (click)="startPayment()">
  77. <span *ngIf="!paying"><span class="btn-icon">💳</span> 微信支付</span>
  78. <span *ngIf="paying">正在生成支付码...</span>
  79. </button>
  80. </ng-container>
  81. <!-- Order History -->
  82. <div class="order-history" *ngIf="apig && !showSuccess">
  83. <div class="section-header">
  84. <div class="section-title">历史订单</div>
  85. <button class="refresh-btn" [disabled]="ordersLoading" (click)="loadOrderHistory()">刷新</button>
  86. </div>
  87. <div class="neu-groove" style="padding:2px 16px;overflow-x:auto;">
  88. <!-- Loading -->
  89. <div class="order-loading" *ngIf="ordersLoading && orders.length === 0">
  90. <span class="polling-dot"></span> 加载中...
  91. </div>
  92. <!-- Empty -->
  93. <div class="order-empty" *ngIf="!ordersLoading && orders.length === 0">
  94. <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
  95. <path d="M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2"/>
  96. <rect x="9" y="3" width="6" height="4" rx="1"/>
  97. </svg>
  98. 暂无订单记录
  99. </div>
  100. <!-- Table -->
  101. <table class="order-table" *ngIf="orders.length > 0">
  102. <thead>
  103. <tr><th>时间</th><th>套餐</th><th>金额</th><th>状态</th></tr>
  104. </thead>
  105. <tbody>
  106. <tr *ngFor="let o of orders">
  107. <td class="col-time">{{formatTime(o.createdAt)}}</td>
  108. <td class="col-count">{{formatCount(o)}}</td>
  109. <td class="col-amount">{{formatAmount(o)}}</td>
  110. <td><span class="order-status" [ngClass]="getStatusClass(o)">{{getStatusText(o)}}</span></td>
  111. </tr>
  112. </tbody>
  113. </table>
  114. <!-- Load more -->
  115. <button class="order-more-btn" *ngIf="hasMoreOrders" (click)="loadOrderHistory(true)">加载更多...</button>
  116. <!-- Error -->
  117. <div class="order-error" *ngIf="orderError">订单加载失败: {{orderError}}</div>
  118. </div>
  119. </div>
  120. <!-- Success Screen -->
  121. <div class="success-screen" [class.show]="showSuccess">
  122. <div class="success-icon">
  123. <svg viewBox="0 0 24 24" fill="none" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
  124. <polyline points="20 6 9 17 4 12"></polyline>
  125. </svg>
  126. </div>
  127. <div class="success-title">充值成功</div>
  128. <div class="success-detail" [innerHTML]="successDetailHtml"></div>
  129. <button class="back-btn" (click)="handleDone()">完成</button>
  130. </div>
  131. </div>
  132. <!-- QR Modal -->
  133. <div class="modal-overlay" [class.show]="showQrModal">
  134. <div class="modal-box neu-raised">
  135. <button class="modal-close" (click)="cancelPayment()">&times;</button>
  136. <div class="modal-title">微信扫码支付</div>
  137. <div class="modal-amount"><span class="symbol">¥</span>{{selectedTier?.price || 0}}</div>
  138. <div class="qr-wrapper">
  139. <canvas #qrCanvas></canvas>
  140. </div>
  141. <div class="scan-hint">
  142. <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  143. <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path>
  144. <circle cx="12" cy="13" r="4"></circle>
  145. </svg>
  146. 打开微信扫一扫
  147. </div>
  148. <div class="polling-status">
  149. <span *ngIf="!paySuccess" class="polling-dot"></span>
  150. <span *ngIf="!paySuccess">等待支付中...</span>
  151. <span *ngIf="paySuccess" style="color:var(--success);">✓ 支付成功,正在充值...</span>
  152. </div>
  153. </div>
  154. </div>