debug-panel.component.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import { Component, signal } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { DouyinService } from '../../services/douyin.service';
  5. @Component({
  6. selector: 'app-debug-panel',
  7. standalone: true,
  8. imports: [CommonModule, FormsModule],
  9. template: `
  10. <div class="debug-panel">
  11. <h2>🔧 API调试面板</h2>
  12. <div class="debug-section">
  13. <h3>Token状态</h3>
  14. <div class="token-info">
  15. <p><strong>当前Token:</strong></p>
  16. <code>{{ currentToken }}</code>
  17. <button (click)="testToken()" class="debug-btn">测试Token</button>
  18. </div>
  19. <div *ngIf="tokenTestResult" class="test-result">
  20. <strong>测试结果:</strong>
  21. <pre>{{ tokenTestResult | json }}</pre>
  22. </div>
  23. </div>
  24. <div class="debug-section">
  25. <h3>搜索测试</h3>
  26. <div class="input-group">
  27. <input
  28. [(ngModel)]="searchKeyword"
  29. placeholder="搜索关键词"
  30. class="debug-input"
  31. />
  32. <button
  33. (click)="debugSearch()"
  34. [disabled]="isSearching"
  35. class="debug-btn"
  36. >
  37. {{ isSearching ? '搜索中...' : '调试搜索' }}
  38. </button>
  39. </div>
  40. <div *ngIf="searchResult" class="test-result">
  41. <strong>搜索结果:</strong>
  42. <pre>{{ searchResult | json }}</pre>
  43. </div>
  44. <div *ngIf="searchError" class="error-result">
  45. <strong>搜索错误:</strong>
  46. <pre>{{ searchError }}</pre>
  47. </div>
  48. </div>
  49. <div class="debug-section">
  50. <h3>网络诊断</h3>
  51. <button (click)="testNetwork()" class="debug-btn">测试网络连接</button>
  52. <div *ngIf="networkStatus" class="test-result">
  53. <strong>网络状态:</strong>
  54. <p>{{ networkStatus }}</p>
  55. </div>
  56. </div>
  57. <div class="debug-section">
  58. <h3>CORS测试</h3>
  59. <button (click)="testCORS()" class="debug-btn">测试CORS支持</button>
  60. <div *ngIf="corsStatus" class="test-result">
  61. <strong>CORS状态:</strong>
  62. <p>{{ corsStatus }}</p>
  63. </div>
  64. </div>
  65. </div>
  66. `,
  67. styles: [`
  68. .debug-panel {
  69. padding: 20px;
  70. max-width: 800px;
  71. margin: 0 auto;
  72. font-family: Arial, sans-serif;
  73. }
  74. .debug-section {
  75. margin-bottom: 30px;
  76. padding: 20px;
  77. border: 1px solid #ddd;
  78. border-radius: 8px;
  79. background: #f9f9f9;
  80. }
  81. .debug-section h3 {
  82. margin-top: 0;
  83. color: #333;
  84. }
  85. .input-group {
  86. display: flex;
  87. gap: 10px;
  88. margin: 15px 0;
  89. }
  90. .debug-input {
  91. flex: 1;
  92. padding: 8px 12px;
  93. border: 1px solid #ccc;
  94. border-radius: 4px;
  95. font-size: 14px;
  96. }
  97. .debug-btn {
  98. padding: 8px 16px;
  99. background: #007bff;
  100. color: white;
  101. border: none;
  102. border-radius: 4px;
  103. cursor: pointer;
  104. font-size: 14px;
  105. }
  106. .debug-btn:disabled {
  107. background: #ccc;
  108. cursor: not-allowed;
  109. }
  110. .debug-btn:hover:not(:disabled) {
  111. background: #0056b3;
  112. }
  113. .token-info {
  114. margin: 10px 0;
  115. }
  116. .token-info code {
  117. display: block;
  118. background: #f0f0f0;
  119. padding: 10px;
  120. border-radius: 4px;
  121. margin: 10px 0;
  122. word-break: break-all;
  123. font-size: 12px;
  124. }
  125. .test-result {
  126. margin-top: 15px;
  127. }
  128. .test-result pre {
  129. background: #e8f5e8;
  130. padding: 15px;
  131. border-radius: 4px;
  132. overflow-x: auto;
  133. max-height: 300px;
  134. overflow-y: auto;
  135. border-left: 4px solid #28a745;
  136. font-size: 12px;
  137. }
  138. .error-result {
  139. margin-top: 15px;
  140. }
  141. .error-result pre {
  142. background: #ffe6e6;
  143. padding: 15px;
  144. border-radius: 4px;
  145. overflow-x: auto;
  146. border-left: 4px solid #dc3545;
  147. color: #721c24;
  148. font-size: 12px;
  149. }
  150. `]
  151. })
  152. export class DebugPanelComponent {
  153. searchKeyword = '科技';
  154. isSearching = false;
  155. searchResult: any = null;
  156. searchError: any = null;
  157. tokenTestResult: any = null;
  158. networkStatus = '';
  159. corsStatus = '';
  160. // 硬编码Token
  161. currentToken = 'r:a5a19ea9868043b15d9b10423234ca43';
  162. constructor(private douyinService: DouyinService) {}
  163. testToken() {
  164. this.tokenTestResult = null;
  165. // 简单的Token格式验证
  166. if (this.currentToken.startsWith('r:') && this.currentToken.length > 10) {
  167. this.tokenTestResult = {
  168. status: '格式正确',
  169. format: 'Bearer Token',
  170. prefix: 'r:',
  171. length: this.currentToken.length,
  172. message: 'Token格式看起来正确'
  173. };
  174. } else {
  175. this.tokenTestResult = {
  176. status: '格式错误',
  177. message: 'Token格式不符合预期'
  178. };
  179. }
  180. }
  181. debugSearch() {
  182. if (!this.searchKeyword.trim() || this.isSearching) return;
  183. this.isSearching = true;
  184. this.searchResult = null;
  185. this.searchError = null;
  186. console.log('开始调试搜索:', {
  187. keyword: this.searchKeyword,
  188. service: this.douyinService
  189. });
  190. this.douyinService.searchVideos(
  191. this.searchKeyword,
  192. '0', // sortType
  193. 0, // cursor
  194. '0', // publishTime
  195. '0', // filterDuration
  196. '0' // contentType
  197. ).subscribe({
  198. next: (result) => {
  199. console.log('搜索成功:', result);
  200. this.searchResult = result;
  201. this.isSearching = false;
  202. },
  203. error: (error) => {
  204. console.error('搜索失败详细错误:', error);
  205. this.searchError = {
  206. message: error.message,
  207. status: error.status,
  208. statusText: error.statusText,
  209. name: error.name,
  210. stack: error.stack,
  211. fullError: error
  212. };
  213. this.isSearching = false;
  214. }
  215. });
  216. }
  217. async testNetwork() {
  218. this.networkStatus = '正在测试网络连接...';
  219. try {
  220. const startTime = Date.now();
  221. const response = await fetch('https://www.baidu.com', {
  222. method: 'HEAD',
  223. mode: 'no-cors'
  224. });
  225. const endTime = Date.now();
  226. this.networkStatus = `网络连接正常 ✅\n响应时间: ${endTime - startTime}ms`;
  227. } catch (error) {
  228. const errorMessage = error instanceof Error ? error.message : '未知错误';
  229. this.networkStatus = `网络连接异常 ❌\n错误: ${errorMessage}`;
  230. }
  231. }
  232. async testCORS() {
  233. this.corsStatus = '正在测试CORS支持...';
  234. try {
  235. const response = await fetch('https://server.fmode.cn/api/voc-social/douyin/search/fetch_general_search_v2', {
  236. method: 'OPTIONS',
  237. headers: {
  238. 'Origin': window.location.origin,
  239. 'Access-Control-Request-Method': 'POST',
  240. 'Access-Control-Request-Headers': 'content-type,authorization'
  241. }
  242. });
  243. const corsHeaders = {
  244. 'Access-Control-Allow-Origin': response.headers.get('Access-Control-Allow-Origin'),
  245. 'Access-Control-Allow-Methods': response.headers.get('Access-Control-Allow-Methods'),
  246. 'Access-Control-Allow-Headers': response.headers.get('Access-Control-Allow-Headers')
  247. };
  248. this.corsStatus = `CORS预检请求完成\n状态: ${response.status}\n响应头: ${JSON.stringify(corsHeaders, null, 2)}`;
  249. } catch (error) {
  250. const errorMessage = error instanceof Error ? error.message : '未知错误';
  251. this.corsStatus = `CORS测试失败 ❌\n错误: ${errorMessage}\n这可能是导致API调用失败的原因`;
  252. }
  253. }
  254. }