You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Datepicker选择未被识别:无法触发可用预约时段下拉框填充

问题描述

我需要实现根据选中的医生与日期,在下拉框中填充该医生当日未被预约的时段,但当前存在以下问题:

  • 选择日期后,系统无法识别选中的日期,无法触发对应的AJAX请求;
  • 仅当先选择医生、再选日期,随后切换其他医生并切回原医生时,下拉框才会正确填充可用时段。

怀疑问题出在为限制医生可用日期而销毁重建datepicker的逻辑上。


相关代码

前端AJAX触发代码

<script>
    $(document).ready(function(){
        $('#datepicker').datepicker({
            onSelect: function() {
                setTimeout(triggerAjaxCall, 0);
            }
        });

        $('#selMedico').change(function(){
            triggerAjaxCall();
        });

        function triggerAjaxCall() {
            var doctor = $('#selMedico').val();
            var date = $('#datepicker').val();

            console.log('Doctor:', doctor);
            console.log('Date:', date); 

            if (!doctor || !date) {
                console.log('Doctor or date not selected');
                return;
            }

            // AJAX call
            $.ajax({
                type: 'POST',
                url: 'fetchConsultas.php',
                data: { medico: doctor, dia: date },
                dataType: 'json',
                success: function(response) {
                    console.log('AJAX request successful');
                    console.log('Response:', response);  

                    $('#hora').empty();
                    $.each(response, function(index, value) {
                        $('#hora').append('<option value="' + value + '">' + value + '</option>');
                    });
                },
                error: function(jqXHR, textStatus, errorThrown) {
                    console.log('AJAX request failed:', textStatus, errorThrown);  
                }
            });
        }
    });
</script>

后端fetchConsultas.php代码

<?php
if (isset($_POST['medico']) && isset($_POST['dia'])) {

    $medicoSelecionado = $_POST['medico'];
    $dataSelecionada = $_POST['dia'];

    include 'connection.php';

    $stmt = $pdo->prepare('SELECT id_hora 
                            FROM tabconsultas 
                            WHERE id_medico = ? 
                            AND id_dia = ? ;');
    
    $stmt->execute([$medicoSelecionado, $dataSelecionada]);

    $horarios = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);

    // 生成8:00-18:00的所有时段(排除13:00)
    $allHours = [];
    for ($i = 8; $i <= 18; $i++) {
        if ($i != 13) {
            $hour = str_pad($i, 2, '0', STR_PAD_LEFT) . ':00:00';
            $allHours[] = $hour;
        }
    }

    // 计算未被预约的时段
    $availableHours = array_diff($allHours, $horarios);

    echo json_encode($availableHours);

    $pdo = null;
    $stmt = null;
} else {
    echo "No doctor or date selected.";
}
die();

医生选择HTML代码

<?php
$consulta = "SELECT DISTINCT tabutilizador.id_utilizador, tabutilizador.nome  
                FROM tabutilizador
                LEFT JOIN tabconsultas ON tabutilizador.id_utilizador = tabconsultas.id_medico 
                WHERE tabutilizador.tipo = 'medico'";

$resultado = $conexao->query($consulta);
// 渲染医生下拉列表
echo '<form id="formulario" action="formhandler.inc.php" method="POST">';
echo '<label for="medico">Médico</label><br><br>';
echo '<select id="selMedico" name="medico" onchange="fetchServicosPorMedico(this.value)" required>';
echo '<option value="" disabled selected>Escolha um Médico</option>';
while ($linha = $resultado->fetch_assoc()) {
    echo '<option value="' . $linha['id_utilizador'] . '">' . $linha['nome'] . '</option>';
}
echo '</select><br><br>';
?>

日期输入HTML代码

<?php
echo '<label for="dia">Data da Consulta</label><br><br>';
echo '<input type="text" id="datepicker" name="dia" placeholder="Selecione uma data" required><br><br>';
?>

重建datepicker的JS代码

<script>
$(document).ready(function() {
    $('#selMedico').change(function() {
        var medicoSelecionado = $(this).val();
        $.ajax({
            url: 'fetchDiasPorMedico.php',
            type: 'post',
            data: {
                medico: medicoSelecionado
            },
            success: function(response) {
                $('#resultado').html(response);
                var diasDisp = response;
                $(function() {
                    $("#datepicker").datepicker("destroy").datepicker({
                        dateFormat: 'yy-mm-dd',
                        dayNames: ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'],
                        dayNamesMin: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
                        dayNamesShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
                        monthNames: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
                        monthNamesShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
                        nextText: 'Próximo',
                        prevText: 'Anterior',
                        beforeShowDay: function(date) {
                            var day = date.getDay();
                            // 根据返回逻辑判断日期是否可用
                            var disableDay = new Function('day', 'return ' + diasDisp);
                            return [disableDay(day), ''];
                        },
                        onSelect: function(dateText, inst) {
                            var selectedDate = $(this).datepicker('getDate');
                            var dayOfWeek = selectedDate.getDay();
                        },
                        minDate: 0
                    });
                });
            }
        });
    });
});
</script>

问题根源

问题出在两次初始化datepicker的事件冲突:

  1. 第一次初始化时,给datepicker绑定了onSelect事件,用于触发triggerAjaxCall;
  2. 选择医生时,代码会销毁原datepicker并重新创建,新datepicker的onSelect被替换成了仅获取星期几的逻辑,完全丢失了触发AJAX的代码;
  3. 切换医生再切回时,医生的change事件会触发triggerAjaxCall,此时如果已有日期选择,才会填充时段。

解决方案

修改重建datepicker的代码,在新的onSelect事件中调用triggerAjaxCall,同时统一函数作用域,避免事件丢失:

修改后的完整JS代码

<script>
$(document).ready(function() {
    // 全局作用域定义triggerAjaxCall,确保重建datepicker时能访问
    function triggerAjaxCall() {
        var doctor = $('#selMedico').val();
        var date = $('#datepicker').val();

        console.log('Doctor:', doctor);
        console.log('Date:', date); 

        if (!doctor || !date) {
            console.log('Doctor or date not selected');
            return;
        }

        // AJAX请求获取可用时段
        $.ajax({
            type: 'POST',
            url: 'fetchConsultas.php',
            data: { medico: doctor, dia: date },
            dataType: 'json',
            success: function(response) {
                console.log('AJAX request successful');
                console.log('Response:', response);  

                $('#hora').empty();
                $.each(response, function(index, value) {
                    $('#hora').append('<option value="' + value + '">' + value + '</option>');
                });
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log('AJAX request failed:', textStatus, errorThrown);  
            }
        });
    }

    // 医生选择事件处理
    $('#selMedico').change(function(){
        var medicoSelecionado = $(this).val();
        
        // 先触发一次AJAX(如果已有日期选择)
        triggerAjaxCall();

        // 请求医生可用日期并重建datepicker
        $.ajax({
            url: 'fetchDiasPorMedico.php',
            type: 'post',
            data: {
                medico: medicoSelecionado
            },
            success: function(response) {
                $('#resultado').html(response);
                var diasDisp = response;
                
                $("#datepicker").datepicker("destroy").datepicker({
                    dateFormat: 'yy-mm-dd',
                    dayNames: ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'],
                    dayNamesMin: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
                    dayNamesShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
                    monthNames: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
                    monthNamesShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
                    nextText: 'Próximo',
                    prevText: 'Anterior',
                    beforeShowDay: function(date) {
                        var day = date.getDay();
                        var disableDay = new Function('day', 'return ' + diasDisp);
                        return [disableDay(day), ''];
                    },
                    // 关键:在新的onSelect中调用triggerAjaxCall
                    onSelect: function(dateText, inst) {
                        var selectedDate = $(this).datepicker('getDate');
                        var dayOfWeek = selectedDate.getDay();
                        triggerAjaxCall(); // 触发AJAX获取可用时段
                    },
                    minDate: 0
                });
            }
        });
    });

    // 页面加载时,如果已有选中的医生,自动初始化datepicker
    var initialDoctor = $('#selMedico').val();
    if(initialDoctor){
        $('#selMedico').trigger('change');
    }
});
</script>

优化说明

  1. 移除了原有的单独datepicker初始化代码,避免重复初始化;
  2. 将triggerAjaxCall函数放到外层作用域,确保重建datepicker时能访问;
  3. 在医生切换事件中,先触发一次triggerAjaxCall,处理已有日期的情况;
  4. 初始加载时自动触发医生选择事件,避免手动选择两次。

内容的提问来源于stack exchange,提问作者José Filipe Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:38:11