吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3389|回复: 41
收起左侧

[其他原创] 医院科室排班展示程序

  [复制链接]
ttyylfd 发表于 2025-8-27 17:29
本帖最后由 ttyylfd 于 2025-8-28 07:07 编辑

事情起因,我们医院比较low,大厅展示的排班是做成mp4在电视上播放的,因为涉及到比如大夫临时有事来不了需要修改排班的情况操作就很困难,所以写了这个东西。

理论上可以无限排,随时随地管理。管理页面也可以打包成APP在手机上安装,方便操作。
科室随便删减、人员随便删减、专家有专家标识、显示字号随便改、自适应屏幕。
我是将页面用变色龙打包了APP,给电视安装APP后就直接显示排班展示页面了。

weekly_schedule.php  是主展示页面

pages/login.php   是登陆页面

dayin.php   用于显示所有排班


后台都在\pages目录下
数据库连接信息在\includes\db.php

pb1.png



pb2.png

下载:https://689966.lanzoul.com/iQh6734nzrve 密码:ext2


当然,您需要服务器去运行,本地的服务也好,网络服务也好,反正是需要的。代码和数据文件请自取。


忘记贴部分代码了,现在补上。
pb3.png

[PHP] 纯文本查看 复制代码
<?php
date_default_timezone_set('Asia/Shanghai');
require_once 'includes/db.php';

// 获取字号设置
$stmt = $pdo->query("SELECT keming, xingming FROM zihao ORDER BY id DESC LIMIT 1");
$fontSizeSettings = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$fontSizeSettings) {
    // 默认值
    $fontSizeSettings = ['keming' => 13, 'xingming' => 13];
}

// 获取7天日期
$dates = [];
for ($i = 0; $i < 7; $i++) {
    $dateObj = new DateTime(date('Y-m-d', strtotime("+$i days")));
    $dayOfWeek = (int)$dateObj->format('w');
    $weekDay = match($dayOfWeek) {
        0 => '星期日',
        1 => '星期一',
        2 => '星期二',
        3 => '星期三',
        4 => '星期四',
        5 => '星期五',
        6 => '星期六',
        default => '未知',
    };
    $displayDate = (int)$dateObj->format('m') . '月' . (int)$dateObj->format('d') . '日';
    $label = $i === 0 ? '(今天)' : '';
    $dates[] = [
        'date' => $dateObj->format('Y-m-d'),
        'display_date' => "$displayDate $weekDay" . $label,
        'is_today' => $i === 0,
    ];
}

// 获取科室列表
$stmt = $pdo->query("SELECT id, name FROM departments ORDER BY order_num ASC");
$departments = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 获取每个日期的排班信息
$schedules_by_date = [];
foreach ($dates as $day) {
    $stmt = $pdo->prepare("
        SELECT d.name AS doctor_name, dp.id AS department_id, s.session, d.is_expert 
        FROM schedules s
        JOIN doctors d ON s.doctor_id = d.id
        JOIN departments dp ON d.department_id = dp.id
        WHERE s.date = ?
        ORDER BY s.session ASC
    ");
    $stmt->execute([$day['date']]);
    $schedules_by_date[$day['date']] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>科室排班表</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <style>
        * { 
            box-sizing: border-box; 
            margin: 0;
            padding: 0;
        }
        body, html {
            width: 100%;
            height: 100%;
            overflow: hidden;
            font-family: "Segoe UI", "Microsoft YaHei", sans-serif;
            background-color: #f9f9f9;
        }

        .slider-container {
            width: 100%;
            height: 100%;
            overflow: hidden;
            position: relative;
            padding: 0;
            display: flex;
            flex-direction: column;
        }

        .slides {
            display: flex;
            transition: transform 0.5s ease-in-out;
            height: 100%;
            width: 100%;
            flex: 1;
        }

        .slide {
            min-width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            padding: 0;
            box-sizing: border-box;
            overflow: hidden;
        }

        .table-container {
            width: 100%;
            height: 100%;
            overflow: auto;
            background-color: white;
            padding: 0;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            min-width: 100%;
            table-layout: fixed;
            height: 100%;
        }

        th, td {
            border: 1px solid #ddd;
            padding: 4px;
            text-align: center;
            vertical-align: middle;
            word-wrap: break-word;
            font-size: 14px;
            line-height: 1.2;
        }

        th {
            position: sticky;
            top: 0;
            z-index: 3;
            background: linear-gradient(to bottom, #0099ff, #007BFF);
            color: white;
            font-weight: bold;
            height: 40px;
        }

        .first-col-bg {
            position: sticky;
            left: 0;
            z-index: 2;
            background-color: #007BFF !important;
            color: white;
            font-weight: bold;
            min-width: 80px;
            width: 80px;
        }

        /* 浅红色底色 */
        .today-bg {
            background-color: #ffb3b3 !important; /* 浅红色 */
            color: #333 !important;
        }

        .today-bold {
            font-weight: bold;
        }

        .schedule-bg-lightgreen {
            background-color: #D7F3E3 !important;
        }

        .schedule-bg-lightgray {
            background-color: #EAEAEA !important;
        }

        .expert-badge {
            display: inline-block;
            background-color: #ffd700;
            color: #333;
            font-size: 10px;
            padding: 1px 4px;
            border-radius: 3px;
            margin-left: 2px;
            white-space: nowrap;
            font-weight: bold;
        }

        .doctor-name {
            font-weight: bold;
            display: block;
            margin: 0;
            padding: 0;
            line-height: 1.1;
        }

        .department-name {
            font-weight: bold;
        }

        /* 添加页码指示器 */
        .pagination {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            z-index: 10;
        }

        .pagination-dot {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background-color: #ccc;
            margin: 0 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .pagination-dot.active {
            background-color: #007BFF;
        }
        
        /* 响应式调整 */
        [url=home.php?mod=space&uid=945662]@media[/url] (max-height: 700px) {
            th, td {
                font-size: 12px;
                padding: 2px;
            }
            
            th {
                height: 35px;
            }
        }
        
        @media (max-height: 600px) {
            th, td {
                font-size: 11px;
                padding: 1px;
            }
            
            .expert-badge {
                font-size: 8px;
                padding: 0 2px;
            }
        }
        
        /* 刷新指示器 */
        .refresh-indicator {
            position: absolute;
            top: 10px;
            right: 10px;
            background-color: rgba(0, 123, 255, 0.8);
            color: white;
            padding: 5px 10px;
            border-radius: 4px;
            font-size: 12px;
            z-index: 100;
            display: none;
        }
        
        /* 确保所有列占满宽度 */
        .date-column {
            width: calc(100% / var(--date-count)); /* 动态计算宽度 */
        }
        
        /* 固定左侧列宽度 */
        .fixed-left-col {
            width: 80px;
            min-width: 80px;
        }
        
        /* 固定行高 */
        tbody tr {
            height: 40px;
        }
        
        tbody td {
            height: 40px;
        }
        
        /* 空白行样式 */
        .empty-row {
            visibility: hidden;
        }
        
        /* 在媒体查询中覆盖固定行高 */
        @media (max-height: 700px) {
            tbody tr {
                height: 35px;
            }
            
            tbody td {
                height: 35px;
            }
        }
        
        @media (max-height: 600px) {
            tbody tr {
                height: 30px;
            }
            
            tbody td {
                height: 30px;
            }
        }
    </style>
</head>
<body>

<div class="slider-container">
    <div class="refresh-indicator" id="refreshIndicator">数据刷新中...</div>
    <div class="slides" id="slides">
        <!-- 动态插入分页内容 -->
    </div>
    <div class="pagination" id="pagination"></div>
</div>

<script>
    // 全局变量存储数据
    let departments = <?= json_encode($departments) ?>;
    let dates = <?= json_encode($dates) ?>;
    let schedulesByDate = <?= json_encode($schedules_by_date) ?>;
    let fontSizeSettings = <?= json_encode($fontSizeSettings) ?>; // 获取字号设置
    
    // 固定每页显示5个科室
    const PAGE_SIZE = 5;
    
    // 刷新状态管理
    let refreshInterval = null;
    let refreshTimeout = null;
    let lastRefreshTime = Date.now();
    let currentPage = 0;
    let totalPages = 0;
    let isRefreshing = false;

    function createPage(deptChunk) {
        const container = document.createElement('div');
        container.className = 'slide';
        
        const tableContainer = document.createElement('div');
        tableContainer.className = 'table-container';
        container.appendChild(tableContainer);
        
        const table = document.createElement('table');
        
        // 设置CSS变量,用于动态计算列宽
        table.style.setProperty('--date-count', dates.length);

        // 表头:只一行
        const thead = document.createElement('thead');
        const headerRow = document.createElement('tr');
        const deptHeader = document.createElement('th');
        deptHeader.textContent = '科室';
        deptHeader.classList.add('first-col-bg', 'department-name', 'fixed-left-col');
        // 应用科室名称字号
        deptHeader.style.fontSize = `${fontSizeSettings.keming}px`;
        headerRow.appendChild(deptHeader);

        dates.forEach(day => {
            const th = document.createElement('th');
            const dateParts = day.display_date.split(' ');
            th.innerHTML = `${dateParts[0]}<br>${dateParts[1]}`;
            th.classList.add('date-column'); // 添加日期列类
            
            if (day.is_today) {
                th.classList.add('today-bg', 'today-bold');
            }
            headerRow.appendChild(th);
        });

        thead.appendChild(headerRow);
        table.appendChild(thead);

        // 表体:每科室占两行
        const tbody = document.createElement('tbody');

        // 添加实际科室行
        deptChunk.forEach((dept, idx) => {
            const bgClass = idx % 2 === 0 ? 'schedule-bg-lightgreen' : 'schedule-bg-lightgray';

            // 上午行
            const amRow = document.createElement('tr');

            const deptCell = document.createElement('td');
            deptCell.textContent = dept.name;
            deptCell.setAttribute('rowspan', '2');
            deptCell.classList.add('first-col-bg', 'department-name', 'fixed-left-col');
            // 应用科室名称字号
            deptCell.style.fontSize = `${fontSizeSettings.keming}px`;
            amRow.appendChild(deptCell);

            dates.forEach(day => {
                const cell = document.createElement('td');
                cell.classList.add('date-column'); // 添加日期列类
                
                // 如果是今天,添加特殊样式
                if (day.is_today) {
                    cell.classList.add('today-bg', 'today-bold');
                } else {
                    cell.classList.add(bgClass);
                }

                const amDoctors = schedulesByDate[day.date].filter(s =>
                    s.department_id == dept.id && s.session.includes('AM')
                );

                if (amDoctors.length > 0) {
                    amDoctors.forEach(d => {
                        const doctorContainer = document.createElement('div');
                        const nameSpan = document.createElement('span');
                        nameSpan.className = 'doctor-name';
                        nameSpan.textContent = d.doctor_name;
                        // 应用医师姓名字号
                        nameSpan.style.fontSize = `${fontSizeSettings.xingming}px`;
                        
                        if (d.is_expert) {
                            const badge = document.createElement('span');
                            badge.textContent = '专家';
                            badge.className = 'expert-badge';
                            nameSpan.appendChild(badge);
                        }
                        
                        doctorContainer.appendChild(nameSpan);
                        cell.appendChild(doctorContainer);
                    });
                } else {
                    cell.textContent = '-';
                }

                amRow.appendChild(cell);
            });

            // 下午行
            const pmRow = document.createElement('tr');
            dates.forEach(day => {
                const cell = document.createElement('td');
                cell.classList.add('date-column'); // 添加日期列类
                
                // 如果是今天,添加特殊样式
                if (day.is_today) {
                    cell.classList.add('today-bg', 'today-bold');
                } else {
                    cell.classList.add(bgClass);
                }

                const pmDoctors = schedulesByDate[day.date].filter(s =>
                    s.department_id == dept.id && s.session.includes('PM')
                );

                if (pmDoctors.length > 0) {
                    pmDoctors.forEach(d => {
                        const doctorContainer = document.createElement('div');
                        const nameSpan = document.createElement('span');
                        nameSpan.className = 'doctor-name';
                        nameSpan.textContent = d.doctor_name;
                        // 应用医师姓名字号
                        nameSpan.style.fontSize = `${fontSizeSettings.xingming}px`;
                        
                        if (d.is_expert) {
                            const badge = document.createElement('span');
                            badge.textContent = '专家';
                            badge.className = 'expert-badge';
                            nameSpan.appendChild(badge);
                        }
                        
                        doctorContainer.appendChild(nameSpan);
                        cell.appendChild(doctorContainer);
                    });
                } else {
                    cell.textContent = '-';
                }

                pmRow.appendChild(cell);
            });

            tbody.appendChild(amRow);
            tbody.appendChild(pmRow);
        });

        // 确保每页都有5个科室的高度(10行)
        const actualRows = deptChunk.length * 2;
        const neededRows = PAGE_SIZE * 2;
        const emptyRows = neededRows - actualRows;
        
        // 只在需要时添加空白行
        if (emptyRows > 0) {
            for (let i = 0; i < emptyRows; i++) {
                const emptyRow = document.createElement('tr');
                emptyRow.classList.add('empty-row');
                
                // 科室列(只在第一行添加)
                if (i === 0) {
                    const deptCell = document.createElement('td');
                    deptCell.classList.add('first-col-bg', 'fixed-left-col');
                    deptCell.setAttribute('rowspan', emptyRows);
                    emptyRow.appendChild(deptCell);
                }
                
                // 日期列
                dates.forEach(() => {
                    const cell = document.createElement('td');
                    cell.textContent = '';
                    cell.classList.add('date-column');
                    emptyRow.appendChild(cell);
                });
                
                tbody.appendChild(emptyRow);
            }
        }

        table.appendChild(tbody);
        tableContainer.appendChild(table);
        
        return container;
    }

    function buildSlider() {
        const slidesContainer = document.getElementById('slides');
        const paginationContainer = document.getElementById('pagination');
        
        // 固定每页显示5个科室
        const pageSize = PAGE_SIZE;
        totalPages = Math.ceil(departments.length / pageSize);
        
        // 清空容器
        slidesContainer.innerHTML = '';
        paginationContainer.innerHTML = '';
        
        // 创建分页指示器
        for (let i = 0; i < totalPages; i++) {
            const dot = document.createElement('div');
            dot.className = 'pagination-dot';
            dot.dataset.page = i;
            if (i === 0) dot.classList.add('active');
            paginationContainer.appendChild(dot);
        }
        
        // 创建分页内容
        for (let i = 0; i < departments.length; i += pageSize) {
            const chunk = departments.slice(i, i + pageSize);
            const page = createPage(chunk);
            slidesContainer.appendChild(page);
        }
        
        // 初始显示当前页
        updateSlider(currentPage);
        
        // 添加分页点击事件
        document.querySelectorAll('.pagination-dot').forEach(dot => {
            dot.addEventListener('click', () => {
                currentPage = parseInt(dot.dataset.page);
                updateSlider(currentPage);
                resetAutoSlide();
            });
        });
    }
    
    // 更新滑块位置
    function updateSlider(pageIndex) {
        const slidesContainer = document.getElementById('slides');
        slidesContainer.style.transform = `translateX(-${pageIndex * 100}%)`;
        
        // 更新分页指示器
        document.querySelectorAll('.pagination-dot').forEach((dot, index) => {
            dot.classList.toggle('active', index === pageIndex);
        });
        
        // 检查是否在最后一页
        if (pageIndex === totalPages - 1) {
            // 在最后一页显示后安排整页刷新
            scheduleFullRefresh();
        }
    }
    
    // 重置自动轮播
    function resetAutoSlide() {
        // 清除旧定时器
        clearInterval(refreshInterval);
        
        // 启动新的轮播
        refreshInterval = setInterval(() => {
            currentPage = (currentPage + 1) % totalPages;
            updateSlider(currentPage);
        }, 7000);
    }
    
    // 安排整页刷新
    function scheduleFullRefresh() {
        // 取消之前的刷新安排
        clearTimeout(refreshTimeout);
        
        // 安排在5秒后整页刷新
        refreshTimeout = setTimeout(() => {
            // 整页刷新(强制从服务器获取)
            location.reload(true);
        }, 5000); // 在最后一页停留5秒后刷新
    }

    window.onload = () => {
        buildSlider();
        resetAutoSlide();
        
        // 在页面加载后立即检查是否需要刷新
        setTimeout(() => {
            // 如果超过30秒未刷新,且当前是最后一页
            if (currentPage === totalPages - 1 && Date.now() - lastRefreshTime > 30000) {
                scheduleFullRefresh();
            }
        }, 1000);
    };
    
    // 窗口大小变化时重新构建滑块
    window.addEventListener('resize', () => {
        // 重新构建滑块
        buildSlider();
        updateSlider(currentPage);
        resetAutoSlide();
    });
</script>

</body>
</html>

免费评分

参与人数 7吾爱币 +15 热心值 +6 收起 理由
qsj521521 + 1 + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
wy192500 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
tzxinqing + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
PythonPan + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
wuloveyou + 1 + 1 我很赞同!
mengmei + 1 用心讨论,共获提升!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| ttyylfd 发表于 2025-8-27 17:47
yifengzi 发表于 2025-8-27 17:40
播放ppt是不是最简单的方法

一直是电视上播放mp4      PPT不知道她们试过没有   反正我是看不下去了
lin5574 发表于 2025-8-27 20:10
ttyylfd 发表于 2025-8-27 17:47
一直是电视上播放mp4      PPT不知道她们试过没有   反正我是看不下去了

没办法,应该是太LOW了。实在是受不了。自己动手整一个。。可惜在其位的不谋其政
 楼主| ttyylfd 发表于 2025-8-27 17:31
第一列总数显示当天,后面连跟6天。  每屏显示5个科室,轮播。
yifengzi 发表于 2025-8-27 17:40
播放ppt是不是最简单的方法
linsixi 发表于 2025-8-27 18:03
楼主的想法不错,这个比较容易实现,还可以做成APP手机后台控制。方便简单。
Waltxiao919 发表于 2025-8-27 18:18
不错的分享
ynworktean 发表于 2025-8-27 18:26
不错不错!
dr-pan 发表于 2025-8-27 18:33
ptt投屏简单方便,易操作,一个U盘搞定
wahahehe 发表于 2025-8-27 18:40
谢谢分享,虽然一般用不到,收藏备用
dupengpeng 发表于 2025-8-27 18:45
老师您好 想咨询一下您有没有医院管理的软件  
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-2-20 16:04

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表