眼科クリニックの予約状況を自動判定し、ホームページのバナーに表示するシステムです。
対応予約: 一般予約・視野予約の2種類の予約システムを独立して管理
reservation-status/
├── timeslot-status-checker.html # ⭐メイン: 予約状況チェッカー(スマホ/壁掛け2モード)
├── timeslot-banner.html # バナー: タイムスロット表示(iframe埋め込み用)
├── timeslot-display.html # 一般予約: 時間枠を抽出して表示
├── timeslot-display-shiya.html # 視野予約: 時間枠を抽出して表示
├── entrance-display.html # エントランスディスプレイ(入口用)
├── entrance-display-debug.html # エントランスディスプレイ(デバッグ版)
├── dashboard.html # 予約傾向ダッシュボード(分析・可視化)
├── chrome-extension-timeslot-general/ # Chrome拡張機能(一般予約枠数表示)
├── chrome-extension-timeslot-shiya/ # Chrome拡張機能(視野予約枠数表示)
├── chrome-extension-auto-reload/ # Chrome拡張機能(ディスプレイ自動リロード)
├── chrome-web-store/ # Chrome Web Store公開用ファイル
├── docker-timeslot-checker/ # 一般予約: タイムスロット抽出システム(Cloud Run)
├── docker-timeslot-checker-shiya/ # 視野予約: タイムスロット抽出システム(Cloud Run)
├── docs/ # ドキュメント
│ └── handover-to-claude-code.md # システム全体の引き継ぎ資料
└── Downloads/ # バナー用画像ファイル・設定ファイル
Cloud Runで自動実行(タイムスロット抽出)
<iframe
src="https://nekonekoganka.github.io/reservation-status/timeslot-banner.html"
width="100%"
height="280"
frameborder="0"
scrolling="no"
style="border:none;">
</iframe>
表示例:
19〜23時台の0〜30分に発生する日付判定問題を回避するため、該当時間帯はバナーを非表示にします。
<div id="reservation-banner-container">
<iframe
src="https://nekonekoganka.github.io/reservation-status/timeslot-banner.html"
width="100%"
height="280"
frameborder="0"
scrolling="no"
style="border:none;">
</iframe>
</div>
<script>
function checkAndHideBanner() {
var now = new Date();
var hour = now.getHours();
var minute = now.getMinutes();
var container = document.getElementById('reservation-banner-container');
// 19時〜23時台で、0分〜30分の間は非表示
if (hour >= 19 && hour <= 23 && minute >= 0 && minute <= 30) {
container.style.display = 'none';
} else {
container.style.display = 'block';
}
}
// ページ読み込み時と1分ごとにチェック
checkAndHideBanner();
setInterval(checkAndHideBanner, 60000);
</script>
Cloud Scheduler(定期実行)
↓
Cloud Run(Puppeteer)
↓ (時間枠抽出)
Cloud Storage(JSON)
↓
GitHub Pages(バナー・ディスプレイ・チェッカー)
const BUCKET_NAME = 'reservation-timeslots-fujiminohikari';
const FILE_NAME_GENERAL = 'timeslots.json';
const FILE_NAME_SHIYA = 'timeslots-shiya.json';
一般予約: https://ckreserve.com/clinic/fujiminohikari-ganka/fujimino
視野予約: https://ckreserve.com/clinic/fujiminohikari-ganka/fujiminohikari
| 種類 | サービス名 | URL |
|---|---|---|
| 一般予約 | timeslot-checker |
https://timeslot-checker-224924651996.asia-northeast1.run.app |
| 視野予約 | timeslot-checker-shiya |
https://timeslot-checker-shiya-224924651996.asia-northeast1.run.app |
| 種類 | ジョブ名 | 呼び出し先 |
|---|---|---|
| 一般予約 | reservation-timeslot-checker-job |
/check エンドポイント |
| 視野予約 | reservation-timeslot-checker-shiya-job |
/check エンドポイント |
注意: Schedulerのジョブ名とCloud Runのサービス名が異なるため、デプロイ後はSchedulerの向き先URLも確認が必要です。
# 一般予約
cd docker-timeslot-checker
gcloud run deploy timeslot-checker \
--source . \
--region asia-northeast1 \
--memory 1Gi
# 視野予約
cd docker-timeslot-checker-shiya
gcloud run deploy timeslot-checker-shiya \
--source . \
--region asia-northeast1 \
--memory 1Gi
デプロイ後の確認:
# 履歴ファイルが作成されているか確認
gsutil ls gs://reservation-timeslots-fujiminohikari/history/general/
gsutil ls gs://reservation-timeslots-fujiminohikari/history/shiya/
このリポジトリはClaude Codeでの開発を想定しています。
引き継ぎ資料: docs/handover-to-claude-code.md
このChrome拡張機能は、Chrome Web Storeに非公開公開する準備が完了しています。
概要:
entrance-display.html と dashboard.html のCloud Storage URLが古いバケット名を参照していた問題を修正しました。
修正内容:
| ファイル | 修正前 | 修正後 |
|—|—|—|
| entrance-display.html | fujimino-ophthalmology-reservations | reservation-timeslots-fujiminohikari |
| dashboard.html | fujimino-ophthalmology-reservations | reservation-timeslots-fujiminohikari |
概要: 履歴保存機能を有効化するため、Cloud Runサービスを再デプロイしました。
デプロイしたサービス:
timeslot-checker (一般予約) - リビジョン: timeslot-checker-00007-qmftimeslot-checker-shiya (視野予約) - リビジョン: timeslot-checker-shiya-00001-vrk問題: Cloud Schedulerが古いサービス名を呼び出していたため、履歴データが保存されていませんでした。
| 種類 | Schedulerが呼んでいたサービス | 実際のサービス名 |
|---|---|---|
| 一般予約 | reservation-timeslot-checker |
timeslot-checker |
| 視野予約 | reservation-timeslot-checker-shiya |
timeslot-checker-shiya |
修正後のScheduler設定:
# 一般予約
gcloud scheduler jobs update http reservation-timeslot-checker-job \
--location=asia-northeast1 \
--uri="https://timeslot-checker-224924651996.asia-northeast1.run.app/check"
# 視野予約
gcloud scheduler jobs update http reservation-timeslot-checker-shiya-job \
--location=asia-northeast1 \
--uri="https://timeslot-checker-shiya-224924651996.asia-northeast1.run.app/check"
概要: ダッシュボード用の履歴データ保存が開始されました。
保存先:
gs://reservation-timeslots-fujiminohikari/
├── history/
│ ├── general/2025-12-08.json ✅ 作成確認済み
│ └── shiya/2025-12-08.json ✅ 作成確認済み
効果:
概要: 予約状況チェッカーとChrome拡張機能のタイムラインバーを、より見やすい2本構成(午前/午後)に変更し、ドットを白抜きスタイルに統一しました。
1. 2本構成タイムラインバー
午前バー: 10:00〜13:00(13時台の枠があれば14:00まで拡張)
午後バー: 15:00〜18:00(18時台の枠があれば18:30まで拡張)
2. 白抜きドット
background: white;
border: 3px solid [テーマカラー];
3. 適用範囲
timeslot-status-checker.html - メインの予約状況チェッカー変更ファイル:
timeslot-status-checker.htmlchrome-extension-timeslot-general/popup.html, popup.jschrome-extension-timeslot-shiya/popup.html, popup.js概要: 旧スプレッドシート経由の予約判定システムで使用していたファイルを完全に削除しました。
削除したHTMLファイル(9件):
index.html, shiya.html - 旧バナーmobile-status.html - 旧モバイルチェッカーdisplay.html, display-shiya.html, display-combined.html - 旧全画面ディスプレイdisplay-test.html, display-test-shiya.html, display-test-combined.html - 旧デバッグページ削除したその他ファイル(6件):
Downloads/20251109.txt - 旧GASコードDownloads/display-preset.json - 旧デバッグページ用プリセットdocs/delete-old-rows-guide.md, docs/delete-old-rows-shiya-guide.md - 旧スプレッドシート用ガイドdocs/implementation-guide-v5.md - 旧v5システム実装ガイド効果: 15ファイル、17,171行を削減
概要: 予約状況チェッカーを、スマホモード(800px以下)と壁掛けモード(801px以上)の2モード構成に簡素化しました。これにより、旧来の全画面ディスプレイ(display.html等)は不要になりました。
スマホモード(800px以下):
壁掛けモード(801px以上):
概要: タイムスロット抽出システムへの移行完了に伴い、旧システム(スプレッドシート経由の判定システム)を完全に削除しました。
削除したCloud Runサービス:
reservation-checker - 旧一般予約チェッカーreservation-checker-shiya - 旧視野予約チェッカー削除したCloud Schedulerジョブ:
check-reservation - 旧一般予約の定期実行check-reservation-shiya - 旧視野予約の定期実行削除したディレクトリ(39ファイル、5,690行):
bookmarklet/ - ブックマークレット版チェッカーdocker-automation/ - 旧一般予約Docker自動化docker-automation-shiya/ - 旧視野予約Docker自動化chrome-extension/ - 旧Chrome拡張機能(ステータス表示)chrome-extension-status-indicator/ - 旧ステータス表示拡張機能chrome-extension-general-indicator/ - 旧一般予約インジケーターchrome-extension-shiya-indicator/ - 旧視野予約インジケーターgas/ - Google Apps Script効果:
概要:
timeslot-banner.htmlのUIを大幅に改善し、より見やすく使いやすいデザインに更新しました。
1. 時間枠の個別ピル表示
修正前: 10:00・11:00・14:00…
修正後: [10:00] [11:00] [14:00] ほか
2. 日付形式の変更
修正前: 本日(土)
修正後: 本日(12/6)
3. モバイル表示の改善
calc(100% - 10px)で画面いっぱいに表示align-items: center)変更ファイル:
timeslot-banner.html - ピルデザイン、日付形式、モバイル対応問題: 一般予約のタイムスロット取得システムで、18:30以降でも「本日」の予約枠を参照してしまう問題が発生していました。視野予約は正常に動作していました。
症状:
原因:
process.env.TZ や toLocaleString がCloud Run環境で不安定だった修正内容:
1. 日本時間取得関数をUTCオフセット方式に変更
function getJapanTime() {
const now = new Date();
// 日本時間はUTC+9時間(環境に依存しない確実な方法)
const japanOffset = 9 * 60 * 60 * 1000;
const japanTime = new Date(now.getTime() + japanOffset);
// UTCメソッドを使って日本時間の各値を取得
const year = japanTime.getUTCFullYear();
const month = japanTime.getUTCMonth() + 1;
const date = japanTime.getUTCDate();
const hour = japanTime.getUTCHours();
const minute = japanTime.getUTCMinutes();
return { year, month, date, dayOfWeek, hour, minute };
}
2. Cloud Runのリビジョン整理
3. メモリを1GBに増加
gcloud run deploy timeslot-checker \
--memory 1Gi \
--region asia-northeast1
変更ファイル:
docker-timeslot-checker/server.js - getJapanTime()関数を追加docker-timeslot-checker-shiya/server.js - 同様の修正docker-timeslot-checker/Dockerfile - GPGキー修正を追加docker-timeslot-checker-shiya/Dockerfile - 同様の修正問題:
gcloud builds submit 実行時に以下のエラーが発生:
E: The repository 'https://dl-ssl.google.com/linux/chrome/deb stable InRelease' is not signed.
原因: Puppeteerイメージ(ghcr.io/puppeteer/puppeteer:22.0.0)内のGoogle Chrome GPGキーが古くなっていた。
修正: Dockerfileに以下を追加:
# Google Chrome GPGキーを更新(古いキーが期限切れになる問題を回避)
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg && \
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list
概要: タイムスロット表示用のChrome拡張機能(一般予約・視野予約)のアイコンに、視認性向上のための枠線を追加しました。
変更内容:
実装コード:
const borderWidth = Math.max(1, Math.round(size * 0.08));
ctx.strokeStyle = themeColor;
ctx.lineWidth = borderWidth;
ctx.strokeRect(borderWidth / 2, borderWidth / 2, size - borderWidth, size - borderWidth);
変更ファイル:
chrome-extension-timeslot-general/background.jschrome-extension-timeslot-shiya/background.jsCloud Runは複数のリビジョン(バージョン)を保持できます。古いリビジョンが残っていると、一部のリクエストが古いコードに当たる可能性があります。
確認方法:
gcloud run revisions list --service timeslot-checker --region asia-northeast1
最新リビジョンに100%トラフィックを割り当て:
gcloud run services update-traffic timeslot-checker --to-latest --region asia-northeast1
デプロイ後の推奨手順:
# 1. ビルド
gcloud builds submit --tag gcr.io/$(gcloud config get-value project)/timeslot-checker
# 2. デプロイ(メモリ1GB指定)
gcloud run deploy timeslot-checker \
--image gcr.io/$(gcloud config get-value project)/timeslot-checker \
--region asia-northeast1 \
--platform managed \
--memory 1Gi
# 3. トラフィックを最新に
gcloud run services update-traffic timeslot-checker --to-latest --region asia-northeast1
Puppeteerを使用するサービスは、512MBでは不足する場合があります。
推奨設定:
--memory 1Gi)Memory limit of 512 MiB exceededCloud Run環境でのタイムゾーン処理は環境依存のため、以下の方式を推奨:
推奨: UTCオフセット方式
const japanOffset = 9 * 60 * 60 * 1000;
const japanTime = new Date(now.getTime() + japanOffset);
非推奨: 環境変数依存
process.env.TZ = 'Asia/Tokyo'; // 効果が不安定
概要: Chrome拡張機能と予約状況チェッカーに、日付を含む統一的な表示を実装しました。一般予約と視野予約で表示が異なる問題を解決し、「明日(12/6)」のように日付を明示することでユーザーにわかりやすくなりました。
実装した機能:
1. 日付付き表示
修正前: "次の診療日 残り5枠" または "明日 ✕ 満枠"
修正後: "次の診療日(12/9) 残り5枠" または "明日(12/6) ✕ 満枠"
2. 表示の統一ロジック
function calculateDisplayTextWithDate(targetDate) {
// dateフィールドから本日/明日/次の診療日を自動判定
if (targetDate === currentDate) → "本日(MM/DD)"
else if (targetDate === currentDate + 1) → "明日(MM/DD)"
else → "次の診療日(MM/DD)"
}
3. 問題の解決
修正前の問題:
一般予約: date=6, displayText="次の診療日"
視野予約: date=6, displayText="明日"
→ 同じ日付なのに異なる表示!
修正後:
一般予約: "明日(12/6)"
視野予約: "明日(12/6)"
→ dateフィールドから計算するので統一表示!
変更ファイル:
chrome-extension-timeslot-general/popup.js - 日付計算ロジック追加chrome-extension-timeslot-shiya/popup.js - 同様の修正timeslot-status-checker.html - 一般・視野両方に適用改善効果:
概要: iframe埋め込み用のタイムスロット版バナーを新規作成しました。具体的な時間枠を表示することで、より詳細な予約情報を提供できます。
新規作成ファイル:
timeslot-banner.html - タイムスロット版iframeバナー主な機能:
表示内容(空き枠がある場合):
✅ 明日の予約
10:00・11:00・14:00…
に 空きがございます
クリックして予約ページへ
更新:2025/12/05 14:30
表示内容(満枠の場合):
😔 本日(12/5)の予約は 満枠です
誠に恐れ入りますが、次の診療日以降で ご予約ください
クリックして 予約ページへ
更新:2025/12/05 14:30
技術仕様:
timeslots.json)iframe埋め込みコード:
<iframe
src="https://nekonekoganka.github.io/reservation-status/timeslot-banner.html"
width="100%"
height="280"
frameborder="0"
scrolling="no"
style="border:none;">
</iframe>
改善効果:
概要: 時間枠(タイムスロット)を数字で表示する新しいシステムを実装しました。○/×だけでなく、「残り何枠」かを具体的に表示し、詳細な空き時間リストも確認できます。
新規作成ファイル:
1. 時間枠対応の予約状況チェッカー
timeslot-status-checker.html - 一般予約と視野予約の枠数と詳細を表示2. Chrome拡張機能(枠数表示版)
chrome-extension-timeslot-general/ - 一般予約の枠数を表示
chrome-extension-timeslot-shiya/ - 視野予約の枠数を表示
3. タイムスロット表示のデバッグパネル
timeslot-display.html - デバッグパネル追加(Dキーで開閉)timeslot-display-shiya.html - デバッグパネル追加(Dキーで開閉)主な機能:
1. 予約状況チェッカー(timeslot-status-checker.html)
2. Chrome拡張機能(枠数表示版)
表示方式:
アイコンクリック時:
データソース:
timeslots.jsontimeslots-shiya.json3. デバッグパネル(タイムスロット表示用)
機能:
使い方:
1. Dキーを押してデバッグパネルを開く
2. 「表示する時間枠の数」を入力(1〜20)
3. 「💾 保存」ボタンをクリック
4. 即座に表示が更新される
技術実装:
タイムスロット表示ロジック:
// デバッグ設定から表示する時間枠の数を取得
const settings = loadDebugSettings();
const maxSlots = settings.maxSlots; // デフォルト: 3
// 時間枠を「・」で区切って表示
let timeslotsText;
if (data.slots.length > maxSlots) {
timeslotsText = data.slots.slice(0, maxSlots).join('・') + '…';
} else {
timeslotsText = data.slots.join('・');
}
Chrome拡張機能のアイコン生成:
// Canvas APIで枠数を太字の白い数字で表示
if (slotsCount > 0) {
const fontSize = slotsCount >= 10 ? size * 0.5 : size * 0.6;
ctx.font = `bold ${fontSize}px sans-serif`;
ctx.fillStyle = 'white';
ctx.fillText(slotsCount.toString(), size / 2, size / 2);
}
予約状況チェッカーの折りたたみ式リスト:
// カードタップで詳細表示/非表示を切り替え
function toggleTimeslots(type) {
const container = document.getElementById(`timeslots-${type}`);
container.classList.toggle('expanded');
}
timeslot-status-checker.html - 新規作成(578行)chrome-extension-timeslot-general/ - 新規ディレクトリ
chrome-extension-timeslot-shiya/ - 新規ディレクトリ
timeslot-display.html - デバッグパネル追加(+200行)timeslot-display-shiya.html - デバッグパネル追加(+200行)README.md - リンク集追加、新システムの説明追加概要: デバッグページに背景点滅機能を実装し、通行人の注目を集めるための効果的なアニメーション機能を追加しました。背景のみを点滅させる技術により、テキストやアイコンの視認性を保ちながら目を引く演出が可能になりました。
更新ファイル:
display-test.html - 背景点滅機能の実装と改善display-test-shiya.html - 同機能の実装display-test-combined.html - 同機能の実装実装された機能:
1. 背景のみを点滅させる仕組み
実装コード:
.display-container::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
pointer-events: none;
opacity: 0;
z-index: 1;
}
.display-container > * {
position: relative;
z-index: 2;
}
2. 3つの点滅モード
3. 2つの点滅パターン
4. 速度調整機能の段階的改善
第1段階(コミット c71dd13):
第2段階(コミット a71e305):
スライダー/数値入力切り替え:
function toggleSpeedInputMode() {
customizeState.bgBlinkSpeedInputMode = !customizeState.bgBlinkSpeedInputMode;
if (customizeState.bgBlinkSpeedInputMode) {
// 数値入力モード
sliderContainer.style.display = 'none';
inputContainer.style.display = 'block';
} else {
// スライダーモード
sliderContainer.style.display = 'block';
inputContainer.style.display = 'none';
}
}
5. 強度調整
6. 動的スタイル注入
function applyBgBlinkEffect() {
const style = document.createElement('style');
style.id = 'bgBlinkStyle';
style.textContent = `
#displayContainer::before {
background: ${overlayColor};
animation: ${animationName} ${duration} ease-in-out infinite;
}
`;
document.head.appendChild(style);
}
アニメーション1タブのUI:
カスタマイズ状態の保存:
customizeState: {
bgBlinkEnabled: false,
bgBlinkMode: 'brighten', // 'brighten', 'darken', 'flash-white'
bgBlinkPattern: 'pulse', // 'pulse', 'flash'
bgBlinkSpeed: 1.5, // 0.3〜5.0秒
bgBlinkSpeedInputMode: false, // false: スライダー, true: 数値入力
bgBlinkIntensity: 0.3,
}
通行人を呼び込みたい時:
営業時間中の控えめ表示:
display-test.html - 背景点滅機能の実装(約200行追加)display-test-shiya.html - 同機能の実装display-test-combined.html - 同機能の実装README.md - 背景点滅機能のドキュメント追加[以降、既存の更新履歴が続きます…]
このプロジェクトは私的利用を目的としています。
システムに関する質問や問題は、Issuesでお知らせください。