|
@@ -0,0 +1,1245 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+ <title>江苏工伤联网结算接口测试平台</title>
|
|
|
+ <style>
|
|
|
+ * {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ body {
|
|
|
+ font-family: 'Microsoft YaHei', Arial, sans-serif;
|
|
|
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+ min-height: 100vh;
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .container {
|
|
|
+ max-width: 1200px;
|
|
|
+ margin: 0 auto;
|
|
|
+ background: white;
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 10px 30px rgba(0,0,0,0.3);
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header {
|
|
|
+ background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%);
|
|
|
+ color: white;
|
|
|
+ padding: 20px;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header h1 {
|
|
|
+ font-size: 24px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .header p {
|
|
|
+ opacity: 0.9;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .main-content {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 300px 1fr;
|
|
|
+ min-height: 600px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sidebar {
|
|
|
+ background: #f8f9fa;
|
|
|
+ border-right: 1px solid #dee2e6;
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .function-group {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .function-group h3 {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ padding-bottom: 5px;
|
|
|
+ border-bottom: 1px solid #e0e0e0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .function-btn {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ padding: 10px 15px;
|
|
|
+ margin: 5px 0;
|
|
|
+ background: white;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ border-radius: 6px;
|
|
|
+ color: #333;
|
|
|
+ text-decoration: none;
|
|
|
+ font-size: 13px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: all 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .function-btn:hover {
|
|
|
+ background: #f0f0f0;
|
|
|
+ border-color: #999;
|
|
|
+ }
|
|
|
+
|
|
|
+ .function-btn.active {
|
|
|
+ background: #4CAF50;
|
|
|
+ color: white;
|
|
|
+ border-color: #4CAF50;
|
|
|
+ }
|
|
|
+
|
|
|
+ .content-area {
|
|
|
+ padding: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-bar {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .execute-btn {
|
|
|
+ background: #4CAF50;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ padding: 10px 20px;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-weight: bold;
|
|
|
+ transition: background 0.2s;
|
|
|
+ }
|
|
|
+
|
|
|
+ .execute-btn:hover {
|
|
|
+ background: #45a049;
|
|
|
+ }
|
|
|
+
|
|
|
+ .execute-btn:disabled {
|
|
|
+ background: #ccc;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .clear-btn {
|
|
|
+ background: #f44336;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ padding: 10px 15px;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .clear-btn:hover {
|
|
|
+ background: #da190b;
|
|
|
+ }
|
|
|
+
|
|
|
+ .status-indicator {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-left: auto;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .status-dot {
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .status-dot.success { background: #4CAF50; }
|
|
|
+ .status-dot.error { background: #f44336; }
|
|
|
+ .status-dot.warning { background: #ff9800; }
|
|
|
+ .status-dot.info { background: #2196f3; }
|
|
|
+
|
|
|
+ .params-section {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 20px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .params-panel {
|
|
|
+ background: #f8f9fa;
|
|
|
+ border: 1px solid #dee2e6;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .params-panel-header {
|
|
|
+ background: #e9ecef;
|
|
|
+ padding: 15px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #495057;
|
|
|
+ border-bottom: 1px solid #dee2e6;
|
|
|
+ }
|
|
|
+
|
|
|
+ .params-panel-content {
|
|
|
+ padding: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .params-textarea {
|
|
|
+ width: 100%;
|
|
|
+ height: 300px;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 10px;
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ font-size: 12px;
|
|
|
+ resize: vertical;
|
|
|
+ background: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ .params-textarea:focus {
|
|
|
+ outline: none;
|
|
|
+ border-color: #4CAF50;
|
|
|
+ }
|
|
|
+
|
|
|
+ .result-textarea {
|
|
|
+ background: #f5f5f5;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .log-section {
|
|
|
+ background: #f8f9fa;
|
|
|
+ border: 1px solid #dee2e6;
|
|
|
+ border-radius: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .log-header {
|
|
|
+ background: #e9ecef;
|
|
|
+ padding: 15px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #495057;
|
|
|
+ border-bottom: 1px solid #dee2e6;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .log-content {
|
|
|
+ padding: 15px;
|
|
|
+ max-height: 200px;
|
|
|
+ overflow-y: auto;
|
|
|
+ background: #1e1e1e;
|
|
|
+ color: #f8f8f2;
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .log-entry {
|
|
|
+ margin: 2px 0;
|
|
|
+ padding: 2px 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .log-entry.info { color: #a6e22e; }
|
|
|
+ .log-entry.error { color: #f92672; }
|
|
|
+ .log-entry.warning { color: #fd971f; }
|
|
|
+ .log-entry.success { color: #66d9ef; }
|
|
|
+
|
|
|
+ .help-panel {
|
|
|
+ background: #e7f3ff;
|
|
|
+ border: 1px solid #b3d9ff;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 15px;
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .help-panel h4 {
|
|
|
+ color: #0066cc;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .help-panel ul {
|
|
|
+ margin-left: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .help-panel li {
|
|
|
+ margin: 5px 0;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .config-modal {
|
|
|
+ display: none;
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background: rgba(0,0,0,0.5);
|
|
|
+ z-index: 1000;
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-content {
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ background: white;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 20px;
|
|
|
+ width: 90%;
|
|
|
+ max-width: 500px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
+ }
|
|
|
+
|
|
|
+ .close-btn {
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
+ font-size: 20px;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #999;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-group {
|
|
|
+ margin-bottom: 15px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-group label {
|
|
|
+ display: block;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-group input {
|
|
|
+ width: 100%;
|
|
|
+ padding: 8px 12px;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-group input:focus {
|
|
|
+ outline: none;
|
|
|
+ border-color: #4CAF50;
|
|
|
+ }
|
|
|
+
|
|
|
+ .modal-footer {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+ justify-content: flex-end;
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-primary {
|
|
|
+ background: #4CAF50;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ padding: 8px 16px;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-secondary {
|
|
|
+ background: #6c757d;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ padding: 8px 16px;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ <div class="container">
|
|
|
+ <div class="header">
|
|
|
+ <h1>🏥 江苏工伤联网结算接口测试平台</h1>
|
|
|
+ <p>基于JSSiInterface.dll的标准工伤联网接口 | 版本 V2.1 | 医院编号:SQ201348</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="main-content">
|
|
|
+ <div class="sidebar">
|
|
|
+ <div class="function-group">
|
|
|
+ <h3>🔧 系统管理</h3>
|
|
|
+ <button class="function-btn" onclick="loadFunction('init', event)">系统初始化</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('health', event)">健康检查</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('stats', event)">统计信息</button>
|
|
|
+ <button class="function-btn" onclick="showConfigModal()">配置设置</button>
|
|
|
+ <button class="function-btn" onclick="runDiagnostics()" style="background: #ff9800; color: white;">🔍 系统诊断</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="function-group">
|
|
|
+ <h3>👤 认证类</h3>
|
|
|
+ <button class="function-btn" onclick="loadFunction('signin', event)">操作员签到</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('signout', event)">操作员签退</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('signin_status', event)">签到状态</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="function-group">
|
|
|
+ <h3>🏥 业务类</h3>
|
|
|
+ <button class="function-btn" onclick="loadFunction('readcard', event)">工伤读卡</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('register', event)">患者登记</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('presettle', event)">费用预结算</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('settle', event)">费用结算</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('cancel_settle', event)">结算撤销</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="function-group">
|
|
|
+ <h3>📄 处方类</h3>
|
|
|
+ <button class="function-btn" onclick="loadFunction('upload_prescription', event)">处方上报</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('cancel_prescription', event)">处方撤销</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('batch_upload', event)">批量上传</button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="function-group">
|
|
|
+ <h3>🔄 其他</h3>
|
|
|
+ <button class="function-btn" onclick="loadFunction('complete_process', event)">完整流程</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('retry', event)">智能重试</button>
|
|
|
+ <button class="function-btn" onclick="loadFunction('reverse', event)">交易冲正</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="content-area">
|
|
|
+ <div class="action-bar">
|
|
|
+ <button class="execute-btn" onclick="executeAPI()" id="executeBtn">🚀 执行接口</button>
|
|
|
+ <button class="clear-btn" onclick="clearAll()">🗑️ 清空</button>
|
|
|
+ <div class="status-indicator">
|
|
|
+ <div class="status-dot info" id="statusDot"></div>
|
|
|
+ <span id="statusText">就绪</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="params-section">
|
|
|
+ <div class="params-panel">
|
|
|
+ <div class="params-panel-header">📝 请求参数</div>
|
|
|
+ <div class="params-panel-content">
|
|
|
+ <textarea id="inputParams" class="params-textarea" placeholder="请选择左侧功能按钮加载默认参数..."></textarea>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="params-panel">
|
|
|
+ <div class="params-panel-header">📊 响应结果</div>
|
|
|
+ <div class="params-panel-content">
|
|
|
+ <textarea id="outputParams" class="params-textarea result-textarea" readonly placeholder="执行接口后,返回结果将显示在这里..."></textarea>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="log-section">
|
|
|
+ <div class="log-header">
|
|
|
+ 📋 执行日志
|
|
|
+ <button class="clear-btn" onclick="clearLogs()" style="font-size: 12px; padding: 5px 10px;">清空日志</button>
|
|
|
+ </div>
|
|
|
+ <div class="log-content" id="logContent">
|
|
|
+ <div class="log-entry info">[INFO] 江苏工伤联网测试平台已就绪</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="help-panel" id="helpPanel">
|
|
|
+ <h4>📚 使用说明</h4>
|
|
|
+ <ul>
|
|
|
+ <li>首次使用请先点击"系统初始化"</li>
|
|
|
+ <li>业务交易前需要先"操作员签到"</li>
|
|
|
+ <li>完整的工伤就医流程:读卡 → 登记 → 预结算 → 结算</li>
|
|
|
+ <li>可以使用"健康检查"监控系统状态</li>
|
|
|
+ <li>支持快捷键:Ctrl+Enter 执行接口,Ctrl+D 清空</li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 配置模态框 -->
|
|
|
+ <div class="config-modal" id="configModal">
|
|
|
+ <div class="modal-content">
|
|
|
+ <div class="modal-header">
|
|
|
+ <h3>⚙️ 系统配置</h3>
|
|
|
+ <button class="close-btn" onclick="closeConfigModal()">×</button>
|
|
|
+ </div>
|
|
|
+ <div class="modal-body">
|
|
|
+ <div class="form-group">
|
|
|
+ <label>医院编号 (fixmedinsCode)</label>
|
|
|
+ <input type="text" id="fixmedinsCode" value="SQ201348">
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>医院名称 (fixmedinsName)</label>
|
|
|
+ <input type="text" id="fixmedinsName" value="沭阳铭和医院">
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>接口版本 (interfaceVersion)</label>
|
|
|
+ <input type="text" id="interfaceVersion" value="V2.1">
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>操作员编号 (operatorId)</label>
|
|
|
+ <input type="text" id="operatorId" value="001">
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>操作员姓名 (operatorName)</label>
|
|
|
+ <input type="text" id="operatorName" value="收费员张三">
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>服务地址 (baseUrl)</label>
|
|
|
+ <input type="text" id="baseUrl" value="http://localhost:8321">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="modal-footer">
|
|
|
+ <button class="btn-primary" onclick="saveConfig()">保存</button>
|
|
|
+ <button class="btn-secondary" onclick="closeConfigModal()">取消</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ // 全局配置
|
|
|
+ let config = {
|
|
|
+ fixmedinsCode: "SQ201348",
|
|
|
+ fixmedinsName: "沭阳铭和医院",
|
|
|
+ interfaceVersion: "V2.1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ baseUrl: "http://localhost:8321"
|
|
|
+ };
|
|
|
+
|
|
|
+ let currentFunction = null;
|
|
|
+
|
|
|
+ // DOM 元素
|
|
|
+ const inputParams = document.getElementById('inputParams');
|
|
|
+ const outputParams = document.getElementById('outputParams');
|
|
|
+ const executeBtn = document.getElementById('executeBtn');
|
|
|
+ const statusDot = document.getElementById('statusDot');
|
|
|
+ const statusText = document.getElementById('statusText');
|
|
|
+ const logContent = document.getElementById('logContent');
|
|
|
+
|
|
|
+ // 参数模板
|
|
|
+ const paramTemplates = {
|
|
|
+ init: {
|
|
|
+ action: "init",
|
|
|
+ config: {
|
|
|
+ fixmedinsCode: "SQ201348",
|
|
|
+ fixmedinsName: "沭阳铭和医院",
|
|
|
+ receiverSysCode: "JSYTH",
|
|
|
+ interfaceVersion: "V2.1",
|
|
|
+ operatorType: "1",
|
|
|
+ defaultOperator: "001",
|
|
|
+ defaultOperatorName: "收费员张三",
|
|
|
+ logPath: "logs/workinjury/"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ signin: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "SignIn",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {}
|
|
|
+ },
|
|
|
+ signout: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "SignOut",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {}
|
|
|
+ },
|
|
|
+ readcard: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "ReadCard",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {}
|
|
|
+ },
|
|
|
+ register: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "RegisterPatient",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {
|
|
|
+ psn_no: "32010219800101001X",
|
|
|
+ visit_type: "1",
|
|
|
+ dept_code: "001",
|
|
|
+ dept_name: "骨科",
|
|
|
+ doctor_code: "DOC001",
|
|
|
+ doctor_name: "张主任",
|
|
|
+ diag_code: "M79.900",
|
|
|
+ diag_name: "骨折",
|
|
|
+ visit_time: "2024-12-19 10:30:00"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ presettle: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "PreSettle",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {
|
|
|
+ visit_no: "V20241219001",
|
|
|
+ fee_details: [
|
|
|
+ {
|
|
|
+ fee_ocur_time: "2024-12-19 10:30:00",
|
|
|
+ med_list_codg: "001",
|
|
|
+ med_list_name: "X光片检查",
|
|
|
+ med_chrgitm_type: "4",
|
|
|
+ fee_amt: 120.00,
|
|
|
+ cnt: 1,
|
|
|
+ pric: 120.00,
|
|
|
+ spec: "胸部X光",
|
|
|
+ dept_code: "001",
|
|
|
+ dept_name: "骨科"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ settle: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "Settle",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {
|
|
|
+ visit_no: "V20241219001",
|
|
|
+ pre_settle_id: "PS20241219001"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ cancel_settle: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "CancelSettle",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {
|
|
|
+ original_settle_id: "ST20241219001",
|
|
|
+ cancel_reason: "系统撤销"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ upload_prescription: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "UploadPrescription",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {
|
|
|
+ visit_no: "V20241219001",
|
|
|
+ prescriptions: [
|
|
|
+ {
|
|
|
+ med_list_codg: "001",
|
|
|
+ med_list_name: "阿莫西林胶囊",
|
|
|
+ med_chrgitm_type: "1",
|
|
|
+ fee_amt: 15.60,
|
|
|
+ cnt: 1,
|
|
|
+ pric: 15.60,
|
|
|
+ spec: "0.25g*24粒",
|
|
|
+ usage: "口服",
|
|
|
+ dosage: "一次2粒,一日3次"
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ cancel_prescription: {
|
|
|
+ action: "transaction",
|
|
|
+ transactionName: "CancelPrescription",
|
|
|
+ identifyMode: "1",
|
|
|
+ operatorId: "001",
|
|
|
+ operatorName: "收费员张三",
|
|
|
+ businessParams: {
|
|
|
+ original_prescription_id: "RX20241219001",
|
|
|
+ cancel_reason: "处方错误"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ health: {
|
|
|
+ action: "health"
|
|
|
+ },
|
|
|
+ stats: {
|
|
|
+ action: "stats"
|
|
|
+ },
|
|
|
+ signin_status: {
|
|
|
+ action: "signin_status"
|
|
|
+ },
|
|
|
+ batch_upload: {
|
|
|
+ action: "batch_upload",
|
|
|
+ patientId: "32010219800101001X",
|
|
|
+ visitNo: "V20241219001",
|
|
|
+ prescriptions: [
|
|
|
+ {
|
|
|
+ med_list_codg: "001",
|
|
|
+ med_list_name: "阿莫西林胶囊",
|
|
|
+ med_chrgitm_type: "1",
|
|
|
+ fee_amt: 15.60,
|
|
|
+ cnt: 1,
|
|
|
+ pric: 15.60
|
|
|
+ },
|
|
|
+ {
|
|
|
+ med_list_codg: "002",
|
|
|
+ med_list_name: "布洛芬片",
|
|
|
+ med_chrgitm_type: "1",
|
|
|
+ fee_amt: 12.50,
|
|
|
+ cnt: 1,
|
|
|
+ pric: 12.50
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ complete_process: {
|
|
|
+ action: "complete_process",
|
|
|
+ patientInfo: {
|
|
|
+ visit_type: "1",
|
|
|
+ dept_code: "001",
|
|
|
+ dept_name: "骨科",
|
|
|
+ doctor_code: "DOC001",
|
|
|
+ doctor_name: "张主任"
|
|
|
+ },
|
|
|
+ feeDetails: [
|
|
|
+ {
|
|
|
+ med_list_codg: "001",
|
|
|
+ med_list_name: "X光检查",
|
|
|
+ med_chrgitm_type: "4",
|
|
|
+ fee_amt: 120.00,
|
|
|
+ cnt: 1,
|
|
|
+ pric: 120.00
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ retry: {
|
|
|
+ action: "retry",
|
|
|
+ transactionName: "ReadCard",
|
|
|
+ maxRetries: 3,
|
|
|
+ baseDelayMs: 1000,
|
|
|
+ businessParams: {}
|
|
|
+ },
|
|
|
+ reverse: {
|
|
|
+ action: "reverse",
|
|
|
+ originalMessageId: "SQ201320241219103012340001"
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 加载功能参数
|
|
|
+ function loadFunction(functionName, sourceEvent) {
|
|
|
+ // 移除之前的活动状态
|
|
|
+ document.querySelectorAll('.function-btn').forEach(btn => {
|
|
|
+ btn.classList.remove('active');
|
|
|
+ });
|
|
|
+
|
|
|
+ // 设置当前按钮为活动状态(如果有事件源)
|
|
|
+ if (sourceEvent && sourceEvent.target) {
|
|
|
+ sourceEvent.target.classList.add('active');
|
|
|
+ } else {
|
|
|
+ // 如果没有事件源,根据functionName查找对应按钮
|
|
|
+ const targetBtn = Array.from(document.querySelectorAll('.function-btn')).find(btn =>
|
|
|
+ btn.textContent.includes(getFunctionDisplayName(functionName)) ||
|
|
|
+ btn.getAttribute('onclick') === `loadFunction('${functionName}')`
|
|
|
+ );
|
|
|
+ if (targetBtn) {
|
|
|
+ targetBtn.classList.add('active');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ currentFunction = functionName;
|
|
|
+
|
|
|
+ if (paramTemplates[functionName]) {
|
|
|
+ // 使用当前配置更新模板
|
|
|
+ let template = JSON.parse(JSON.stringify(paramTemplates[functionName]));
|
|
|
+ updateTemplateWithConfig(template);
|
|
|
+
|
|
|
+ inputParams.value = JSON.stringify(template, null, 2);
|
|
|
+ addLog(`已加载 ${getFunctionDisplayName(functionName)} 参数模板`, 'info');
|
|
|
+ updateStatus('参数已加载', 'info');
|
|
|
+ } else {
|
|
|
+ addLog(`未找到 ${functionName} 的参数模板`, 'error');
|
|
|
+ updateStatus('参数加载失败', 'error');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用当前配置更新模板
|
|
|
+ function updateTemplateWithConfig(template) {
|
|
|
+ if (template.config) {
|
|
|
+ template.config.fixmedinsCode = config.fixmedinsCode;
|
|
|
+ template.config.fixmedinsName = config.fixmedinsName;
|
|
|
+ template.config.interfaceVersion = config.interfaceVersion;
|
|
|
+ template.config.defaultOperator = config.operatorId;
|
|
|
+ template.config.defaultOperatorName = config.operatorName;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (template.operatorId !== undefined) {
|
|
|
+ template.operatorId = config.operatorId;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (template.operatorName !== undefined) {
|
|
|
+ template.operatorName = config.operatorName;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取功能显示名称
|
|
|
+ function getFunctionDisplayName(functionName) {
|
|
|
+ const displayNames = {
|
|
|
+ init: "系统初始化",
|
|
|
+ signin: "操作员签到",
|
|
|
+ signout: "操作员签退",
|
|
|
+ readcard: "工伤读卡",
|
|
|
+ register: "患者登记",
|
|
|
+ presettle: "费用预结算",
|
|
|
+ settle: "费用结算",
|
|
|
+ cancel_settle: "结算撤销",
|
|
|
+ upload_prescription: "处方上报",
|
|
|
+ cancel_prescription: "处方撤销",
|
|
|
+ health: "健康检查",
|
|
|
+ stats: "统计信息",
|
|
|
+ signin_status: "签到状态",
|
|
|
+ batch_upload: "批量上传",
|
|
|
+ complete_process: "完整流程",
|
|
|
+ retry: "智能重试",
|
|
|
+ reverse: "交易冲正"
|
|
|
+ };
|
|
|
+ return displayNames[functionName] || functionName;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行API调用
|
|
|
+ async function executeAPI() {
|
|
|
+ const startTime = new Date();
|
|
|
+ try {
|
|
|
+ const inputText = inputParams.value.trim();
|
|
|
+ if (!inputText) {
|
|
|
+ addLog('请先选择功能并加载参数', 'error');
|
|
|
+ updateStatus('参数为空', 'error');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let params;
|
|
|
+ try {
|
|
|
+ params = JSON.parse(inputText);
|
|
|
+ } catch (e) {
|
|
|
+ addLog('参数JSON格式错误: ' + e.message, 'error');
|
|
|
+ updateStatus('JSON格式错误', 'error');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ executeBtn.disabled = true;
|
|
|
+ executeBtn.textContent = '🔄 执行中...';
|
|
|
+ updateStatus('正在调用接口...', 'warning');
|
|
|
+
|
|
|
+ addLog(`开始执行 ${getFunctionDisplayName(currentFunction)} 接口`, 'info');
|
|
|
+ addLog(`请求地址: ${config.baseUrl}/api/entry/workinjury`, 'info');
|
|
|
+ addLog(`请求参数: ${JSON.stringify(params)}`, 'info');
|
|
|
+
|
|
|
+ // 创建 AbortController 来处理超时
|
|
|
+ const controller = new AbortController();
|
|
|
+ const timeoutId = setTimeout(() => {
|
|
|
+ controller.abort();
|
|
|
+ addLog('请求超时(30秒),已取消', 'error');
|
|
|
+ }, 30000);
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await fetch(`${config.baseUrl}/api/entry/workinjury`, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ 'Accept': 'application/json',
|
|
|
+ 'Cache-Control': 'no-cache',
|
|
|
+ 'Pragma': 'no-cache'
|
|
|
+ },
|
|
|
+ body: JSON.stringify(params),
|
|
|
+ signal: controller.signal
|
|
|
+ });
|
|
|
+
|
|
|
+ clearTimeout(timeoutId);
|
|
|
+
|
|
|
+ const elapsed = new Date() - startTime;
|
|
|
+ addLog(`HTTP状态码: ${response.status} (耗时: ${elapsed}ms)`, response.ok ? 'success' : 'error');
|
|
|
+
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ const contentType = response.headers.get('content-type');
|
|
|
+ if (!contentType || !contentType.includes('application/json')) {
|
|
|
+ const text = await response.text();
|
|
|
+ addLog(`服务端返回非JSON数据: ${text.substring(0, 200)}...`, 'error');
|
|
|
+ throw new Error('服务端返回的不是JSON格式数据');
|
|
|
+ }
|
|
|
+
|
|
|
+ const result = await response.json();
|
|
|
+ outputParams.value = JSON.stringify(result, null, 2);
|
|
|
+
|
|
|
+ if (result.success === true) {
|
|
|
+ addLog(`接口调用成功: ${result.message}`, 'success');
|
|
|
+ updateStatus('接口调用成功', 'success');
|
|
|
+ } else {
|
|
|
+ addLog(`接口调用失败: ${result.message} (代码: ${result.code})`, 'error');
|
|
|
+ updateStatus('接口调用失败', 'error');
|
|
|
+
|
|
|
+ // 如果是DLL相关错误,提供额外建议
|
|
|
+ if (result.message && result.message.includes('JSSiInterface.dll')) {
|
|
|
+ addLog('建议检查: 1) DLL文件是否存在 2) DLL版本是否正确 3) 运行环境配置', 'warning');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (fetchError) {
|
|
|
+ clearTimeout(timeoutId);
|
|
|
+
|
|
|
+ if (fetchError.name === 'AbortError') {
|
|
|
+ throw new Error('请求超时');
|
|
|
+ } else {
|
|
|
+ throw fetchError;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ const elapsed = new Date() - startTime;
|
|
|
+ addLog(`网络错误 (${elapsed}ms): ${error.message}`, 'error');
|
|
|
+ updateStatus('网络连接失败', 'error');
|
|
|
+
|
|
|
+ // 提供更详细的错误信息和建议
|
|
|
+ let errorAdvice = '';
|
|
|
+ if (error.message.includes('Failed to fetch')) {
|
|
|
+ errorAdvice = '建议检查: 1) 服务是否启动 2) 端口8321是否被占用 3) 防火墙设置';
|
|
|
+ } else if (error.message.includes('超时')) {
|
|
|
+ errorAdvice = '建议检查: 1) 服务响应速度 2) DLL是否正常加载 3) 网络连接';
|
|
|
+ } else if (error.message.includes('CORS')) {
|
|
|
+ errorAdvice = '建议检查: 1) 服务端CORS配置 2) 请求头设置';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (errorAdvice) {
|
|
|
+ addLog(errorAdvice, 'warning');
|
|
|
+ }
|
|
|
+
|
|
|
+ outputParams.value = JSON.stringify({
|
|
|
+ success: false,
|
|
|
+ error: error.message,
|
|
|
+ timestamp: new Date().toISOString(),
|
|
|
+ elapsed: elapsed + 'ms',
|
|
|
+ function: currentFunction,
|
|
|
+ advice: errorAdvice
|
|
|
+ }, null, 2);
|
|
|
+
|
|
|
+ } finally {
|
|
|
+ executeBtn.disabled = false;
|
|
|
+ executeBtn.textContent = '🚀 执行接口';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新状态显示
|
|
|
+ function updateStatus(text, type = 'info') {
|
|
|
+ statusText.textContent = text;
|
|
|
+ statusDot.className = `status-dot ${type}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加日志
|
|
|
+ function addLog(message, type = 'info') {
|
|
|
+ const timestamp = new Date().toLocaleTimeString();
|
|
|
+ const logEntry = document.createElement('div');
|
|
|
+ logEntry.className = `log-entry ${type}`;
|
|
|
+ logEntry.textContent = `[${timestamp}] ${message}`;
|
|
|
+
|
|
|
+ logContent.appendChild(logEntry);
|
|
|
+ logContent.scrollTop = logContent.scrollHeight;
|
|
|
+
|
|
|
+ // 限制日志条数
|
|
|
+ const logs = logContent.querySelectorAll('.log-entry');
|
|
|
+ if (logs.length > 100) {
|
|
|
+ logs[0].remove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清空所有内容
|
|
|
+ function clearAll() {
|
|
|
+ inputParams.value = '';
|
|
|
+ outputParams.value = '';
|
|
|
+ updateStatus('已清空', 'info');
|
|
|
+ addLog('已清空所有内容', 'info');
|
|
|
+
|
|
|
+ // 移除所有按钮的活动状态
|
|
|
+ document.querySelectorAll('.function-btn').forEach(btn => {
|
|
|
+ btn.classList.remove('active');
|
|
|
+ });
|
|
|
+ currentFunction = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清空日志
|
|
|
+ function clearLogs() {
|
|
|
+ logContent.innerHTML = '<div class="log-entry info">[INFO] 日志已清空</div>';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示配置模态框
|
|
|
+ function showConfigModal() {
|
|
|
+ document.getElementById('fixmedinsCode').value = config.fixmedinsCode;
|
|
|
+ document.getElementById('fixmedinsName').value = config.fixmedinsName;
|
|
|
+ document.getElementById('interfaceVersion').value = config.interfaceVersion;
|
|
|
+ document.getElementById('operatorId').value = config.operatorId;
|
|
|
+ document.getElementById('operatorName').value = config.operatorName;
|
|
|
+ document.getElementById('baseUrl').value = config.baseUrl;
|
|
|
+
|
|
|
+ document.getElementById('configModal').style.display = 'block';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关闭配置模态框
|
|
|
+ function closeConfigModal() {
|
|
|
+ document.getElementById('configModal').style.display = 'none';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存配置
|
|
|
+ function saveConfig() {
|
|
|
+ config.fixmedinsCode = document.getElementById('fixmedinsCode').value;
|
|
|
+ config.fixmedinsName = document.getElementById('fixmedinsName').value;
|
|
|
+ config.interfaceVersion = document.getElementById('interfaceVersion').value;
|
|
|
+ config.operatorId = document.getElementById('operatorId').value;
|
|
|
+ config.operatorName = document.getElementById('operatorName').value;
|
|
|
+ config.baseUrl = document.getElementById('baseUrl').value;
|
|
|
+
|
|
|
+ // 保存到localStorage
|
|
|
+ localStorage.setItem('workinjury_config', JSON.stringify(config));
|
|
|
+
|
|
|
+ addLog('配置已保存', 'success');
|
|
|
+ closeConfigModal();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载保存的配置
|
|
|
+ function loadSavedConfig() {
|
|
|
+ const savedConfig = localStorage.getItem('workinjury_config');
|
|
|
+ if (savedConfig) {
|
|
|
+ try {
|
|
|
+ config = { ...config, ...JSON.parse(savedConfig) };
|
|
|
+ addLog('已加载保存的配置', 'info');
|
|
|
+ } catch (e) {
|
|
|
+ addLog('配置加载失败,使用默认配置', 'warning');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 键盘快捷键
|
|
|
+ document.addEventListener('keydown', function(e) {
|
|
|
+ if (e.ctrlKey) {
|
|
|
+ switch(e.key) {
|
|
|
+ case 'Enter':
|
|
|
+ e.preventDefault();
|
|
|
+ executeAPI();
|
|
|
+ break;
|
|
|
+ case 'd':
|
|
|
+ e.preventDefault();
|
|
|
+ clearAll();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 点击模态框外部关闭
|
|
|
+ document.getElementById('configModal').addEventListener('click', function(e) {
|
|
|
+ if (e.target === this) {
|
|
|
+ closeConfigModal();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 运行系统诊断
|
|
|
+ async function runDiagnostics() {
|
|
|
+ addLog('开始运行系统诊断...', 'info');
|
|
|
+ updateStatus('正在诊断...', 'warning');
|
|
|
+
|
|
|
+ const diagnostics = {
|
|
|
+ timestamp: new Date().toISOString(),
|
|
|
+ tests: {}
|
|
|
+ };
|
|
|
+
|
|
|
+ // 1. 检查服务连通性
|
|
|
+ addLog('1. 检查服务连通性...', 'info');
|
|
|
+ try {
|
|
|
+ // 使用健康检查接口测试连通性,避免OPTIONS请求问题
|
|
|
+ const response = await fetch(`${config.baseUrl}/api/entry/workinjury`, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ 'Accept': 'application/json'
|
|
|
+ },
|
|
|
+ body: JSON.stringify({ action: 'health' })
|
|
|
+ });
|
|
|
+
|
|
|
+ if (response.ok) {
|
|
|
+ diagnostics.tests.connectivity = {
|
|
|
+ status: 'success',
|
|
|
+ message: `服务可访问 (HTTP ${response.status})`,
|
|
|
+ url: `${config.baseUrl}/api/entry/workinjury`
|
|
|
+ };
|
|
|
+ addLog('✓ 服务连通性检查通过', 'success');
|
|
|
+ } else {
|
|
|
+ diagnostics.tests.connectivity = {
|
|
|
+ status: 'error',
|
|
|
+ message: `服务响应错误: HTTP ${response.status}`,
|
|
|
+ url: `${config.baseUrl}/api/entry/workinjury`
|
|
|
+ };
|
|
|
+ addLog('✗ 服务连通性检查失败: HTTP ' + response.status, 'error');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ diagnostics.tests.connectivity = {
|
|
|
+ status: 'error',
|
|
|
+ message: `服务无法访问: ${error.message}`,
|
|
|
+ url: `${config.baseUrl}/api/entry/workinjury`
|
|
|
+ };
|
|
|
+ addLog('✗ 服务连通性检查失败: ' + error.message, 'error');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 解析健康状态(从连通性检查的结果中获取)
|
|
|
+ addLog('2. 解析系统健康状态...', 'info');
|
|
|
+ if (diagnostics.tests.connectivity.status === 'success') {
|
|
|
+ try {
|
|
|
+ // 从连通性检查的响应中获取健康检查结果
|
|
|
+ const healthResponse = await fetch(`${config.baseUrl}/api/entry/workinjury`, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
+ body: JSON.stringify({ action: 'health' })
|
|
|
+ });
|
|
|
+
|
|
|
+ if (healthResponse.ok) {
|
|
|
+ const healthResult = await healthResponse.json();
|
|
|
+ diagnostics.tests.health = healthResult;
|
|
|
+ addLog('✓ 健康检查完成', 'success');
|
|
|
+ } else {
|
|
|
+ diagnostics.tests.health = {
|
|
|
+ success: false,
|
|
|
+ message: `健康检查失败: HTTP ${healthResponse.status}`
|
|
|
+ };
|
|
|
+ addLog('✗ 健康检查失败', 'error');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ diagnostics.tests.health = {
|
|
|
+ success: false,
|
|
|
+ message: `健康检查异常: ${error.message}`
|
|
|
+ };
|
|
|
+ addLog('✗ 健康检查异常: ' + error.message, 'error');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ diagnostics.tests.health = {
|
|
|
+ success: false,
|
|
|
+ message: '跳过健康检查(服务连通性失败)'
|
|
|
+ };
|
|
|
+ addLog('⚠ 跳过健康检查(服务不可达)', 'warning');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 测试初始化
|
|
|
+ addLog('3. 测试系统初始化...', 'info');
|
|
|
+ if (diagnostics.tests.connectivity.status === 'success') {
|
|
|
+ try {
|
|
|
+ const initResponse = await fetch(`${config.baseUrl}/api/entry/workinjury`, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
+ body: JSON.stringify({
|
|
|
+ action: 'init',
|
|
|
+ config: {
|
|
|
+ fixmedinsCode: config.fixmedinsCode,
|
|
|
+ fixmedinsName: config.fixmedinsName,
|
|
|
+ receiverSysCode: 'JSYTH',
|
|
|
+ interfaceVersion: config.interfaceVersion,
|
|
|
+ operatorType: '1',
|
|
|
+ defaultOperator: config.operatorId,
|
|
|
+ defaultOperatorName: config.operatorName,
|
|
|
+ logPath: 'logs/workinjury/'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ });
|
|
|
+
|
|
|
+ if (initResponse.ok) {
|
|
|
+ const initResult = await initResponse.json();
|
|
|
+ diagnostics.tests.initialization = initResult;
|
|
|
+ if (initResult.success) {
|
|
|
+ addLog('✓ 初始化测试成功', 'success');
|
|
|
+ } else {
|
|
|
+ addLog('✗ 初始化失败: ' + initResult.message, 'error');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ diagnostics.tests.initialization = {
|
|
|
+ success: false,
|
|
|
+ message: `初始化请求失败: HTTP ${initResponse.status}`
|
|
|
+ };
|
|
|
+ addLog('✗ 初始化请求失败: HTTP ' + initResponse.status, 'error');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ diagnostics.tests.initialization = {
|
|
|
+ success: false,
|
|
|
+ message: `初始化测试异常: ${error.message}`
|
|
|
+ };
|
|
|
+ addLog('✗ 初始化测试异常: ' + error.message, 'error');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ diagnostics.tests.initialization = {
|
|
|
+ success: false,
|
|
|
+ message: '跳过初始化测试(服务连通性失败)'
|
|
|
+ };
|
|
|
+ addLog('⚠ 跳过初始化测试(服务不可达)', 'warning');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 环境信息收集
|
|
|
+ addLog('4. 收集环境信息...', 'info');
|
|
|
+ diagnostics.environment = {
|
|
|
+ userAgent: navigator.userAgent,
|
|
|
+ currentUrl: window.location.href,
|
|
|
+ timestamp: new Date().toLocaleString(),
|
|
|
+ config: config
|
|
|
+ };
|
|
|
+ addLog('✓ 环境信息收集完成', 'success');
|
|
|
+
|
|
|
+ // 5. 生成诊断报告
|
|
|
+ const report = generateDiagnosticReport(diagnostics);
|
|
|
+ outputParams.value = JSON.stringify(diagnostics, null, 2);
|
|
|
+
|
|
|
+ addLog('系统诊断完成', 'success');
|
|
|
+ addLog(report, 'info');
|
|
|
+ updateStatus('诊断完成', 'success');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成诊断报告
|
|
|
+ function generateDiagnosticReport(diagnostics) {
|
|
|
+ let report = '=== 诊断报告 ===\n';
|
|
|
+
|
|
|
+ if (diagnostics.tests.connectivity?.status === 'success') {
|
|
|
+ report += '✓ 服务连通性: 正常\n';
|
|
|
+ } else {
|
|
|
+ report += '✗ 服务连通性: 异常 - ' + (diagnostics.tests.connectivity?.message || '未知错误') + '\n';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (diagnostics.tests.health?.success) {
|
|
|
+ report += '✓ 系统健康: 正常\n';
|
|
|
+ } else {
|
|
|
+ report += '✗ 系统健康: 异常 - ' + (diagnostics.tests.health?.message || '未知错误') + '\n';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (diagnostics.tests.initialization?.success) {
|
|
|
+ report += '✓ 系统初始化: 正常\n';
|
|
|
+ } else {
|
|
|
+ report += '✗ 系统初始化: 异常 - ' + (diagnostics.tests.initialization?.message || '未知错误') + '\n';
|
|
|
+ }
|
|
|
+
|
|
|
+ // 提供解决建议
|
|
|
+ const hasErrors = Object.values(diagnostics.tests).some(test =>
|
|
|
+ test.status === 'error' || test.success === false
|
|
|
+ );
|
|
|
+
|
|
|
+ if (hasErrors) {
|
|
|
+ report += '\n=== 解决建议 ===\n';
|
|
|
+ report += '1. 确认 ThCardReader.exe 服务已启动\n';
|
|
|
+ report += '2. 检查 JSSiInterface.dll 文件是否存在\n';
|
|
|
+ report += '3. 确认端口 8321 未被占用\n';
|
|
|
+ report += '4. 检查防火墙和杀毒软件设置\n';
|
|
|
+ report += '5. 确认医院编号和配置信息正确\n';
|
|
|
+ } else {
|
|
|
+ report += '\n✓ 所有检查都通过,系统状态正常';
|
|
|
+ }
|
|
|
+
|
|
|
+ return report;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 页面加载完成
|
|
|
+ window.addEventListener('load', function() {
|
|
|
+ loadSavedConfig();
|
|
|
+ addLog('江苏工伤联网测试平台已启动', 'success');
|
|
|
+ updateStatus('系统就绪', 'success');
|
|
|
+
|
|
|
+ // 默认加载初始化功能
|
|
|
+ setTimeout(() => {
|
|
|
+ loadFunction('init', null);
|
|
|
+ }, 500);
|
|
|
+ });
|
|
|
+ </script>
|
|
|
+</body>
|
|
|
+</html>
|