test_huashi_photo_base64.html 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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>华视读卡器照片BASE64功能测试</title>
  7. <style>
  8. body { font-family: Arial, sans-serif; margin: 20px; line-height: 1.6; }
  9. .container { max-width: 1000px; margin: 0 auto; }
  10. button { background: #007cba; color: white; border: none; padding: 10px 20px; margin: 5px; cursor: pointer; border-radius: 4px; }
  11. button:hover { background: #005a87; }
  12. .result { background: #f5f5f5; border: 1px solid #ccc; padding: 15px; margin: 10px 0; border-radius: 4px; }
  13. .photo-section { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 4px; }
  14. .photo-preview { max-width: 200px; max-height: 200px; border: 1px solid #ccc; margin: 10px 0; }
  15. .base64-text { max-height: 200px; overflow-y: auto; background: #fff; border: 1px solid #ccc; padding: 10px; font-family: monospace; font-size: 12px; }
  16. .error { color: red; }
  17. .success { color: green; }
  18. .info { color: blue; }
  19. </style>
  20. </head>
  21. <body>
  22. <div class="container">
  23. <h1>华视读卡器照片BASE64功能测试</h1>
  24. <div class="test-section">
  25. <h2>测试功能</h2>
  26. <button onclick="testInitialize()">1. 初始化读卡器</button>
  27. <button onclick="testReadCardWithPhoto()">2. 读取身份证(含照片BASE64)</button>
  28. <button onclick="testDeviceStatus()">3. 检查设备状态</button>
  29. <button onclick="testClose()">4. 关闭设备</button>
  30. <br><br>
  31. <button onclick="clearResults()">清除结果</button>
  32. </div>
  33. <div id="results"></div>
  34. <div class="photo-section" id="photoSection" style="display: none;">
  35. <h3>照片预览</h3>
  36. <div>
  37. <strong>照片格式:</strong><span id="photoFormat"></span> |
  38. <strong>照片大小:</strong><span id="photoSize"></span> 字符
  39. </div>
  40. <img id="photoPreview" class="photo-preview" alt="身份证照片">
  41. <div>
  42. <h4>BASE64编码 (前500字符):</h4>
  43. <div id="base64Preview" class="base64-text"></div>
  44. </div>
  45. <button onclick="downloadPhoto()">下载照片</button>
  46. </div>
  47. </div>
  48. <script>
  49. let currentPhotoData = null;
  50. function addResult(title, data, type = 'info') {
  51. const results = document.getElementById('results');
  52. const div = document.createElement('div');
  53. div.className = `result ${type}`;
  54. let content = `<h3>${title}</h3>`;
  55. if (typeof data === 'object') {
  56. content += `<pre>${JSON.stringify(data, null, 2)}</pre>`;
  57. // 如果包含照片数据,显示照片预览
  58. if (data.data && data.data.photoBase64 && data.data.hasPhoto) {
  59. showPhotoPreview(data.data);
  60. }
  61. } else {
  62. content += `<p>${data}</p>`;
  63. }
  64. div.innerHTML = content;
  65. results.appendChild(div);
  66. results.scrollTop = results.scrollHeight;
  67. }
  68. function showPhotoPreview(data) {
  69. currentPhotoData = data;
  70. const photoSection = document.getElementById('photoSection');
  71. const photoPreview = document.getElementById('photoPreview');
  72. const photoFormat = document.getElementById('photoFormat');
  73. const photoSize = document.getElementById('photoSize');
  74. const base64Preview = document.getElementById('base64Preview');
  75. if (data.hasPhoto && data.photoBase64) {
  76. photoSection.style.display = 'block';
  77. // 设置照片信息
  78. photoFormat.textContent = data.photoFormat || 'UNKNOWN';
  79. photoSize.textContent = data.photoSize || data.photoBase64.length;
  80. // 显示BASE64前500字符
  81. base64Preview.textContent = data.photoBase64.substring(0, 500) +
  82. (data.photoBase64.length > 500 ? '...' : '');
  83. // 显示照片预览
  84. try {
  85. let mimeType = 'image/jpeg';
  86. if (data.photoFormat === 'BMP') {
  87. mimeType = 'image/bmp';
  88. }
  89. photoPreview.src = `data:${mimeType};base64,${data.photoBase64}`;
  90. photoPreview.style.display = 'block';
  91. } catch (e) {
  92. photoPreview.style.display = 'none';
  93. addResult('照片预览错误', e.message, 'error');
  94. }
  95. } else {
  96. photoSection.style.display = 'none';
  97. }
  98. }
  99. function downloadPhoto() {
  100. if (!currentPhotoData || !currentPhotoData.photoBase64) {
  101. alert('没有可下载的照片数据');
  102. return;
  103. }
  104. try {
  105. const base64Data = currentPhotoData.photoBase64;
  106. const format = currentPhotoData.photoFormat || 'JPEG';
  107. const mimeType = format === 'BMP' ? 'image/bmp' : 'image/jpeg';
  108. const extension = format === 'BMP' ? 'bmp' : 'jpg';
  109. // 创建下载链接
  110. const link = document.createElement('a');
  111. link.href = `data:${mimeType};base64,${base64Data}`;
  112. link.download = `idcard_photo_${new Date().getTime()}.${extension}`;
  113. document.body.appendChild(link);
  114. link.click();
  115. document.body.removeChild(link);
  116. } catch (e) {
  117. addResult('照片下载错误', e.message, 'error');
  118. }
  119. }
  120. function testInitialize() {
  121. fetch('http://localhost:8321/readcard/huashi/initialize', {
  122. method: 'POST',
  123. headers: { 'Content-Type': 'application/json' }
  124. })
  125. .then(response => response.json())
  126. .then(data => {
  127. const type = data.code === 200 ? 'success' : 'error';
  128. addResult('初始化华视读卡器', data, type);
  129. })
  130. .catch(error => {
  131. addResult('初始化请求错误', error.message, 'error');
  132. });
  133. }
  134. function testReadCardWithPhoto() {
  135. addResult('开始读取身份证', '请将身份证放在读卡器上...', 'info');
  136. fetch('http://localhost:8321/readcard/huashi/readcard', {
  137. method: 'POST',
  138. headers: { 'Content-Type': 'application/json' }
  139. })
  140. .then(response => response.json())
  141. .then(data => {
  142. const type = data.code === 200 ? 'success' : 'error';
  143. addResult('读取身份证信息(含照片BASE64)', data, type);
  144. })
  145. .catch(error => {
  146. addResult('读卡请求错误', error.message, 'error');
  147. });
  148. }
  149. function testDeviceStatus() {
  150. fetch('http://localhost:8321/readcard/huashi/status', {
  151. method: 'GET',
  152. headers: { 'Content-Type': 'application/json' }
  153. })
  154. .then(response => response.json())
  155. .then(data => {
  156. const type = data.connected ? 'success' : 'error';
  157. addResult('设备状态检查', data, type);
  158. })
  159. .catch(error => {
  160. addResult('状态检查错误', error.message, 'error');
  161. });
  162. }
  163. function testClose() {
  164. fetch('http://localhost:8321/readcard/huashi/close', {
  165. method: 'POST',
  166. headers: { 'Content-Type': 'application/json' }
  167. })
  168. .then(response => response.json())
  169. .then(data => {
  170. const type = data.code === 200 ? 'success' : 'error';
  171. addResult('关闭设备连接', data, type);
  172. })
  173. .catch(error => {
  174. addResult('关闭设备错误', error.message, 'error');
  175. });
  176. }
  177. function clearResults() {
  178. document.getElementById('results').innerHTML = '';
  179. document.getElementById('photoSection').style.display = 'none';
  180. currentPhotoData = null;
  181. }
  182. // 页面加载完成后的说明
  183. window.onload = function() {
  184. addResult('测试说明',
  185. `本页面用于测试华视读卡器的照片BASE64编码功能。
  186. 新增功能特性:
  187. 1. 在身份证数据中包含 photoBase64 字段(照片的BASE64编码)
  188. 2. hasPhoto 字段指示是否成功获取到照片
  189. 3. photoFormat 字段指示照片格式(JPEG/BMP)
  190. 4. photoSize 字段指示BASE64编码长度
  191. 测试步骤:
  192. 1. 先点击"初始化读卡器"
  193. 2. 将身份证放在读卡器上
  194. 3. 点击"读取身份证(含照片BASE64)"
  195. 4. 查看结果中的照片信息和预览
  196. 注意:确保华视读卡器已正确连接并安装驱动程序。`, 'info');
  197. };
  198. </script>
  199. </body>
  200. </html>