123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245 |
- <!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>
|