Procházet zdrojové kódy

feat: show available API service list after login (no more static prompt)

gangvy před 5 měsíci
rodič
revize
2e4ed7ebc0
3 změnil soubory, kde provedl 116 přidání a 36 odebrání
  1. 24 11
      src/app/app.html
  2. 53 23
      src/app/app.scss
  3. 39 2
      src/app/app.ts

+ 24 - 11
src/app/app.html

@@ -39,18 +39,31 @@
     </div>
   </div>
 
-  <!-- Missing apigId prompt -->
-  <div class="missing-apig-prompt" *ngIf="loggedInUser && !apigId && !needLogin">
-    <div class="prompt-icon">
-      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
-        <circle cx="12" cy="12" r="10"/>
-        <line x1="12" y1="16" x2="12" y2="12"/>
-        <line x1="12" y1="8" x2="12.01" y2="8"/>
-      </svg>
+  <!-- API Service List (after login, no apigId) -->
+  <div class="apig-list-section" *ngIf="loggedInUser && !apigId && !needLogin">
+    <h3 class="apig-list-title">选择要充值的 API 服务</h3>
+
+    <!-- Loading -->
+    <div class="apig-list-loading" *ngIf="apigListLoading">
+      <span class="polling-dot"></span> 加载服务列表...
+    </div>
+
+    <!-- List -->
+    <div class="apig-list-grid" *ngIf="!apigListLoading && apigList.length > 0">
+      <div class="apig-list-card neu-raised" *ngFor="let item of apigList" (click)="navigateToApig(item.objectId)">
+        <div class="apig-list-card-title">{{item.title}}</div>
+        <div class="apig-list-card-desc">{{item.content || '专业API数据服务'}}</div>
+        <div class="apig-list-card-price" *ngIf="item.priceStep && item.priceStep.length > 0">
+          <span class="symbol">¥</span>{{item.priceStep[0].price}} 起
+        </div>
+        <div class="apig-list-card-arrow">→</div>
+      </div>
+    </div>
+
+    <!-- Empty -->
+    <div class="apig-list-empty" *ngIf="!apigListLoading && apigList.length === 0">
+      暂无可用的 API 服务
     </div>
-    <h3>登录成功</h3>
-    <p>请通过包含 <code>apigid</code> 参数的链接访问此页面以进行充值。</p>
-    <p class="example-url">示例:<code>?apigid=xxx</code></p>
   </div>
 
   <!-- Error -->

+ 53 - 23
src/app/app.scss

@@ -125,35 +125,65 @@
   flex: 1;
 }
 
-/* ─── Missing ApigId Prompt ─── */
-.missing-apig-prompt {
-  text-align: center;
-  padding: 48px 24px;
+/* ─── API Service List ─── */
+.apig-list-section {
   margin-bottom: 24px;
 }
-.missing-apig-prompt .prompt-icon {
-  width: 56px; height: 56px;
-  margin: 0 auto 16px;
-  color: var(--neon);
-  opacity: 0.6;
+.apig-list-title {
+  margin: 0 0 16px; font-size: 16px;
+  font-weight: 700; color: var(--text-bright);
+  letter-spacing: 1px;
 }
-.missing-apig-prompt .prompt-icon svg { width: 100%; height: 100%; }
-.missing-apig-prompt h3 {
-  margin: 0 0 12px; font-size: 20px;
-  font-weight: 700; color: var(--success);
+.apig-list-loading {
+  text-align: center; padding: 32px;
+  color: var(--text-dim); font-size: 14px;
 }
-.missing-apig-prompt p {
-  margin: 0 0 8px; font-size: 14px;
-  color: var(--text-dim); line-height: 1.6;
+.apig-list-grid {
+  display: flex; flex-direction: column; gap: 12px;
 }
-.missing-apig-prompt code {
-  padding: 2px 8px; font-size: 13px;
-  background: rgba(0,212,255,0.1);
-  border: 1px solid rgba(0,212,255,0.2);
-  border-radius: 4px; color: var(--neon);
+.apig-list-card {
+  padding: 20px 24px;
+  cursor: pointer;
+  border: 1px solid transparent;
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
 }
-.missing-apig-prompt .example-url {
-  margin-top: 16px; font-size: 13px;
+.apig-list-card:hover {
+  border-color: var(--neon);
+  box-shadow:
+    4px 4px 8px var(--shadow-dark),
+    -4px -4px 8px var(--shadow-light),
+    0 0 12px var(--neon-glow);
+  transform: translateY(-1px);
+}
+.apig-list-card-title {
+  font-size: 16px; font-weight: 700;
+  color: var(--text-bright);
+}
+.apig-list-card-desc {
+  font-size: 13px; color: var(--text-dim);
+  line-height: 1.4;
+  overflow: hidden; text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.apig-list-card-price {
+  font-size: 18px; font-weight: 700;
+  color: var(--neon); margin-top: 4px;
+}
+.apig-list-card-price .symbol { font-size: 12px; }
+.apig-list-card-arrow {
+  position: absolute;
+  right: 20px; top: 50%;
+  transform: translateY(-50%);
+  font-size: 20px; color: var(--neon);
+  opacity: 0.4; transition: opacity 0.2s;
+}
+.apig-list-card:hover .apig-list-card-arrow { opacity: 1; }
+.apig-list-empty {
+  text-align: center; padding: 32px;
+  color: var(--text-dim); font-size: 14px;
 }
 
 /* ─── API Info Card ─── */

+ 39 - 2
src/app/app.ts

@@ -57,6 +57,8 @@ export class App implements OnInit {
   // Login state
   needLogin = false;
   loggedInUser: string = '';
+  apigList: ApigData[] = [];
+  apigListLoading = false;
 
   // State
   apig: ApigData | null = null;
@@ -116,8 +118,9 @@ export class App implements OnInit {
       this.validateCachedToken(cachedToken, cachedUserId);
       if (this.apigId) {
         this.loadApig();
+      } else {
+        this.loadApigList();
       }
-      // 即使没有 apigId,也不需要重新登录(模板会显示友好提示)
       return;
     }
 
@@ -154,12 +157,46 @@ export class App implements OnInit {
     this.errorMsg = '';
 
     if (!this.apigId) {
-      // 没有 apigId,模板会显示友好提示
+      this.loadApigList();
       return;
     }
     this.loadApig();
   }
 
+  // ─── Load available APIG list (when no apigId) ───
+  async loadApigList(): Promise<void> {
+    this.apigListLoading = true;
+    try {
+      const query: any = {
+        _method: 'GET',
+        where: JSON.stringify({ isVerified: true }),
+        keys: 'title,content,priceStep',
+        order: '-updatedAt',
+        limit: '20'
+      };
+      const resp = await fetch(API_BASE + '/parse/classes/APIG?' + new URLSearchParams(query), {
+        headers: { 'X-Parse-Application-Id': APP_ID }
+      });
+      const data = await resp.json();
+      if (data.results?.length > 0) {
+        this.apigList = data.results;
+        console.log('[APIG] 获取到', data.results.length, '个可用 API');
+      } else {
+        console.log('[APIG] 未查询到可用 API');
+      }
+    } catch (e: any) {
+      console.warn('[APIG] 查询 API 列表失败:', e.message);
+    } finally {
+      this.apigListLoading = false;
+    }
+  }
+
+  navigateToApig(apigId: string): void {
+    const url = new URL(window.location.href);
+    url.searchParams.set('apigid', apigId);
+    window.location.href = url.toString();
+  }
+
   // ─── Load APIG Info ───
   async loadApig(): Promise<void> {
     try {