11
WXL
3 天以前 dbf761cb549cdc0e8ef1ed266a41f515b8ef148d
11
已添加2个文件
已重命名1个文件
601 ■■■■■ 文件已修改
public/ConsultationRoom.html 补丁 | 查看 | 原始文档 | blame | 历史
public/integration.html 601 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/static/jinhua.png 补丁 | 查看 | 原始文档 | blame | 历史
public/ConsultationRoom.html
public/integration.html
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,601 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>金华人民医院大屏叫号系统</title>
  <style>
    /* åŸºç¡€æ ·å¼ */
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Helvetica Neue', Arial, sans-serif;
    }
    body {
      background: linear-gradient(135deg, #e6f0f8, #d9e4f0);
      color: #4a5568;
      height: 100vh;
      overflow: hidden;
    }
    .bigscreen-container {
      height: 100%;
      display: flex;
      flex-direction: column;
      padding: 8px;
    }
    /* åŒ»é™¢æ ‡é¢˜æ ·å¼ */
    .hospital-header {
      display: flex;
      justify-content: center;
      align-items: center;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 12px;
      padding: 12px;
      margin-bottom: 8px;
      font-size: 22px;
      font-weight: bold;
      color: #4a7dff;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }
    .hospital-header img {
      margin-right: 8px;
      height: 40px;
    }
    .running-indicator {
      width: 12px;
      height: 12px;
      border-radius: 50%;
      margin-left: 12px;
      transition: background-color 0.3s;
    }
    /* åˆ—标题区域 */
    .column-header {
      display: flex;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 12px;
      padding: 12px 0;
      margin-bottom: 8px;
      font-size: 20px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }
    .column-title {
      flex: 1;
      min-width: 0;
      text-align: center;
      padding: 0 12px;
      border-left: 1px solid rgba(91, 140, 255, 0.2);
    }
    .column-title:first-child {
      border-left: none;
      flex: 2; /* ç¬¬ä¸€ä¸ªæˆ¿é—´æ ‡é¢˜å ä¸¤åˆ—宽度 */
    }
    /* æ‚£è€…列表区域 */
    .patient-list-container {
      display: flex;
      flex-grow: 1;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 12px;
      padding: 12px 0;
      margin-bottom: 8px;
      font-size: 18px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
      overflow-y: auto;
    }
    .patient-column {
      flex: 1;
      min-width: 0;
      padding: 0 12px;
      border-left: 1px solid rgba(91, 140, 255, 0.2);
    }
    .patient-column:first-child {
      border-left: none;
      flex: 2; /* ç¬¬ä¸€ä¸ªæˆ¿é—´å ä¸¤åˆ—宽度 */
    }
    /* ç¬¬ä¸€ä¸ªæˆ¿é—´åˆ†æˆä¸¤åˆ—的特殊样式 */
    .first-room-columns {
      display: flex;
      flex: 2;
      min-width: 0;
    }
    .first-room-column {
      flex: 1;
      min-width: 0;
      padding: 0 12px;
    }
    .first-room-column:first-child {
      border-right: 1px solid rgba(91, 140, 255, 0.2);
    }
    /* æ‚£è€…项样式 - ä¼˜åŒ–后的布局 */
    .patient-item {
      padding: 10px 8px;
      margin-bottom: 8px;
      border-radius: 8px;
      transition: all 0.3s;
      background: rgba(255, 255, 255, 0.8);
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    }
    .patient-item:hover {
      background: rgba(91, 140, 255, 0.1);
    }
    .patient-info-row {
      display: flex;
      width: 100%;
      margin-bottom: 4px;
    }
    .patient-number-name {
      display: flex;
      flex-wrap: wrap;
    }
    .patient-number {
      color: #5b8cff;
      font-weight: bold;
      margin-right: 10px;
      min-width: 80px;
    }
    .patient-name {
      flex: 1;
      min-width: 100px;
    }
    .patient-status {
      width: 100%;
      color: #67c23a;
      margin-top: 4px;
    }
    .warning-row {
      background-color: rgba(230, 162, 60, 0.1);
      color: #e6a23c;
    }
    /* åº•部控制区域 */
    .footer-controls {
      display: flex;
      justify-content: center;
      align-items: center;
      background: rgba(255, 255, 255, 0.9);
      border-radius: 12px;
      padding: 12px;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }
    .welcome-btn {
      background: rgba(91, 140, 255, 0.1);
      color: #4a7dff;
      border: none;
      border-radius: 8px;
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
    }
    .welcome-btn:hover {
      background: rgba(91, 140, 255, 0.2);
    }
    /* æ»šåŠ¨æ¡æ ·å¼ */
    .patient-list-container::-webkit-scrollbar {
      width: 6px;
    }
    .patient-list-container::-webkit-scrollbar-track {
      background: rgba(0, 0, 0, 0.05);
      border-radius: 4px;
    }
    .patient-list-container::-webkit-scrollbar-thumb {
      background: rgba(91, 140, 255, 0.4);
      border-radius: 4px;
    }
    /* å“åº”式调整 */
    @media (max-width: 1200px) {
      .hospital-header {
        font-size: 18px;
      }
      .column-header {
        font-size: 16px;
      }
      .patient-list-container {
        font-size: 14px;
      }
      .patient-number {
        min-width: 60px;
      }
    }
    @media (max-width: 768px) {
      .hospital-header {
        font-size: 16px;
        padding: 8px;
      }
      .column-header {
        flex-direction: column;
        padding: 8px 0;
      }
      .column-title {
        min-width: 100%;
        padding: 8px 0;
        border-left: none;
        border-bottom: 1px solid rgba(91, 140, 255, 0.2);
      }
      .patient-list-container {
        flex-direction: column;
      }
      .patient-column, .first-room-columns {
        min-width: 100%;
        padding: 8px 0;
        border-left: none;
        border-bottom: 1px solid rgba(91, 140, 255, 0.2);
      }
      .first-room-column {
        padding: 0 8px;
      }
    }
  </style>
</head>
<body>
  <div class="bigscreen-container">
    <!-- é¡¶éƒ¨åŒ»é™¢æ ‡é¢˜ -->
    <div class="hospital-header">
      <img src="./static/jinhua.png"/>
      <span>金华人民医院</span>
      <div class="running-indicator" id="runningIndicator"></div>
    </div>
    <!-- åˆ—标题区域 -->
    <div class="column-header" id="columnHeader">
      <!-- åˆ—标题将通过JS动态生成 -->
    </div>
    <!-- æ‚£è€…列表区域 -->
    <div class="patient-list-container" id="patientListContainer">
      <!-- æ‚£è€…列表将通过JS动态生成 -->
    </div>
    <div class="footer-controls">
      <button class="welcome-btn" id="welcomeBtn">欢迎语</button>
    </div>
  </div>
  <script src="./static/jquery.min.js"></script>
  <script>
    // åº”用状态
    var appState = {
      runningIndicator: 0,
      displayColInfo: {
        "0": ["常规心电图A", "床边心电图(常规+频谱)M", "常规心电图-心电向量图N"],
        "1": ["动态心电B", "动态血压C"],
        "2": ["平板运动心电D"],
        "3": ["食道电生理F"],
        "4": ["动脉硬化监测E"]
      },
      mapColumnVsPatients: new Map(),
      curSpeakPat: null,
      timer: null,
      speechSynthesis: window.speechSynthesis || null,
      apiBaseUrl: 'http://localhost:48080/admin-api'
    };
    // é¡µé¢åŠ è½½å®ŒæˆåŽåˆå§‹åŒ–
    $(document).ready(function() {
      // åˆå§‹åŒ–事件监听
      $('#welcomeBtn').click(function() {
        speak('欢迎使用金华人民医院叫号系统');
      });
      // åˆå§‹åŒ–数据
      updateColumnHeader();
      startScrolling();
      // åˆå§‹åŒ–语音合成
      if (appState.speechSynthesis) {
        appState.speechSynthesis.onend = onSpeachEndEvent;
      }
    });
    // æ›´æ–°åˆ—标题显示
    function updateColumnHeader() {
      var $header = $('#columnHeader');
      $header.empty();
      // æŒ‰ç…§å›ºå®šé¡ºåºæ˜¾ç¤ºäº”个房间的标题
      for (var i = 0; i < 5; i++) {
        var disColId = i.toString();
        var disNameList = appState.displayColInfo[disColId] || [];
        var isFirstColumn = disColId === "0";
        var $title = $('<div class="column-title' + (isFirstColumn ? ' double-column' : '') + '"></div>');
        disNameList.forEach(function(dispName) {
          $title.append('<div>' + dispName + '</div>');
        });
        $header.append($title);
      }
    }
    // èŽ·å–æ‚£è€…åˆ—è¡¨
    function getList() {
      // è¿™é‡Œæ›¿æ¢ä¸ºå®žé™…çš„API调用
      $.ajax({
        url: appState.apiBaseUrl + '/ecg/screen/big-screen-data',
        type: 'GET',
        dataType: 'json',
        success: function(response) {
          // ç¡®ä¿æ•°æ®æŒ‰ç…§äº”个房间的顺序排列
          var data = response.data || response;
          appState.mapColumnVsPatients = new Map();
          // æŒ‰ç…§å›ºå®šé¡ºåºå¤„理五个房间的数据
          for (var i = 0; i < 5; i++) {
            var roomId = i.toString();
            appState.mapColumnVsPatients.set(roomId, data[roomId] || []);
          }
          updatePatientList();
        },
        error: function(xhr, status, error) {
          console.error('获取患者列表失败:', error);
          // ä½¿ç”¨æ¨¡æ‹Ÿæ•°æ®ä½œä¸ºåŽå¤‡
          appState.mapColumnVsPatients = generateMockPatients();
          updatePatientList();
        }
      });
    }
    // æ›´æ–°æ‚£è€…列表显示
    function updatePatientList() {
      var $container = $('#patientListContainer');
      $container.empty();
      // æŒ‰ç…§å›ºå®šé¡ºåºæ˜¾ç¤ºäº”个房间的患者数据
      for (var i = 0; i < 5; i++) {
        var disColId = i.toString();
        var patients = appState.mapColumnVsPatients.get(disColId) || [];
        var isFirstColumn = disColId === "0";
        if (isFirstColumn) {
          // ç¬¬ä¸€ä¸ªæˆ¿é—´ç‰¹æ®Šå¤„理
          if (patients.length > 10) {
            // è¶…过10人,分成两列
            var $firstRoomColumns = $('<div class="first-room-columns"></div>');
            // ç¬¬ä¸€åˆ—(前10条)
            var $firstCol = $('<div class="first-room-column"></div>');
            patients.slice(0, 10).forEach(function(item, itemIndex) {
              $firstCol.append(createPatientItem(item));
            });
            $firstRoomColumns.append($firstCol);
            // ç¬¬äºŒåˆ—(剩余数据)
            var $secondCol = $('<div class="first-room-column"></div>');
            patients.slice(10).forEach(function(item, itemIndex) {
              $secondCol.append(createPatientItem(item, itemIndex + 10));
            });
            $firstRoomColumns.append($secondCol);
            $container.append($firstRoomColumns);
          } else {
            // ä¸è¶…过10人,单列显示但占两列宽度
            var $col = $('<div class="patient-column" style="flex:2"></div>');
            patients.forEach(function(item, itemIndex) {
              $col.append(createPatientItem(item, itemIndex));
            });
            $container.append($col);
          }
        } else {
          // å…¶ä»–房间单列显示
          var $col = $('<div class="patient-column"></div>');
          patients.forEach(function(item, itemIndex) {
            $col.append(createPatientItem(item, itemIndex));
          });
          $container.append($col);
        }
      }
    }
    // åˆ›å»ºæ‚£è€…项 - ä¼˜åŒ–后的版本
    function createPatientItem(item, index) {
      var statusClass = getItemCssClass(item);
      var $item = $('<div class="patient-item ' + statusClass + '"></div>');
      // å·ç å’Œå§“名在一行
      var $numberNameRow = $('<div class="patient-info-row patient-number-name"></div>');
      $numberNameRow.append('<span class="patient-number">' + getCheckTypeSeqPrefix(item.bookCheckType) + item.bookSeqNum + '</span>');
      $numberNameRow.append('<span class="patient-name">' + nameDesensitize(item.patName) + '</span>');
      $item.append($numberNameRow);
      // çŠ¶æ€åœ¨ä¸‹ä¸€è¡Œ
      var $statusRow = $('<div class="patient-info-row"></div>');
      $statusRow.append('<span class="patient-status">' + queueStatusConvert(item.status) + '</span>');
      $item.append($statusRow);
      return $item;
    }
    // å¼€å§‹å®šæ—¶åˆ·æ–°
    function startScrolling() {
      getList();
      appState.timer = setInterval(function() {
        appState.runningIndicator++;
        $('#runningIndicator').css('backgroundColor', appState.runningIndicator % 2 === 0 ? '#67c23a' : '#e6a23c');
        getList();
        if (appState.curSpeakPat == null) {
          initiateSpeak();
        }
      }, 5000);
    }
    // è¯­éŸ³ç»“束事件
    function onSpeachEndEvent(event) {
      console.log("Speech ended... " + event.currentTarget.text);
      // è¿™é‡Œæ›¿æ¢ä¸ºå®žé™…çš„API调用
      $.ajax({
        url: appState.apiBaseUrl + '/ecg/call/update',
        method: 'PUT',
        data: {
          id: appState.curSpeakPat.id,
          called: 1
        },
        success: function() {
          initiateSpeak();
        },
        error: function(xhr, status, error) {
          console.error('更新叫号状态失败:', error);
        }
      });
    }
    // å«å·åŠŸèƒ½
    function initiateSpeak() {
      // è¿™é‡Œæ›¿æ¢ä¸ºå®žé™…çš„API调用
      $.ajax({
        url: appState.apiBaseUrl + '/ecg/call/next',
        type: 'GET',
        dataType: 'json',
        success: function(response) {
          appState.curSpeakPat = response.data || response;
          if (appState.curSpeakPat != null && appState.curSpeakPat.called === 0) {
            speak("请、" + appState.curSpeakPat.patName + "到" + appState.curSpeakPat.roomName + "就诊");
          }
        },
        error: function(xhr, status, error) {
          console.error('获取下一个叫号失败:', error);
        }
      });
    }
    // è¯­éŸ³æ’­æŠ¥
    function speak(msg) {
      console.info("speak " + msg);
      if (!appState.speechSynthesis) {
        console.warn("当前浏览器不支持语音合成");
        return;
      }
      // å–消当前正在进行的语音
      appState.speechSynthesis.cancel();
      var speech = new SpeechSynthesisUtterance();
      speech.text = msg + "。。。" + msg + "。。。" + msg + "。。。";
      speech.pitch = 1;
      speech.rate = 0.9;
      speech.volume = 100;
      speech.lang = 'zh-CN';
      speech.onend = onSpeachEndEvent;
      appState.speechSynthesis.speak(speech);
    }
    // å·¥å…·å‡½æ•°
    function nameDesensitize(patName) {
      if (!patName) return '';
      if (patName.length === 2) {
        return patName.substring(0, 1) + '*';
      } else if (patName.length === 3) {
        return patName.substring(0, 1) + '*' + patName.substring(2, 3);
      } else if (patName.length > 3) {
        return patName.substring(0, 1) + '*' + '*' + patName.substring(3, patName.length);
      }
      return patName;
    }
    function getItemCssClass(item) {
      if (item.status === 5 || item.status === 7) {
        return "warning-row";
      }
      return "";
    }
    function queueStatusConvert(status) {
      var statusMap = {
        3: '已过号-排队',
        5: '已过号',
        7: '已过号-安装',
        10: '排队中',
        12: '亲和',
        13: '亲和-安装',
        15: '已召回',
        20: '候诊中',
        30: '就诊中',
        33: '已领用',
        34: '已召回-安装',
        36: '安装中',
        40: '已就诊'
      };
      return statusMap[status] || '未知状态';
    }
    function getCheckTypeSeqPrefix(type) {
      var types = {
        1: 'A001',
        2: 'A002',
        3: 'A003',
        4: 'A004'
      };
      return types[type] || '';
    }
    // ç”Ÿæˆæ¨¡æ‹Ÿæ‚£è€…数据
    function generateMockPatients() {
      var mockData = {
        "0": generateMockPatientsForRoom(15, "常规心电图A"),
        "1": generateMockPatientsForRoom(8, "动态心电B"),
        "2": generateMockPatientsForRoom(5, "平板运动心电D"),
        "3": generateMockPatientsForRoom(3, "食道电生理F"),
        "4": generateMockPatientsForRoom(4, "动脉硬化监测E")
      };
      return new Map(Object.entries(mockData));
    }
    function generateMockPatientsForRoom(count, checkTypeName) {
      var mockPatients = [];
      var names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十'];
      var rooms = ['心电图室1', '心电图室2', '动态心电室', '心电监护室'];
      var statuses = [5, 7, 10, 12, 13, 15, 20, 30, 33, 34, 36, 40];
      var checkTypes = [1, 2, 3, 4];
      for (var i = 0; i < count; i++) {
        mockPatients.push({
          id: i + 1,
          patName: names[Math.floor(Math.random() * names.length)],
          roomName: rooms[Math.floor(Math.random() * rooms.length)],
          bedNo: '床' + (Math.floor(Math.random() * 20) + 1),
          status: statuses[Math.floor(Math.random() * statuses.length)],
          bookCheckType: checkTypes[Math.floor(Math.random() * checkTypes.length)],
          bookSeqNum: Math.floor(Math.random() * 50) + 1,
          called: 0,
          checkTypeName: checkTypeName
        });
      }
      return mockPatients;
    }
  </script>
</body>
</html>
public/static/jinhua.png