建設会社向けの施工管理アプリを作ってください。職人を現場と日付に割り当てる「手配ボード」と、協力会社が自分のスマホで現場の報告(現場・時間・午前/午後/1日)を入力する画面の2つが要ります。HTML1ファイル(CSSとJavaScriptも中に入れる)で、フレームワークなしで作ってください。

現場の条件は次のとおりです。
- 同じ職人が同じ日・同じ時間帯に2つの現場へ入る割り当ては、警告を出して止めてください。
- 現場ごとに必要な資格があり、資格の足りない職人は割り当てられません。
- 半日(午前・午後)の割り当てを扱います。午前に現場A、午後に現場Bは正常です。1日と半日の重なりは重なりです。
- 協力会社の入力画面は、職人ごと・日ごとの入力リンク(アカウントなし)で開きます。リンクの有効期限は7日で、過ぎたら入力を受け付けません。
- 電波が悪い現場が多いので、圏外で送信しても内容を失わず、電波が戻ったら自動で送り直してください。ただし同じ報告が2回届いてはいけません。ボタンの連打も1回にまとめてください。
- 協力会社は自分の報告を入れるだけで、手配ボードの割り当ては変えられません。
- 時間の入力は0〜24の範囲だけ受け付けます。
- 出面(人工)は月末に職人ごとに集計します。1日=1人工、午前または午後だけ=0.5人工で、月をまたぐ分は入れません。

自動で試すため、次の関数をwindow.genbaに公開してください。これは動作確認のための窓口で、画面のつくりは自由です。
- addWorker({id, name, company, quals:[資格名]}) と addSite({id, name, needQuals:[資格名]})
- assign({workerId, siteId, date:'YYYY-MM-DD', part:'am'|'pm'|'day'}) → {ok:boolean, warnings:[文字列]}
- unassign(同じ引数) 、getAssignments() → 割り当ての配列
- setRole('dispatcher'|'partner') で操作する人の立場を切り替える
- issueLink({workerId, date}) → トークン文字列 、linkValid(token) → boolean
- submitReport(token, {siteId, date:'YYYY-MM-DD', part:'am'|'pm'|'day', hours:数}) → {ok:boolean, error?:文字列}(同期でもPromiseでもよい)。送信先はPOST /api/reports(JSONで本文を送る。サーバーは別に用意済み)
- getReports() → 受け付けた報告の配列
- monthlyTally(workerId, 'YYYY-MM') → {days:数}(1日=1人工、午前または午後=0.5)

返答は、完成したHTML全体を1つのコードブロックで。説明は不要です。
