邀请码管理edit icon

创建者:
用户VaAPqVEZ
Fork(复制)
下载
嵌入
BUG反馈
index.html
md
README.md
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>邀请码管理系统</title>
    <!-- Tailwind CSS v3 -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Font Awesome -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/css/font-awesome.min.css" rel="stylesheet">
    <!-- 统一的 Tailwind 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3b82f6',
                        secondary: '#64748b',
                        success: '#10b981',
                        warning: '#f59e0b',
                        danger: '#ef4444',
                        light: '#f3f4f6',
                        dark: '#1f2937'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                    boxShadow: {
                        card: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
                        modal: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
                    }
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .transition-all-300 {
                transition: all 300ms ease-in-out;
            }
            .glass-effect {
                background: rgba(255, 255, 255, 0.7);
                backdrop-filter: blur(10px);
                -webkit-backdrop-filter: blur(10px);
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen">
    <div class="container mx-auto px-4 py-8">
        <!-- 页面标题 -->
        <header class="mb-8">
            <h1 class="text-3xl font-bold text-gray-800">邀请码管理系统</h1>
            <p class="text-gray-600 mt-2">管理医生邀请码的生成、使用和失效情况</p>
        </header>

        <!-- 筛选区域 -->
        <section class="bg-white rounded-lg shadow-card p-6 mb-6">
            <h2 class="text-xl font-semibold text-gray-800 mb-4">筛选条件</h2>
            <div class="grid grid-cols-1 md:grid-cols-5 gap-6">
                <!-- 医生姓名筛选 -->
                <div>
                    <label for="doctor-name" class="block text-sm font-medium text-gray-700 mb-1">医生姓名</label>
                    <input type="text" id="doctor-name" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all-300" placeholder="请输入医生姓名">
                </div>
                
                <!-- 医院名称筛选 -->
                <div>
                    <label for="hospital-name" class="block text-sm font-medium text-gray-700 mb-1">医院名称</label>
                    <input type="text" id="hospital-name" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all-300" placeholder="请输入医院名称">
                </div>
                
                <!-- 已生成总数 -->
                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-1">已生成总数</label>
                    <div id="total-generated" class="w-full px-4 py-2 bg-gray-50 border border-gray-300 rounded-md text-gray-800 font-medium">0</div>
                </div>
                
                <!-- 未使用总数 -->
                <div>
                    <label class="block text-sm font-medium text-gray-700 mb-1">未使用总数</label>
                    <div id="total-unused" class="w-full px-4 py-2 bg-gray-50 border border-gray-300 rounded-md text-blue-600 font-medium">0</div>
                </div>
                
                <!-- 新增邀请码按钮 -->
                <div class="flex items-end">
                    <button id="main-add-code-btn" class="w-full px-4 py-2 bg-primary text-white rounded-md hover:bg-blue-600 transition-all-300">
                        <i class="fa fa-plus mr-2"></i>新增邀请码
                    </button>
                </div>
            </div>
            
            <!-- 筛选按钮 -->
            <div class="mt-6 flex justify-end">
                <button id="reset-filter" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition-all-300 mr-3">
                    <i class="fa fa-refresh mr-2"></i>重置
                </button>
                <button id="apply-filter" class="px-6 py-2 bg-primary text-white rounded-md hover:bg-blue-600 transition-all-300">
                    <i class="fa fa-search mr-2"></i>筛选
                </button>
            </div>
        </section>

        <!-- 医生列表区域 -->
        <section class="bg-white rounded-lg shadow-card overflow-hidden">
            <div class="p-6 border-b border-gray-200">
                <h2 class="text-xl font-semibold text-gray-800">医生邀请码列表</h2>
            </div>
            
            <!-- 列表头部 -->
            <div class="grid grid-cols-12 bg-gray-50 px-6 py-3 text-sm font-medium text-gray-500 border-b border-gray-200">
                <div class="col-span-2">医生姓名</div>
                <div class="col-span-2">医院名称</div>
                <div class="col-span-1 text-center">未使用</div>
                <div class="col-span-1 text-center">已使用</div>
                <div class="col-span-1 text-center">已失效</div>
                <div class="col-span-2 text-center">统计(已生成/总上限)</div>
                <div class="col-span-2 text-center">操作</div>
            </div>
            
            <!-- 列表内容 -->
            <div id="doctor-list" class="divide-y divide-gray-200">
                <!-- 列表项将通过JavaScript动态生成 -->
            </div>
            
            <!-- 分页区域 -->
            <div class="px-6 py-4 flex items-center justify-between border-t border-gray-200">
                <div class="text-sm text-gray-700">
                    显示 <span id="start-item">1</span> 到 <span id="end-item">10</span> 条,共 <span id="total-items">0</span> 条
                </div>
                <div class="flex space-x-2">
                    <button id="prev-page" class="px-3 py-1 border border-gray-300 rounded-md text-sm disabled:opacity-50 disabled:cursor-not-allowed">
                        <i class="fa fa-chevron-left"></i>
                    </button>
                    <button id="next-page" class="px-3 py-1 border border-gray-300 rounded-md text-sm disabled:opacity-50 disabled:cursor-not-allowed">
                        <i class="fa fa-chevron-right"></i>
                    </button>
                </div>
            </div>
        </section>
    </div>

    <!-- 明细浮窗 -->
    <div id="detail-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
        <div class="bg-white rounded-lg shadow-modal w-full max-w-2xl max-h-[90vh] overflow-hidden flex flex-col">
            <!-- 浮窗头部 -->
            <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
                <h3 class="text-xl font-semibold text-gray-800">邀请码明细</h3>
                <button id="close-modal" class="text-gray-500 hover:text-gray-700">
                    <i class="fa fa-times text-xl"></i>
                </button>
            </div>
            
            <!-- 浮窗内容 -->
            <div class="px-6 py-4 overflow-y-auto flex-grow">
                <div class="mb-4">
                    <span class="text-gray-600">医生姓名:</span>
                    <span id="detail-doctor-name" class="font-medium text-gray-800"></span>
                </div>
                
                <!-- 明细筛选 -->
                <div class="mb-4 grid grid-cols-12 gap-4">
                    <div class="col-span-4">
                        <input type="text" id="detail-code-filter" class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="筛选邀请码">
                    </div>
                    <div class="col-span-3">
                        <select id="detail-status-filter" class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
                            <option value="">全部状态</option>
                            <option value="unused">未使用</option>
                            <option value="used">已使用</option>
                            <option value="expired">已失效</option>
                        </select>
                    </div>
                    <div class="col-span-5 flex gap-2">
                        <input type="datetime-local" id="detail-date-from" class="w-1/2 px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="开始日期">
                        <span class="flex items-center text-gray-500">至</span>
                        <input type="datetime-local" id="detail-date-to" class="w-1/2 px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent" placeholder="结束日期">
                    </div>
                </div>
                
                <!-- 邀请码列表 -->
                <div class="grid grid-cols-12 bg-gray-50 px-4 py-2 text-sm font-medium text-gray-500 rounded-t-md">
                    <div class="col-span-5">邀请码</div>
                    <div class="col-span-3">状态</div>
                    <div class="col-span-4">失效日期</div>
                </div>
                <div id="code-detail-list" class="divide-y divide-gray-200 bg-white rounded-b-md">
                    <!-- 邀请码明细将通过JavaScript动态生成 -->
                </div>
            </div>
            
            <!-- 浮窗底部 -->
            <div class="px-6 py-4 border-t border-gray-200 flex justify-end">
                <button id="close-detail-modal" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition-all-300">
                    关闭
                </button>
            </div>
        </div>
    </div>

    <!-- 新增邀请码浮窗 -->
    <div id="add-code-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
        <div class="bg-white rounded-lg shadow-modal w-full max-w-md">
            <!-- 浮窗头部 -->
            <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
                <h3 class="text-xl font-semibold text-gray-800">新增邀请码</h3>
                <button id="close-add-modal" class="text-gray-500 hover:text-gray-700">
                    <i class="fa fa-times text-xl"></i>
                </button>
            </div>
            
            <!-- 浮窗内容 -->
            <div class="px-6 py-6">
                <div class="mb-6">
                    <label for="doctor-select" class="block text-sm font-medium text-gray-700 mb-1">医生姓名</label>
                    <select id="doctor-select" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all-300">
                        <!-- 医生选项将通过JavaScript动态生成 -->
                    </select>
                </div>
                
                <div class="mb-6">
                    <label for="code-count" class="block text-sm font-medium text-gray-700 mb-1">生成数量</label>
                    <input type="number" id="code-count" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all-300" min="1" max="100" value="10">
                </div>
                
                <div class="mb-6">
                    <label for="expire-time" class="block text-sm font-medium text-gray-700 mb-1">失效时间</label>
                    <input type="datetime-local" id="expire-time" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent transition-all-300">
                </div>
            </div>
            
            <!-- 浮窗底部 -->
            <div class="px-6 pb-6 pt-2 flex justify-end">
                <button id="cancel-add-code" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition-all-300 mr-3">
                    取消
                </button>
                <button id="confirm-add-code" class="px-6 py-2 bg-primary text-white rounded-md hover:bg-blue-600 transition-all-300">
                    确认生成
                </button>
            </div>
        </div>
    </div>

    <!-- 提示消息 -->
    <div id="toast" class="fixed top-4 right-4 bg-white rounded-lg shadow-card px-6 py-3 flex items-center z-50 transform translate-x-full transition-all duration-300">
        <div id="toast-icon" class="mr-3 text-xl"></div>
        <div id="toast-message" class="text-gray-800"></div>
    </div>

    <script>
        // 模拟数据
        const mockDoctors = [
            {
                id: 1,
                name: "张医生",
                hospital: "北京协和医院",
                codes: [
                    { code: "ABC123", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "DEF456", status: "used", expireTime: "2026-12-31T23:59:59" },
                    { code: "GHI789", status: "expired", expireTime: "2025-12-31T23:59:59" },
                    { code: "JKL012", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "MNO345", status: "unused", expireTime: "2026-12-31T23:59:59" }
                ]
            },
            {
                id: 2,
                name: "李医生",
                hospital: "上海瑞金医院",
                codes: [
                    { code: "PQR678", status: "used", expireTime: "2026-12-31T23:59:59" },
                    { code: "STU901", status: "used", expireTime: "2026-12-31T23:59:59" },
                    { code: "VWX234", status: "unused", expireTime: "2026-12-31T23:59:59" }
                ]
            },
            {
                id: 3,
                name: "王医生",
                hospital: "广州中山医院",
                codes: [
                    { code: "YZA567", status: "expired", expireTime: "2025-12-31T23:59:59" },
                    { code: "BCD890", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "EFG123", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "HIJ456", status: "unused", expireTime: "2026-12-31T23:59:59" }
                ]
            },
            {
                id: 4,
                name: "赵医生",
                hospital: "北京协和医院",
                codes: [
                    { code: "KLM789", status: "used", expireTime: "2026-12-31T23:59:59" },
                    { code: "NOP012", status: "unused", expireTime: "2026-12-31T23:59:59" }
                ]
            },
            {
                id: 5,
                name: "刘医生",
                hospital: "上海瑞金医院",
                codes: [
                    { code: "QRS345", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "TUV678", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "WXY901", status: "expired", expireTime: "2025-12-31T23:59:59" },
                    { code: "ZAB234", status: "used", expireTime: "2026-12-31T23:59:59" },
                    { code: "CDE567", status: "unused", expireTime: "2026-12-31T23:59:59" },
                    { code: "FGH890", status: "unused", expireTime: "2026-12-31T23:59:59" }
                ]
            }
        ];

        // 全局变量
        let currentPage = 1;
        const itemsPerPage = 10;
        let filteredDoctors = [...mockDoctors];
        let currentDoctorId = null;

        // DOM 加载完成后执行
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化页面
            renderDoctorList();
            setupEventListeners();
            updateStatistics();
            
            // 设置默认失效时间为30天后
            const defaultExpireTime = new Date();
            defaultExpireTime.setDate(defaultExpireTime.getDate() + 30);
            document.getElementById('expire-time').value = formatDateTime(defaultExpireTime);
        });

        // 设置事件监听器
        function setupEventListeners() {
            // 筛选按钮
            document.getElementById('apply-filter').addEventListener('click', applyFilter);
            document.getElementById('reset-filter').addEventListener('click', resetFilter);
            
            // 分页按钮
            document.getElementById('prev-page').addEventListener('click', goToPrevPage);
            document.getElementById('next-page').addEventListener('click', goToNextPage);
            
            // 明细浮窗
            document.getElementById('close-modal').addEventListener('click', closeDetailModal);
            document.getElementById('close-detail-modal').addEventListener('click', closeDetailModal);
            
            // 新增邀请码浮窗
            document.getElementById('main-add-code-btn').addEventListener('click', openAddCodeModal);
            document.getElementById('close-add-modal').addEventListener('click', closeAddCodeModal);
            document.getElementById('cancel-add-code').addEventListener('click', closeAddCodeModal);
            document.getElementById('confirm-add-code').addEventListener('click', confirmAddCode);
            
            // 明细筛选
            document.getElementById('detail-code-filter').addEventListener('input', filterDetailList);
            document.getElementById('detail-status-filter').addEventListener('change', filterDetailList);
            document.getElementById('detail-date-from').addEventListener('change', filterDetailList);
            document.getElementById('detail-date-to').addEventListener('change', filterDetailList);
            
            // 点击浮窗外区域关闭浮窗
            document.getElementById('detail-modal').addEventListener('click', function(e) {
                if (e.target === this) closeDetailModal();
            });
            document.getElementById('add-code-modal').addEventListener('click', function(e) {
                if (e.target === this) closeAddCodeModal();
            });
        }

        // 渲染医生列表
        function renderDoctorList() {
            const doctorList = document.getElementById('doctor-list');
            doctorList.innerHTML = '';
            
            // 计算分页
            const startIndex = (currentPage - 1) * itemsPerPage;
            const endIndex = Math.min(startIndex + itemsPerPage, filteredDoctors.length);
            const pageDoctors = filteredDoctors.slice(startIndex, endIndex);
            
            // 更新分页信息
            document.getElementById('start-item').textContent = filteredDoctors.length > 0 ? startIndex + 1 : 0;
            document.getElementById('end-item').textContent = endIndex;
            document.getElementById('total-items').textContent = filteredDoctors.length;
            
            // 更新分页按钮状态
            document.getElementById('prev-page').disabled = currentPage === 1;
            document.getElementById('next-page').disabled = endIndex >= filteredDoctors.length;
            
            // 渲染列表项
            if (pageDoctors.length === 0) {
                const emptyItem = document.createElement('div');
                emptyItem.className = 'px-6 py-10 text-center text-gray-500';
                emptyItem.textContent = '暂无数据';
                doctorList.appendChild(emptyItem);
            } else {
                pageDoctors.forEach(doctor => {
                    const item = document.createElement('div');
                    item.className = 'grid grid-cols-12 px-6 py-4 hover:bg-gray-50 transition-all-300';
                    
                    // 计算邀请码使用情况
                    const unused = doctor.codes.filter(code => code.status === 'unused').length;
                    const used = doctor.codes.filter(code => code.status === 'used').length;
                    const expired = doctor.codes.filter(code => code.status === 'expired').length;
                    const generated = unused + used; // 已生成 = 未使用 + 已使用
                    
                    // 设置总上限
                    const totalLimit = 100;
                    
                    item.innerHTML = `
                        <div class="col-span-2 font-medium text-gray-800">${doctor.name}</div>
                        <div class="col-span-2 text-gray-600">${doctor.hospital}</div>
                        <div class="col-span-1 text-center font-medium text-blue-600">${unused}</div>
                        <div class="col-span-1 text-center font-medium text-green-600">${used}</div>
                        <div class="col-span-1 text-center font-medium text-red-600">${expired}</div>
                        <div class="col-span-2 text-center">
                            <span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">${Math.min(generated, totalLimit)}/${totalLimit}</span>
                        </div>
                        <div class="col-span-2 text-center">
                            <button class="view-detail px-3 py-1 bg-primary text-white rounded-md hover:bg-blue-600 transition-all-300" data-doctor-id="${doctor.id}">
                                明细
                            </button>
                        </div>
                    `;
                    
                    doctorList.appendChild(item);
                });
                
                // 添加明细按钮点击事件
                document.querySelectorAll('.view-detail').forEach(button => {
                    button.addEventListener('click', function() {
                        const doctorId = parseInt(this.getAttribute('data-doctor-id'));
                        openDetailModal(doctorId);
                    });
                });
            }
        }

        // 应用筛选
        function applyFilter() {
            const doctorName = document.getElementById('doctor-name').value.trim().toLowerCase();
            const hospitalName = document.getElementById('hospital-name').value.trim().toLowerCase();
            
            filteredDoctors = mockDoctors.filter(doctor => {
                // 筛选医生姓名
                const nameMatch = doctorName === '' || doctor.name.toLowerCase().includes(doctorName);
                // 筛选医院名称
                const hospitalMatch = hospitalName === '' || doctor.hospital.toLowerCase().includes(hospitalName);
                return nameMatch && hospitalMatch;
            });
            
            currentPage = 1;
            renderDoctorList();
            updateStatistics();
        }

        // 重置筛选
        function resetFilter() {
            document.getElementById('doctor-name').value = '';
            document.getElementById('hospital-name').value = '';
            
            filteredDoctors = [...mockDoctors];
            currentPage = 1;
            renderDoctorList();
            updateStatistics();
        }

        // 上一页
        function goToPrevPage() {
            if (currentPage > 1) {
                currentPage--;
                renderDoctorList();
            }
        }

        // 下一页
        function goToNextPage() {
            const maxPage = Math.ceil(filteredDoctors.length / itemsPerPage);
            if (currentPage < maxPage) {
                currentPage++;
                renderDoctorList();
            }
        }

        // 打开明细浮窗
        function openDetailModal(doctorId) {
            const doctor = mockDoctors.find(d => d.id === doctorId);
            if (!doctor) return;
            
            currentDoctorId = doctorId;
            document.getElementById('detail-doctor-name').textContent = doctor.name;
            
            // 重置筛选条件
            document.getElementById('detail-code-filter').value = '';
            document.getElementById('detail-status-filter').value = '';
            document.getElementById('detail-date-from').value = '';
            document.getElementById('detail-date-to').value = '';
            
            // 渲染明细列表
            renderDetailList(doctor.codes);
            
            document.getElementById('detail-modal').classList.remove('hidden');
        }

        // 关闭明细浮窗
        function closeDetailModal() {
            document.getElementById('detail-modal').classList.add('hidden');
            currentDoctorId = null;
        }

        // 打开新增邀请码浮窗
        function openAddCodeModal() {
            // 填充医生选择下拉框
            populateDoctorSelect();
            
            document.getElementById('add-code-modal').classList.remove('hidden');
        }

        // 关闭新增邀请码浮窗
        function closeAddCodeModal() {
            document.getElementById('add-code-modal').classList.add('hidden');
        }

        // 更新统计信息
        function updateStatistics() {
            let totalGenerated = 0;
            let totalUnused = 0;
            
            mockDoctors.forEach(doctor => {
                const unused = doctor.codes.filter(code => code.status === 'unused').length;
                const used = doctor.codes.filter(code => code.status === 'used').length;
                totalGenerated += unused + used;
                totalUnused += unused;
            });
            
            document.getElementById('total-generated').textContent = totalGenerated;
            document.getElementById('total-unused').textContent = totalUnused;
        }
        
        // 填充医生选择下拉框
        function populateDoctorSelect() {
            const select = document.getElementById('doctor-select');
            select.innerHTML = '';
            
            mockDoctors.forEach(doctor => {
                const option = document.createElement('option');
                option.value = doctor.id;
                option.textContent = `${doctor.name} - ${doctor.hospital}`;
                select.appendChild(option);
            });
            
            // 如果当前有选中的医生,设置为默认选中
            if (currentDoctorId) {
                select.value = currentDoctorId;
            }
        }
        
        // 筛选明细列表
        function filterDetailList() {
            const codeFilter = document.getElementById('detail-code-filter').value.trim().toUpperCase();
            const statusFilter = document.getElementById('detail-status-filter').value;
            const dateFrom = document.getElementById('detail-date-from').value;
            const dateTo = document.getElementById('detail-date-to').value;
            
            const doctor = mockDoctors.find(d => d.id === currentDoctorId);
            if (!doctor) return;
            
            const filteredCodes = doctor.codes.filter(code => {
                // 筛选邀请码
                const codeMatch = codeFilter === '' || code.code.includes(codeFilter);
                
                // 筛选状态
                const statusMatch = statusFilter === '' || code.status === statusFilter;
                
                // 筛选日期范围
                let dateMatch = true;
                if (dateFrom) {
                    const codeDate = new Date(code.expireTime);
                    const fromDate = new Date(dateFrom);
                    dateMatch = dateMatch && codeDate >= fromDate;
                }
                
                if (dateTo) {
                    const codeDate = new Date(code.expireTime);
                    const toDate = new Date(dateTo);
                    dateMatch = dateMatch && codeDate <= toDate;
                }
                
                return codeMatch && statusMatch && dateMatch;
            });
            
            renderDetailList(filteredCodes);
        }
        
        // 渲染明细列表
        function renderDetailList(codes) {
            const codeList = document.getElementById('code-detail-list');
            codeList.innerHTML = '';
            
            if (codes.length === 0) {
                const emptyItem = document.createElement('div');
                emptyItem.className = 'px-4 py-6 text-center text-gray-500';
                emptyItem.textContent = '暂无邀请码';
                codeList.appendChild(emptyItem);
            } else {
                codes.forEach(code => {
                    const item = document.createElement('div');
                    item.className = 'grid grid-cols-12 px-4 py-3 hover:bg-gray-50 transition-all-300';
                    
                    // 格式化失效时间(仅显示日期)
                    const expireTime = new Date(code.expireTime);
                    const formattedTime = expireTime.toLocaleDateString('zh-CN', {
                        year: 'numeric',
                        month: '2-digit',
                        day: '2-digit'
                    });
                    
                    // 根据状态设置样式
                    let statusText = '';
                    let statusClass = '';
                    
                    switch (code.status) {
                        case 'unused':
                            statusText = '未使用';
                            statusClass = 'bg-blue-100 text-blue-800';
                            break;
                        case 'used':
                            statusText = '已使用';
                            statusClass = 'bg-green-100 text-green-800';
                            break;
                        case 'expired':
                            statusText = '已失效';
                            statusClass = 'bg-red-100 text-red-800';
                            break;
                    }
                    
                    item.innerHTML = `
                        <div class="col-span-5 font-mono text-gray-800">${code.code}</div>
                        <div class="col-span-3">
                            <span class="px-2 py-1 ${statusClass} rounded-full text-xs">${statusText}</span>
                        </div>
                        <div class="col-span-4 text-gray-600">${formattedTime}</div>
                    `;
                    
                    codeList.appendChild(item);
                });
            }
        }
        
        // 确认新增邀请码
        function confirmAddCode() {
            const doctorId = parseInt(document.getElementById('doctor-select').value);
            const count = parseInt(document.getElementById('code-count').value);
            const expireTime = document.getElementById('expire-time').value;
            
            // 获取当前医生信息
            const doctor = mockDoctors.find(d => d.id === doctorId);
            if (!doctor) {
                showToast('error', '未找到医生信息');
                return;
            }
            
            // 设置总上限
            const totalLimit = 100;
            
            // 验证输入
            if (isNaN(count) || count < 1) {
                showToast('error', '请输入有效的生成数量(至少1个)');
                return;
            }
            
            // 检查是否超过总上限
            if (doctor.codes.length + count > totalLimit) {
                showToast('error', `生成数量超过总上限,最多还可生成 ${totalLimit - doctor.codes.length} 个邀请码`);
                return;
            }
            
            if (!expireTime) {
                showToast('error', '请选择失效时间');
                return;
            }
            
            // 生成随机邀请码
            for (let i = 0; i < count; i++) {
                const newCode = generateRandomCode();
                doctor.codes.push({
                    code: newCode,
                    status: 'unused',
                    expireTime: new Date(expireTime).toISOString().slice(0, 19).replace('T', ' ')
                });
            }
            
            // 关闭浮窗
            closeAddCodeModal();
            
            // 刷新主列表和统计信息
            applyFilter();
            
            showToast('success', `成功生成 ${count} 个邀请码`);
        }

        // 生成随机邀请码
        function generateRandomCode() {
            const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
            let code = '';
            for (let i = 0; i < 6; i++) {
                code += chars.charAt(Math.floor(Math.random() * chars.length));
            }
            return code;
        }

        // 格式化日期时间
        function formatDateTime(date) {
            const year = date.getFullYear();
            const month = String(date.getMonth() + 1).padStart(2, '0');
            const day = String(date.getDate()).padStart(2, '0');
            const hours = String(date.getHours()).padStart(2, '0');
            const minutes = String(date.getMinutes()).padStart(2, '0');
            
            return `${year}-${month}-${day}T${hours}:${minutes}`;
        }

        // 显示提示消息
        function showToast(type, message) {
            const toast = document.getElementById('toast');
            const toastIcon = document.getElementById('toast-icon');
            const toastMessage = document.getElementById('toast-message');
            
            // 设置图标和颜色
            if (type === 'success') {
                toastIcon.className = 'mr-3 text-xl text-green-500';
                toastIcon.innerHTML = '<i class="fa fa-check-circle"></i>';
                toast.classList.add('border-l-4', 'border-green-500');
            } else if (type === 'error') {
                toastIcon.className = 'mr-3 text-xl text-red-500';
                toastIcon.innerHTML = '<i class="fa fa-exclamation-circle"></i>';
                toast.classList.add('border-l-4', 'border-red-500');
            } else if (type === 'warning') {
                toastIcon.className = 'mr-3 text-xl text-yellow-500';
                toastIcon.innerHTML = '<i class="fa fa-exclamation-triangle"></i>';
                toast.classList.add('border-l-4', 'border-yellow-500');
            }
            
            // 设置消息
            toastMessage.textContent = message;
            
            // 显示提示
            toast.classList.remove('translate-x-full');
            
            // 3秒后隐藏
            setTimeout(() => {
                toast.classList.add('translate-x-full');
                
                // 重置样式
                setTimeout(() => {
                    toast.classList.remove('border-l-4', 'border-green-500', 'border-red-500', 'border-yellow-500');
                }, 300);
            }, 3000);
        }
    </script>
</body>
</html>
        
编辑器加载中
预览
控制台