ken_nogi/pleasanter/develop/#リフォームラボ/■イオン多摩平シフト希望/sites/scripts/2.カレンダー表示.js
Kenichiro NOGI 7176dc33ec pleasanter
2025-07-10 10:15:35 +09:00

289 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
@config : next999.json
@filename : ${psFileBasename}
@title : 2.カレンダー表示
@name : 2.カレンダー表示
@siteIds : 310514
@siteTitles : イオン多摩平シフト希望
@disabled: false
*/
//カレンダーを生成して挿入する関数
function renderCalendar(year, month, checkedDates = [], selectedHoursArray = []) {
$('#custom-calendar-container').remove();
let containerHtml = `<div id="custom-calendar-container">`; // メインコンテナ
let calendarAndControlsFlexContainer = `<div id="custom-calendar">`; // カレンダーと操作ボタンのFlexコンテナ
// カレンダー本体
let calendarTableHtml = `<div><table border="1"><thead><tr>
<th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th>
</tr></thead><tbody><tr>`;
let firstDay = new Date(year, month - 1, 1);
let lastDay = new Date(year, month, 0);
for (let i = 0; i < firstDay.getDay(); i++) calendarTableHtml += "<td></td>";
for (let d = 1; d <= lastDay.getDate(); d++) {
let dateObj = new Date(year, month - 1, d);
let dayOfWeek = dateObj.getDay();
let dateStr = `${year}-${String(month).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
let checked = checkedDates.includes(dateStr) ? 'checked' : '';
calendarTableHtml += `<td><label><input type="checkbox" class="calendar-checkbox" value="${dateStr}" data-day="${dayOfWeek}" ${checked}><br>${d}</label></td>`;
if ((firstDay.getDay() + d) % 7 === 0 && d !== lastDay.getDate()) calendarTableHtml += "</tr><tr>";
}
let lastDayOfWeek = new Date(year, month - 1, lastDay.getDate()).getDay();
for (let i = lastDayOfWeek + 1; i <= 6; i++) calendarTableHtml += "<td></td>";
calendarTableHtml += "</tr></tbody></table></div>"; // カレンダーテーブルの閉じタグ
calendarAndControlsFlexContainer += calendarTableHtml;
// 操作コントロール(ボタンとタイムバー)のコンテナ
let controlsContainerHtml = `<div class="controls-container">`;
// 一括操作ボタン
controlsContainerHtml += `
<div>
<button type="button" id="calendar-check-all">全てチェック</button>
<button type="button" id="calendar-uncheck-all">全て解除</button>
</div>`;
// 曜日ボタン
controlsContainerHtml += `<div class="day-toggle-buttons">
<button type="button" class="calendar-day-toggle" data-day="1">月</button>
<button type="button" class="calendar-day-toggle" data-day="2">火</button>
<button type="button" class="calendar-day-toggle" data-day="3">水</button>
<button type="button" class="calendar-day-toggle" data-day="4">木</button>
<button type="button" class="calendar-day-toggle" data-day="5">金</button>
<button type="button" class="calendar-day-toggle" data-day="6">土</button>
<button type="button" class="calendar-day-toggle" data-day="0">日</button>
</div>`;
// 時間選択バー
controlsContainerHtml += `
<div id="time-selector-container">
<label>希望時間帯 (10時21時) - 開始と終了時間を選択:</label>
<div id="time-bar">`;
for (let hour = 10; hour <= 21; hour++) {
controlsContainerHtml += `<div class="time-slot" data-hour="${hour}" style="color: darkblue;">${hour}</div>`;
}
controlsContainerHtml += `</div>
<p>選択された時間: <span id="selected-hours-display">なし</span></p>
</div>
`;
controlsContainerHtml += `</div>`; // controls-container の閉じタグ
calendarAndControlsFlexContainer += controlsContainerHtml;
calendarAndControlsFlexContainer += `</div>`; // custom-calendar (Flexコンテナ) の閉じタグ
containerHtml += calendarAndControlsFlexContainer;
containerHtml += "</div>"; // custom-calendar-container の閉じタグ
$('#SectionFields1Container').after(containerHtml);
// ボタンイベント (変更なし)
$('#calendar-check-all').off('click').on('click', function () {
$('#custom-calendar .calendar-checkbox').prop('checked', true);
});
$('#calendar-uncheck-all').off('click').on('click', function () {
$('#custom-calendar .calendar-checkbox').prop('checked', false);
});
let dayToggleState = { 0: false, 1: false, 2: false, 3: false, 4: false, 5: false, 6: false };
$('.calendar-day-toggle').off('click').on('click', function () {
const day = $(this).data('day');
dayToggleState[day] = !dayToggleState[day];
$('#custom-calendar .calendar-checkbox[data-day="' + day + '"]').prop('checked', dayToggleState[day]);
if (dayToggleState[day]) {
$(this).css('background', '#0078d7').css('color', '#fff');
} else {
$(this).css('background', '').css('color', '');
}
});
// 時間選択バーのロジック (変更なし)
const timeSlots = $('.time-slot');
const selectedHoursDisplay = $('#selected-hours-display');
let isDragging = false;
let selectionStartHour = -1;
let selectionEndHour = -1;
if (selectedHoursArray && selectedHoursArray.length > 0) {
if (selectedHoursArray.length >= 1) {
selectionStartHour = Math.min(...selectedHoursArray);
selectionEndHour = Math.max(...selectedHoursArray);
updateSelectionVisuals();
if (selectedHoursArray.length >= 2) {
selectedHoursDisplay.text(selectedHoursArray.sort((a, b) => a - b).join(','));
} else {
selectedHoursDisplay.text('最低2時間選択してください');
}
}
}
timeSlots.on('mousedown touchstart', function (e) { // touchstart を追加
e.preventDefault();
isDragging = true;
const currentHour = parseInt($(this).data('hour'));
selectionStartHour = currentHour;
selectionEndHour = currentHour;
updateSelectionVisuals();
});
timeSlots.on('mousemove touchmove', function (e) { // touchmove を追加
if (isDragging) {
let pageX;
if (e.type === 'touchmove') {
pageX = e.originalEvent.touches[0].pageX;
} else {
pageX = e.pageX;
}
// マウス/タッチ位置から最も近いスロットを見つける
let closestSlot = null;
let minDistance = Infinity;
timeSlots.each(function () {
const slot = $(this);
const slotCenterX = slot.offset().left + slot.width() / 2;
const distance = Math.abs(pageX - slotCenterX);
if (distance < minDistance) {
minDistance = distance;
closestSlot = slot;
}
});
if (closestSlot) {
const currentHour = parseInt(closestSlot.data('hour'));
selectionEndHour = currentHour;
updateSelectionVisuals();
}
}
});
$(document).on('mouseup touchend', function () { // touchend を追加
if (isDragging) {
isDragging = false;
const start = Math.min(selectionStartHour, selectionEndHour);
const end = Math.max(selectionStartHour, selectionEndHour);
const selectedCount = (start !== -1 && end !== -1) ? (end - start + 1) : 0;
if (selectedCount < 2 && selectedCount > 0) {
$p.ex.setMyMessage('alert-error new-status-red', '開始時間と終了時間を選択してください');
timeSlots.css('background-color', '');
selectedHoursDisplay.text('なし');
$p.set($('#Results_ClassD'), JSON.stringify([]));
selectionStartHour = -1;
selectionEndHour = -1;
} else if (selectedCount >= 2) {
$p.clearMessage();
saveSelectedHoursToField();
} else {
$p.clearMessage();
timeSlots.css('background-color', '');
selectedHoursDisplay.text('なし');
$p.set($('#Results_ClassD'), JSON.stringify([]));
selectionStartHour = -1;
selectionEndHour = -1;
}
}
});
function updateSelectionVisuals() {
timeSlots.css('background-color', '');
const start = Math.min(selectionStartHour, selectionEndHour);
const end = Math.max(selectionStartHour, selectionEndHour);
if (start !== -1 && end !== -1) {
for (let i = start; i <= end; i++) {
$(`.time-slot[data-hour="${i}"]`).css('background-color', '#a0c4ff');
}
}
}
function saveSelectedHoursToField() {
const selected = [];
if (selectionStartHour !== -1 && selectionEndHour !== -1) {
const start = Math.min(selectionStartHour, selectionEndHour);
const end = Math.max(selectionStartHour, selectionEndHour);
if ((end - start + 1) >= 2) {
for (let i = start; i <= end; i++) {
selected.push(i.toString());
}
selectedHoursDisplay.text(selected.join(',') || 'なし');
$p.set($('#Results_ClassD'), JSON.stringify(selected));
console.log('Selected hours saved to Results_ClassD:', JSON.stringify(selected));
} else {
selectedHoursDisplay.text('開始時間と終了時間を選択してください');
$p.set($('#Results_ClassD'), JSON.stringify([]));
console.log('Selection less than 2 hours, not saved.');
}
} else {
selectedHoursDisplay.text('なし');
$p.set($('#Results_ClassD'), JSON.stringify([]));
}
}
}
//チェックされた日付を取得する関数 (変更なし)
function getCheckedDates() {
return $('.calendar-checkbox:checked').map(function () {
return this.value;
}).get();
}
//選択された時間を取得する関数 (Results_ClassDから読み込む)
function getSelectedHours() {
const classD = $('#Results_ClassD').val();
let hoursArray = [];
if (classD[0] === 'いつでも') {
hoursArray = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21];
} else {
for (let i = 0; i < classD.length; i++) {
hoursArray.push(parseFloat(classD[i]));
}
}
return hoursArray;
}
/*
console.log(hoursString);
if (hoursString) {
try {
const parsedHours = JSON.parse(hoursString);
if (Array.isArray(parsedHours) && parsedHours.every(h => typeof h === 'number')) {
return parsedHours;
}
} catch (e) {
console.error("Error parsing selected hours from Results_ClassD:", e);
if (typeof hoursString === 'string' && hoursString.includes(',')) {
return hoursString.split(',').map(h => parseInt(h.trim(), 10)).filter(h => !isNaN(h));
}
}
}
return [];
}
*/
//年月選択UIとイベント (変更なし)
function setupCalendarUI(initialYear, initialMonth, checkedDates = [], initialSelectedHoursArray = []) {
renderCalendar(initialYear, initialMonth, checkedDates, initialSelectedHoursArray);
$p.on('change', 'ClassA', function () {
let y = parseFloat($('#Results_ClassA').val().split('年')[0]);
let m = parseFloat($('#Results_ClassA').val().split('年')[1].split('月')[0]);
renderCalendar(y, m, getCheckedDates(), getSelectedHours());
});
}
function setupCalendar() {
let initialYear = parseFloat($('#Results_ClassA').val().split('年')[0]);
let initialMonth = parseFloat($('#Results_ClassA').val().split('年')[1].split('月')[0]);
let initialCheckedDates = $('#Results_ClassW').val() ? JSON.parse($('#Results_ClassW').val()) : [];
let initialSelectedHoursArray = getSelectedHours();
setupCalendarUI(initialYear, initialMonth, initialCheckedDates, initialSelectedHoursArray);
}