1// ========================================================= 2// ð¨ ã«ã¬ã³ãã¼UI å ±éæç»ã¢ã¸ã¥ã¼ã« (calendar_view.js) 3// ========================================================= 4 5const CalendarView = { 6 /** 7 * ã«ã¬ã³ãã¼ã®HTMLæååãæ§ç¯ãã¦è¿ã 8 * @param {string} shopName - åºèå 9 * @param {string} startDateStr - ã«ã¬ã³ãã¼ã®éå§æ¥ (YYYY-MM-DD) 10 * @param {string} shopTel - ã«ã¬ã³ãã¼ã®éå§æ¥ (YYYY-MM-DD) 11 * @param {Object} calendarData - APIããåå¾ãã dates, times, grid ãå«ããªãã¸ã§ã¯ã 12 * @param {boolean} isMember - ä¼å¡ã¢ã¼ããã©ããã®ãã©ã°ï¼è¦åæãªã©ã®åºãåãç¨ï¼ 13 * @returns {string} - çæãããHTMLæåå 14 */ 15 buildHTML: function (shopName, startDateStr, calendarData, isMember = false, shopTel = '') { 16 // ð ã¹ã±ã¸ã¥ã¼ã«ãåå¨ããªãæ(60æ¥ä»¥ä¸å ã®ãã¼ã¿ãªã©) 17 if (!calendarData || !calendarData.dates || calendarData.dates.length === 0) { 18 const startDate = new Date(startDateStr + 'T00:00:00'); 19 const prevDate = new Date(startDate); 20 prevDate.setDate(prevDate.getDate() - 7); 21 22 const formatDate = (d) => { 23 const y = d.getFullYear(); 24 const m = String(d.getMonth() + 1).padStart(2, '0'); 25 const day = String(d.getDate()).padStart(2, '0'); 26 return `${y}-${m}-${day}`; 27 }; 28 29 const navHtml = ` 30 <div class="calendar-nav-wrap" style="display: flex; justify-content: space-between; margin: 15px 0;"> 31 <button type="button" class="btn-nav prev" data-date="${formatDate(prevDate)}">â åã®é±</button> 32 <div></div> 33 </div> 34 `; 35 36 // ð ã¡ãã»ã¼ã¸ã®åºæ¬å½¢ 37 let emptyMsgHtml = ` 38 <p style="font-weight: bold; color: #e43a6e; margin-bottom: 10px; font-size: 1.1rem;">â æå®æ¥ä»¥éã®ã¹ã±ã¸ã¥ã¼ã«ã¯ç¢ºå®ãã¦ãã¾ããã</p> 39 <p style="font-size: 0.95rem; color: #555;">æ¥ä»ã夿´ãã¦ã«ã¬ã³ãã¼ãæ´æ°ãããããããã°ãããå¾ ã¡ãã ããã</p> 40 `; 41 42 // ð ã¡ã³ãã¼(isMember)ãªããé»è©±çªå·å ¥ãã®è¿½å ã¡ãã»ã¼ã¸ããã£ã¤ããï¼ 43 if (isMember) { 44 emptyMsgHtml += ` 45 <p style="font-size: 0.95rem; color: #555; margin-top: 15px; font-weight: bold;"> 46 â ç¾å¨ãã61æ¥ä»¥ä¸å ã®æ¥ä»ã®ãäºç´ã¯ãé»è©±ãã¨ããã«ã¯ãªããã¯ãåãåãããLINEã§ãç¸è«ãã ããã<br> 47 ${shopName} <a href="tel:${shopTel}" style="text-decoration:underline; color:#D21577;">${shopTel}</a><br> 48 <a href="https://eminal-clinic.jp/contact/" target="_blank" style="text-decoration:underline; color:#D21577;">ã¨ããã«ã¯ãªããã¯ãåãåãã</a> 49 </p> 50 `; 51 } 52 53 return ` 54 <div id="calendar-top-anchor" class="calendar-shop-header"> 55 <div class="shop-name">${shopName}</div> 56 </div> 57 ${navHtml} 58 <div style="text-align: center; padding: 3rem 1rem; background: #fffafb; border: 1px solid #e43a6e; border-radius: 8px; margin: 2rem 0; line-height: 1.6;"> 59 ${emptyMsgHtml} 60 </div> 61 ${navHtml} 62 `; 63 } 64 65 const { dates, times, grid } = calendarData; 66 const startDate = new Date(startDateStr + 'T00:00:00'); 67 const today = new Date(); 68 today.setHours(0, 0, 0, 0); 69 70 const formatDate = (d) => { 71 const y = d.getFullYear(); 72 const m = String(d.getMonth() + 1).padStart(2, '0'); 73 const day = String(d.getDate()).padStart(2, '0'); 74 return `${y}-${m}-${day}`; 75 }; 76 77 const prevDate = new Date(startDate); 78 prevDate.setDate(prevDate.getDate() - 7); 79 const nextDate = new Date(startDate); 80 nextDate.setDate(nextDate.getDate() + 7); 81 82 const isPrevDisabled = startDate <= today; 83 84 const dispYear = startDate.getFullYear(); 85 const dispMonth = String(startDate.getMonth() + 1).padStart(2, '0'); 86 const dispDay = String(startDate.getDate()).padStart(2, '0'); 87 const rangeText = `${dispYear}å¹´${dispMonth}æ${dispDay}æ¥ãã7æ¥é`; 88 89 const navHtml = ` 90 <div class="calendar-nav-wrap" style="display: flex; justify-content: space-between; margin: 15px 0;"> 91 ${!isPrevDisabled ? `<button type="button" class="btn-nav prev" data-date="${formatDate(prevDate)}">â åã®é±</button>` : '<div></div>'} 92 <button type="button" class="btn-nav next" data-date="${formatDate(nextDate)}">次ã®é± â·</button> 93 </div> 94 `; 95 96 let html = ` 97 <div id="calendar-top-anchor" class="calendar-shop-header"> 98 <div class="shop-name">${shopName}</div> 99 <div class="date-range">${rangeText}</div> 100 </div> 101 ${navHtml} 102 <div class="table-responsive"> 103 <table class="timetable"> 104 <thead> 105 `; 106 107 // æã®ãããã¼çæ 108 let monthCounts = [];
109 let curMonth = ''; 110 let curCount = 0; 111 dates.forEach(dStr => { 112 const m = parseInt(dStr.substring(4, 6), 10) + "æ"; 113 if (m !== curMonth) { 114 if (curMonth !== '') monthCounts.push({ month: curMonth, count: curCount }); 115 curMonth = m; 116 curCount = 1; 117 } else { 118 curCount++; 119 } 120 }); 121 monthCounts.push({ month: curMonth, count: curCount }); 122 123 html += `<tr>`; 124 monthCounts.forEach(mc => { 125 html += `<th colspan="${mc.count}" class="month-row">${mc.month}</th>`; 126 }); 127 html += `</tr><tr>`; 128 129 // æ¥ä»ã¨ææ¥ã®ãããã¼çæ 130 const weekNames = ['æ¥', 'æ', 'ç«', 'æ°´', 'æ¨', 'é', 'å']; 131 const formatDates = []; 132 dates.forEach((dStr) => { 133 const y = dStr.substring(0, 4); 134 const m = dStr.substring(4, 6); 135 const d = dStr.substring(6, 8); 136 const fDate = `${y}-${m}-${d}`; 137 formatDates.push(fDate); 138 139 const dateObj = new Date(`${fDate}T00:00:00`); 140 const wNum = dateObj.getDay(); 141 let thClass = wNum === 0 ? 'sun' : (wNum === 6 ? 'sat' : ''); 142 html += `<th class="day-row ${thClass}">${parseInt(d, 10)}<br><span class="week">(${weekNames[wNum]})</span></th>`; 143 }); 144 html += `</tr></thead><tbody>`; 145 146 // ã¿ã¤ã ãã¼ãã«ï¼è¡ï¼ã®çæ 147 times.forEach(t => { 148 const timeLabel = t.substring(0, 2) + ':' + t.substring(2, 4); 149 html += `<tr>`; 150 dates.forEach((dStr, index) => { 151 const cell = grid[t][dStr]; 152 const fDate = formatDates[index]; 153 if (!cell || cell.type === 'span') return; 154 155 if (cell.type === 'ok') { 156 html += `<td rowspan="${cell.rowspan}" class="cell-ok"> 157 <button type="button" class="btn-slot ok" data-date="${fDate}" data-time="${timeLabel}"> 158 <span class="time-text">${timeLabel}</span><br><span class="mark">â</span> 159 </button> 160 </td>`; 161 } else { 162 html += `<td class="cell-ng"></td>`; 163 } 164 }); 165 html += `</tr>`; 166 }); 167 168 html += `</tbody></table></div>`; 169 html += navHtml; 170 171 // ð¡ ä¼å¡åãã®ç¹è¨äºé ã追å å¯è½ 172 if (isMember) { 173 html += ` 174 <div style="margin-top: 2rem; font-size: 0.85rem; color: #666; text-align: center;"> 175 <p>â»ãå¸æã®æ¥æï¼âï¼ãã¿ãããã¦ãã ããã</p> 176 </div> 177 `; 178 } 179 180 return html; 181 } 182};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.