在开发医生排班系统的过程中,我遭遇了一系列棘手的问题,这些问题主要集中在多重循环渲染、数据处理以及弹窗和月份切换的控制上。通过对这些问题的梳理与总结,希望能为后续的开发优化以及遇到类似问题的开发者提供一些参考。
多重循环渲染问题
问题描述
在页面渲染环节,尤其是涉及到展示医生排班信息时,需要对医生数据、日期数据以及每个日期下的具体排班数据进行多层遍历。例如,在render
函数中,首先要遍历医生数组来展示每个医生的基本信息,接着对于每个医生,又要遍历当前月份的每一天来展示对应的排班情况,在renderAgain
函数中,还需进一步遍历每一天中具体的排班时段数据。这种多层嵌套的循环结构虽然能够实现数据的准确展示,但带来了性能和代码可读性方面的挑战。
function render() {
let str = '';
let days = getDaysInMonths();
for (let i = page * pageSize; i < doctors.length && i < page * pageSize + pageSize; i++) {
// 添加医生信息
str += `<div class="nav_status">
<div class="child_long">${doctors[i].name}</div>
<div class="child_long">${doctors[i].office}</div></div>`;
// 处理每一天
for (let d = 1; d <= days; d++) {
if (data[d] == undefined) {
continue;
}
renderAgain(d);
}
}
$("#body_status").html(str)
$(".notice_scroll").html(scroll_str);
page_paging(data);
}
function renderAgain(d) {
for (let j = 0; j < data[d].date.length; j++) {
let day_ser = j + 1;
// 拼接日期、上午、下午
scroll_str += `
<div class="scroll_item">
<div class="specific_time">${data[d].date[j]}</div>
<div class="am_pm" style="background-color: rgb(245, 247, 250)">
<div class="am_title">上午</div>
<div class="pm_title">下午</div>
</div>`;
let emptySlots = '';
for (let k = page * pageSize; k < data.length && k < page * pageSize + pageSize; k++) {
let am_source = data[k].shang[day_ser - 1].source? '号源:' + data[k].shang[day_ser - 1].source : '无';
let pm_source = data[k].xia[day_ser - 1].source? '号源:' + data[k].xia[day_ser - 1].source : '无';
emptySlots += `<div class="am_pm_child">`;
emptySlots += `<div class="am_title">${am_source}</div>
<div class="pm_title">${pm_source}</div>`;
emptySlots += `</div>`;
}
scroll_str += emptySlots;
scroll_str += `</div></div>`;
}
}
问题分析
在上述代码中,render
函数中嵌套了两层循环,外层循环遍历医生,内层循环遍历日期。而renderAgain
函数又包含了多层循环,用于处理每一天中的具体排班时段。这样的结构导致代码逻辑复杂,难以维护和调试。并且,过多的循环操作可能会在数据量较大时影响页面渲染性能,导致页面卡顿。
解决思路
- 优化数据结构:在数据获取阶段,对从服务器获取的数据进行预处理,将数据整理成更易于遍历和渲染的结构。例如,可以将医生信息和其对应的排班信息进行整合,减少在渲染过程中的多层查找和遍历。
- 使用更高效的算法:考虑使用一些数据处理算法,如哈希表,来优化数据查找的效率。在渲染过程中,通过哈希表快速定位到需要的数据,减少不必要的循环操作。
- 代码拆分与模块化:将复杂的渲染逻辑拆分成多个独立的函数,每个函数专注于处理某一层的数据遍历和渲染,提高代码的可读性和可维护性。
数据处理不当问题
问题描述
在数据处理过程中,存在数据格式不一致、数据验证不严谨以及数据更新后页面同步不及时等问题。例如,在保存排班数据时,需要对用户输入的时间、号源等信息进行验证,但当前的验证逻辑不够完善,容易导致非法数据提交到服务器。另外,当服务器返回新的排班数据时,页面有时未能及时更新显示最新信息。
function save() {
isValid = true;
if (switch_am_time == 1 && switch_pm_time == 1) {
showPopup('请至少选择一个时间段', '#f44336', '#ffebee', '#f44336');
return;
}
if (switch_am_time == 2) {
const amStart = $('#am_start').val();
const amEnd = $('#am_end').val();
if (amStart == '') {
showPopup('请选择上午开始时间', '#f44336', '#ffebee', '#f44336');
return;
}
if (amEnd == '') {
showPopup('请选择上午结束时间', '#f44336', '#ffebee', '#f44336');
return;
}
if (amStart === amEnd) {
showPopup('上午开始时间和结束时间不能一样', '#f44336', '#ffebee', '#f44336');
return;
}
const startMinutes = convertTimeToMinutes(amStart);
const endMinutes = convertTimeToMinutes(amEnd);
if (startMinutes < 360) {
showPopup('上午开始时间不得早于 6 点', '#f44336', '#ffebee', '#f44336');
return;
}
if (endMinutes > 720) {
showPopup('上午结束时间不得晚于 12 点', '#f44336', '#ffebee', '#f44336');
return;
}
if ($('#am_source').val() == '') {
showPopup('请填写上午号源', '#f44336', '#ffebee', '#f44336');
return;
}
}
// 下午时间和号源的验证逻辑类似
if (switch_am_time == 2) {
total_data.push({
date: $('.part_text').html(),
time_slot: $('#am_start').val().replace(/:\d{2}$/, '') + '-' + $('#am_end').val().replace(/:\d{2}$/, ''),
depart_id: department_id,
doctor_id: editId,
time: 1,
status: 1,
num: 0,
source: $('#am_source').val(),
month: new Date().getMonth() + 1,
})
}
if (switch_pm_time == 2) {
total_data.push({
date: $('.part_text').html(),
time_slot: $('#pm_start').val().replace(/:\d{2}$/, '') + '-' + $('#pm_end').val().replace(/:\d{2}$/, ''),
time: 2,
source: $('#pm_source').val(),
month: new Date().getMonth() + 1,
status: 1,
num: 0,
doctor_id: editId,
depart_id: department_id,
})
}
$.ajax({
type: "post",
url: url + ``,
headers: {
token: token,
id: uid
},
data: {
doctor_id: editId,
arr: JSON.stringify(total_data)
},
success: function (results) {
if (results.code == 1) {
$('.delete_back').hide();
showPopup('添加成功', '#4caf50', '#e8f5e9', '#4caf50');
getDaysInMonth();
switch_am($('#switchs')[0]);
switch_pm($('#switch')[0]);
hide();
} else if (results.code == 2) {
showPopup(results.msg, '#f44336', '#ffebee', '#f44336');
}
},
});
}
问题分析
在save
函数中,虽然对用户输入的时间和号源进行了部分验证,但验证逻辑较为分散,且对于一些边界情况的处理不够全面。例如,时间格式的验证仅通过简单的字符串比较,未考虑到时间格式错误的情况。在数据更新方面,当服务器返回成功响应后,虽然调用了getDaysInMonth
函数重新获取数据,但在某些情况下,页面可能并未正确更新,这可能是由于数据更新与页面渲染之间的同步机制存在问题。
解决思路
- 完善数据验证:采用更严格的数据验证方法,例如使用正则表达式验证时间格式,确保输入的数据符合预期格式。同时,将验证逻辑进行整合,提高代码的可维护性。
- 优化数据更新机制:在数据更新时,确保页面渲染函数能够准确地获取最新的数据并进行更新。可以在数据更新后,触发特定的事件来通知页面进行重新渲染,或者在渲染函数中增加对数据变化的检测机制。
多层弹窗下数据渲染显示和月份切换问题
问题描述
在系统中存在多层弹窗,当用户在弹窗中进行操作时,有时会出现数据重复渲染或者不必要的渲染情况。例如,在编辑医生排班的弹窗中,切换月份时,弹窗内的数据可能会出现异常渲染,显示的数据与所选月份不匹配。另外,在多层弹窗嵌套的情况下,如何禁止某些弹窗内的数据渲染,以提高系统性能和用户体验,也是一个难题。
function redact(id) {
editId = id;
$('.examine').show();
let date_time = ``;
let getdate = getDatesInMonth(new Date().getFullYear(), new Date().getMonth() + 1);
for (let h = 0; h < getdate.length; h++) {
$(".work_time").html(getdate[h]);
}
$("#nowDay").trigger("click");
for (let i = 0; i < data.length; i++) {
if (data[i].id == id) {
department_id = data[i].depart_id;
sessionStorage.setItem('SourceId', data[i].id);
for (let j = 0; j < data[i].date.length; j++) {
let shangData = data[i].shang[j];
let date = new Date(data[i].date[j]);
let day = date.getDate();
let formattedDate = `${day}`;
$('#person').html(data[i].name);
let shang = data[i].shang[j];
let weekDay = getWeekDay(data[i].date[j]);
$('.week').html(weekDay);
let sourceText = shangData.source === undefined? '无号源' : '号源: ' + shangData.source;
let sourceClass = shangData.source === undefined? 'no-source' : 'has-source';
date_time += `
<div class="plan_box" data-day="${day}">
<span>${formattedDate}</span><br>
<span class="${sourceClass}">${sourceText}</span>
</div>`;
}
$('.date_box').html(date_time);
details_id = id;
}
}
}
$('#monthSelect').on('change', function () {
let selectedMonth = parseInt(this.value);
let currentDate = new Date();
let currentYear = currentDate.getFullYear();
let currentMonth = currentDate.getMonth() + 1;
if (currentYear === new Date().getFullYear() && selectedMonth < currentMonth) {
$(this).val($(this).data('lastValue'));
} else {
$(this).data('lastValue', selectedMonth);
if (selectedMonth) {
calendar(selectedMonth);
}
}
});
问题分析
在redact
函数中,当打开编辑弹窗时,会根据当前月份渲染相关数据。但在月份切换时,由于没有对已渲染的数据进行有效的清理和重新加载控制,导致数据显示异常。在$('#monthSelect').on('change'
事件中,虽然实现了月份切换功能,但对于多层弹窗下的特殊情况考虑不足,没有处理好如何禁止某些弹窗内数据的不必要渲染。
解决思路
- 数据清理与缓存:在打开弹窗或切换月份时,首先清理弹窗内已有的数据,避免数据残留导致的显示异常。同时,可以考虑使用数据缓存机制,在切换月份时,如果数据未发生变化,则直接从缓存中读取数据,减少不必要的渲染。
- 事件委托与控制:通过事件委托机制,在父元素上统一监听与弹窗和月份切换相关的事件,根据当前弹窗的状态和用户操作,精确控制哪些数据需要渲染,哪些需要禁止渲染。例如,在多层弹窗中,可以设置标志位,当处于特定弹窗层级时,禁止某些数据渲染函数的执行。
通过对这些问题的总结,我深刻认识到在开发医生排班系统过程中,需要更加严谨地处理数据,优化渲染逻辑,以及精细控制页面交互。这些问题的解决将有助于提升系统的性能、稳定性和用户体验,为后续的开发工作积累宝贵经验。