workinjury_test_debug.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>工伤接口调试工具</title>
  7. <style>
  8. body { font-family: 'Microsoft YaHei', sans-serif; margin: 20px; background: #f5f5f5; }
  9. .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
  10. .debug-section { margin: 15px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
  11. .debug-section h3 { margin-top: 0; color: #333; }
  12. button { padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }
  13. .btn-test { background: #007bff; color: white; }
  14. .btn-test:hover { background: #0056b3; }
  15. textarea { width: 100%; height: 200px; font-family: 'Consolas', monospace; font-size: 12px; border: 1px solid #ddd; border-radius: 4px; padding: 10px; }
  16. .status-success { background-color: #d4edda; border-color: #c3e6cb; color: #155724; }
  17. .status-error { background-color: #f8d7da; border-color: #f5c6cb; color: #721c24; }
  18. .status-warning { background-color: #fff3cd; border-color: #ffeaa7; color: #856404; }
  19. .info-box { padding: 10px; margin: 10px 0; border-radius: 4px; border: 1px solid; }
  20. .timestamp { font-size: 12px; color: #666; float: right; }
  21. </style>
  22. </head>
  23. <body>
  24. <div class="container">
  25. <h1>🔧 江苏工伤联网接口调试工具</h1>
  26. <p>专门用于诊断Status 200但无响应体的问题</p>
  27. <div class="debug-section">
  28. <h3>🚀 快速测试</h3>
  29. <button class="btn-test" onclick="testInit()">测试初始化</button>
  30. <button class="btn-test" onclick="testHealth()">测试健康检查</button>
  31. <button class="btn-test" onclick="testSignIn()">测试签到</button>
  32. <button class="btn-test" onclick="testSignOut()">测试签退</button>
  33. <button class="btn-test" onclick="clearLogs()">清空日志</button>
  34. </div>
  35. <div class="debug-section">
  36. <h3>📡 请求信息</h3>
  37. <div>
  38. <strong>请求URL:</strong> <span id="requestUrl">等待请求...</span>
  39. <span class="timestamp" id="requestTime"></span>
  40. </div>
  41. <div><strong>请求方法:</strong> POST</div>
  42. <div><strong>Content-Type:</strong> application/json</div>
  43. <div><strong>请求体:</strong></div>
  44. <textarea id="requestBody" readonly></textarea>
  45. </div>
  46. <div class="debug-section">
  47. <h3>📊 响应信息</h3>
  48. <div class="info-box" id="statusBox">
  49. <strong>状态:</strong> <span id="httpStatus">等待响应...</span>
  50. <span class="timestamp" id="responseTime"></span>
  51. </div>
  52. <div><strong>响应头:</strong></div>
  53. <textarea id="responseHeaders" readonly></textarea>
  54. <div><strong>响应体:</strong></div>
  55. <textarea id="responseBody" readonly></textarea>
  56. </div>
  57. <div class="debug-section">
  58. <h3>🔍 执行路径追踪</h3>
  59. <div id="executionPath"></div>
  60. </div>
  61. <div class="debug-section">
  62. <h3>📝 调试日志</h3>
  63. <div id="debugLogs"></div>
  64. </div>
  65. </div>
  66. <script>
  67. const BASE_URL = 'http://localhost:8321/api/entry/workinjury';
  68. function logMessage(message, type = 'info') {
  69. const logs = document.getElementById('debugLogs');
  70. const timestamp = new Date().toLocaleString();
  71. const logEntry = document.createElement('div');
  72. logEntry.className = `info-box status-${type === 'error' ? 'error' : type === 'warning' ? 'warning' : 'success'}`;
  73. logEntry.innerHTML = `<strong>[${timestamp}]</strong> ${message}`;
  74. logs.appendChild(logEntry);
  75. logs.scrollTop = logs.scrollHeight;
  76. }
  77. function clearLogs() {
  78. document.getElementById('debugLogs').innerHTML = '';
  79. document.getElementById('requestBody').value = '';
  80. document.getElementById('responseBody').value = '';
  81. document.getElementById('responseHeaders').value = '';
  82. document.getElementById('httpStatus').textContent = '等待响应...';
  83. document.getElementById('executionPath').innerHTML = '';
  84. }
  85. function updateRequestInfo(url, body) {
  86. document.getElementById('requestUrl').textContent = url;
  87. document.getElementById('requestTime').textContent = new Date().toLocaleString();
  88. document.getElementById('requestBody').value = JSON.stringify(body, null, 2);
  89. }
  90. function updateResponseInfo(status, headers, body, responseTime) {
  91. const statusBox = document.getElementById('statusBox');
  92. const statusSpan = document.getElementById('httpStatus');
  93. statusSpan.textContent = `${status}`;
  94. document.getElementById('responseTime').textContent = new Date(responseTime).toLocaleString();
  95. // 设置状态颜色
  96. statusBox.className = 'info-box ' + (status === 200 ? 'status-success' : 'status-error');
  97. // 显示响应头
  98. let headersText = '';
  99. if (headers) {
  100. for (let [key, value] of headers.entries()) {
  101. headersText += `${key}: ${value}\n`;
  102. }
  103. }
  104. document.getElementById('responseHeaders').value = headersText;
  105. // 显示响应体
  106. if (body) {
  107. document.getElementById('responseBody').value = JSON.stringify(body, null, 2);
  108. // 追踪执行路径
  109. updateExecutionPath(body);
  110. } else {
  111. document.getElementById('responseBody').value = '(无响应体或响应体为空)';
  112. logMessage('⚠️ 关键问题:Status 200但响应体为空!', 'error');
  113. }
  114. }
  115. function updateExecutionPath(responseBody) {
  116. const pathDiv = document.getElementById('executionPath');
  117. pathDiv.innerHTML = '';
  118. if (responseBody && typeof responseBody === 'object') {
  119. const steps = [];
  120. // 收集所有debug_step信息
  121. for (let key in responseBody) {
  122. if (key.startsWith('debug_')) {
  123. steps.push(`<strong>${key}:</strong> ${responseBody[key]}`);
  124. }
  125. }
  126. if (steps.length > 0) {
  127. pathDiv.innerHTML = '<div class="info-box status-success">' + steps.join('<br>') + '</div>';
  128. } else {
  129. pathDiv.innerHTML = '<div class="info-box status-warning">响应中无调试信息</div>';
  130. }
  131. } else {
  132. pathDiv.innerHTML = '<div class="info-box status-error">无法解析响应体</div>';
  133. }
  134. }
  135. async function makeRequest(action, additionalParams = {}) {
  136. const requestTime = Date.now();
  137. const requestBody = {
  138. action: action,
  139. timestamp: new Date().toISOString(),
  140. ...additionalParams
  141. };
  142. updateRequestInfo(BASE_URL, requestBody);
  143. logMessage(`🚀 发送请求: ${action}`, 'info');
  144. try {
  145. const response = await fetch(BASE_URL, {
  146. method: 'POST',
  147. headers: {
  148. 'Content-Type': 'application/json',
  149. 'Accept': 'application/json'
  150. },
  151. body: JSON.stringify(requestBody)
  152. });
  153. const responseTime = Date.now();
  154. logMessage(`📡 收到响应: ${response.status} ${response.statusText}`, response.ok ? 'success' : 'error');
  155. let responseBody = null;
  156. const contentType = response.headers.get('content-type');
  157. if (contentType && contentType.includes('application/json')) {
  158. try {
  159. responseBody = await response.json();
  160. logMessage('✅ 响应体解析成功', 'success');
  161. } catch (jsonError) {
  162. logMessage(`❌ JSON解析失败: ${jsonError.message}`, 'error');
  163. responseBody = { error: 'JSON解析失败', details: jsonError.message };
  164. }
  165. } else {
  166. const text = await response.text();
  167. logMessage(`⚠️ 响应不是JSON格式,Content-Type: ${contentType}`, 'warning');
  168. responseBody = { error: '非JSON响应', contentType: contentType, text: text };
  169. }
  170. updateResponseInfo(response.status, response.headers, responseBody, responseTime);
  171. // 特殊处理Status 200但无响应体的情况
  172. if (response.status === 200 && (!responseBody || Object.keys(responseBody).length === 0)) {
  173. logMessage('🔥 发现关键问题:HTTP 200成功但响应体为空!', 'error');
  174. logMessage('这通常表示C#代码执行过程中发生了未捕获的异常或DLL访问冲突', 'error');
  175. }
  176. } catch (networkError) {
  177. logMessage(`🚫 网络错误: ${networkError.message}`, 'error');
  178. updateResponseInfo('Network Error', null, { error: networkError.message }, Date.now());
  179. }
  180. }
  181. // 测试函数
  182. function testInit() {
  183. makeRequest('init', {
  184. config: {
  185. fixmedinsCode: 'SQ201348',
  186. fixmedinsName: '沭阳铭和医院',
  187. interfaceVersion: 'V2.1'
  188. }
  189. });
  190. }
  191. function testHealth() {
  192. makeRequest('health');
  193. }
  194. function testSignIn() {
  195. makeRequest('transaction', {
  196. transactionName: 'SignIn',
  197. identifyMode: '1',
  198. operatorId: '001',
  199. operatorName: '系统管理员'
  200. });
  201. }
  202. function testSignOut() {
  203. makeRequest('transaction', {
  204. transactionName: 'SignOut',
  205. identifyMode: '1',
  206. operatorId: '001',
  207. operatorName: '系统管理员'
  208. });
  209. }
  210. // 页面加载时的初始化
  211. document.addEventListener('DOMContentLoaded', function() {
  212. logMessage('🔧 调试工具已加载,可以开始测试', 'success');
  213. logMessage('如果看到Status 200但无响应体,请检查ThCardReader.exe进程是否正常运行', 'warning');
  214. });
  215. </script>
  216. </body>
  217. </html>