次に管理者画面を強化していきます。
Contents
変更内容
内容 | 説明 |
---|---|
① 社員一覧を管理者画面で表示 | 誰が登録されているかを一覧で見たい |
② スタッフごとの過去の履歴も見たい | 日付ごとの出退勤履歴を社員ごとに確認 |
進め方のイメージ
順番に作っていきます。
- Firestoreに「社員リスト」を作成
- 管理者ページで社員一覧表示
- 各社員ごとに「今の出勤状況」を表示
- 社員をクリックすると「その人の履歴一覧ページ」にジャンプ
①最初のステップ:「社員リスト」を作ろう
Firestoreに「usersコレクション」を作成する
- コレクション名:
users
- ドキュメント:社員ごとのデータ
- データ例:
- name: “田中 太郎”
- email: “tanaka@example.com“
- role: “employee”(普通の社員ならemployee、管理者ならadmin)
🛠 Firestoreに手動で追加する方法
- Firebaseコンソールに行く
- Firestore Databaseを開く
- 「コレクションを開始」をクリック
- コレクションIDに
users
と入力 - ドキュメントIDは自動生成でもOK
- フィールドを追加:
- name : “山田 太郎”(←社員名)
- email : “yamada@example.com“(←社員のメールアドレス)
- role : “employee”(←社員ならemployee)
これでOKです!
次にやること
管理者ページ(admin.html)で、
この users
コレクションを読み込んで、社員一覧を表示します!
イメージ👇
名前 | メールアドレス | 出勤状況 |
---|---|---|
山田 太郎 | yamada@example.com | 出勤中 |
佐藤 花子 | sato@example.com | 退勤済み |
今あるadmin.html
の <body>
部分をちょっと変えます👇
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>出退勤履歴一覧</title>
<script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-firestore-compat.js"></script>
</head>
<body>
<h1>管理者ページ</h1>
<table border="1">
<thead>
<tr>
<th>名前</th>
<th>メールアドレス</th>
<th>出勤状況</th>
</tr>
</thead>
<tbody id="userList">
<!-- ここに社員リストが表示される -->
</tbody>
</table>
<script>
// ここにFirebase設定と初期化を追加!!👇
const firebaseConfig = {
apiKey: "あなたのAPIキー",
authDomain: "あなたのプロジェクトID.firebaseapp.com",
projectId: "あなたのプロジェクトID",
storageBucket: "あなたのプロジェクトID.appspot.com",
messagingSenderId: "送信者ID",
appId: "アプリID"
};
// Firebase初期化
firebase.initializeApp(firebaseConfig);
// Firestore使うよ
const db = firebase.firestore();
function loadUsers() {
db.collection("users").get()
.then((querySnapshot) => {
const userList = document.getElementById("userList");
userList.innerHTML = ""; // 一回クリア
querySnapshot.forEach((doc) => {
const user = doc.data();
// 出勤状況は今は仮で「不明」
const status = "不明";
const row = `
<tr>
<td>${user.name}</td>
<td>${user.email}</td>
<td>${status}</td>
</tr>
`;
userList.innerHTML += row;
});
})
.catch((error) => {
console.error("エラー:", error);
});
}
// ページが開いたら実行
window.onload = loadUsers;
</script>
</body>
</html>
② 社員ごとの過去の出退勤履歴を一覧で見れるようにする
やりたいこと
- Firestoreのattendanceコレクションから
- 特定のUIDと一致するデータだけ取得して
- リスト表示する
- 日付や出勤・退勤の情報も見やすく出す
イメージとしては、
日付 | 出勤/退勤 | 時間 |
---|---|---|
4月28日 | 出勤 | 23:42 |
4月28日 | 退勤 | 23:50 |
みたいな感じ。
これから作る機能
- Firestoreから指定のユーザーのattendanceデータだけを取得
- 名前にボタン機能をつける
- ボタンを押すと履歴がリスト表示される
- 日付・出勤or退勤・時間をわかりやすく表示する
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>出退勤履歴一覧</title>
<script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-firestore-compat.js"></script>
</head>
<body>
<h1>管理者ページ</h1>
<table border="1">
<thead>
<tr>
<th>名前</th>
<th>メールアドレス</th>
<th>出勤状況</th>
</tr>
</thead>
<tbody id="userList">
<!-- ここに社員リストが表示される -->
</tbody>
</table>
<h2>出退勤履歴</h2>
<div id="attendanceList">
<!-- ここに選択した社員の出退勤記録が表示される -->
</div>
<script>
const firebaseConfig = {
apiKey: "あなたのAPIキー",
authDomain: "あなたのプロジェクトID.firebaseapp.com",
projectId: "あなたのプロジェクトID",
storageBucket: "あなたのプロジェクトID.appspot.com",
messagingSenderId: "送信者ID",
appId: "アプリID"
};
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
function loadUsers() {
db.collection("users").get()
.then((querySnapshot) => {
const userList = document.getElementById("userList");
userList.innerHTML = "";
querySnapshot.forEach((doc) => {
const user = doc.data();
const userId = doc.id; // ドキュメントIDがUIDの場合
const row = `
<tr>
<td><a href="#" onclick="loadAttendance('${userId}', '${user.name}')">${user.name}</a></td>
<td>${user.email}</td>
<td>不明</td>
</tr>
`;
userList.innerHTML += row;
});
})
.catch((error) => {
console.error("エラー:", error);
});
}
function loadAttendance(userId, userName) {
const attendanceList = document.getElementById("attendanceList");
attendanceList.innerHTML = `<h3>${userName}さんの出退勤履歴</h3>`;
db.collection("attendance")
.where("uid", "==", userId)
.orderBy("time", "desc")
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
attendanceList.innerHTML += "<p>出退勤記録がありません。</p>";
return;
}
let listHtml = "<ul>";
querySnapshot.forEach((doc) => {
const data = doc.data();
const type = data.type;
const time = data.time.toDate().toLocaleString('ja-JP');
listHtml += `<li>${time} - ${type}</li>`;
});
listHtml += "</ul>";
attendanceList.innerHTML += listHtml;
})
.catch((error) => {
console.error("出退勤記録の取得エラー:", error);
});
}
window.onload = loadUsers;
</script>
</body>
</html>
🔥変更ポイントまとめ
名前
をリンクにして、クリックしたらloadAttendance(userId, userName)
を呼ぶattendance
コレクションから、uidが一致する出退勤データを取得- 時系列(新しい順)に並べてリスト表示
- 出勤 or 退勤が時刻と一緒に表示される
さらに良くするために
- 「次の月へ」「前の月へ」ボタン式にする
- 今月以降の未来の月は押せないようにする
- 出勤・退勤でアイコンや色をつける
- 合計勤務日数、合計勤務時間を出す
改良版コード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>出退勤履歴一覧</title>
<script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.11.0/firebase-firestore-compat.js"></script>
<style>
.clock-in {
color: green;
font-weight: bold;
}
.clock-out {
color: blue;
font-weight: bold;
}
</style>
</head>
<body>
<h1>管理者ページ</h1>
<table border="1">
<thead>
<tr>
<th>名前</th>
<th>メールアドレス</th>
<th>出勤状況</th>
</tr>
</thead>
<tbody id="userList">
<!-- ここに社員リストが表示される -->
</tbody>
</table>
<h2>出退勤履歴</h2>
<div id="attendanceList">
<!-- ここに選択した社員の出退勤記録が表示される -->
</div>
<script>
const firebaseConfig = {
apiKey: "あなたのAPIキー",
authDomain: "あなたのプロジェクトID.firebaseapp.com",
projectId: "あなたのプロジェクトID",
storageBucket: "あなたのプロジェクトID.appspot.com",
messagingSenderId: "送信者ID",
appId: "アプリID"
};
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
let currentUserId = null;
let currentUserName = null;
let currentYear = null;
let currentMonth = null; // 0〜11
const today = new Date();
function loadUsers() {
db.collection("users").get()
.then((querySnapshot) => {
const userList = document.getElementById("userList");
userList.innerHTML = "";
querySnapshot.forEach((doc) => {
const user = doc.data();
const userId = doc.id;
const row = `
<tr>
<td><a href="#" onclick="loadAttendance('${userId}', '${user.name}')">${user.name}</a></td>
<td>${user.email}</td>
<td>不明</td>
</tr>
`;
userList.innerHTML += row;
});
})
.catch((error) => {
console.error("エラー:", error);
});
}
function loadAttendance(userId, userName) {
currentUserId = userId;
currentUserName = userName;
const now = new Date();
currentYear = now.getFullYear();
currentMonth = now.getMonth();
renderAttendancePage();
}
function renderAttendancePage() {
const attendanceList = document.getElementById("attendanceList");
attendanceList.innerHTML = `
<h3>${currentUserName}さんの出退勤履歴</h3>
<div>
<button onclick="changeMonth(-1)">前の月へ</button>
<span id="currentMonthLabel">${currentYear}年${currentMonth + 1}月</span>
<button onclick="changeMonth(1)">次の月へ</button>
</div>
<div id="attendanceRecords"></div>
`;
fetchAttendance(currentUserId, currentYear, currentMonth);
}
function changeMonth(diff) {
let tempYear = currentYear;
let tempMonth = currentMonth + diff;
if (tempMonth < 0) {
tempMonth = 11;
tempYear--;
} else if (tempMonth > 11) {
tempMonth = 0;
tempYear++;
}
// 未来の月はダメ!
if (tempYear > today.getFullYear() || (tempYear === today.getFullYear() && tempMonth > today.getMonth())) {
return;
}
currentYear = tempYear;
currentMonth = tempMonth;
document.getElementById("currentMonthLabel").innerText = `${currentYear}年${currentMonth + 1}月`;
fetchAttendance(currentUserId, currentYear, currentMonth);
}
function fetchAttendance(userId, year, month) {
const start = new Date(year, month, 1);
const end = new Date(year, month + 1, 1);
const attendanceRecords = document.getElementById("attendanceRecords");
attendanceRecords.innerHTML = `<p>読み込み中...</p>`;
db.collection("attendance")
.where("uid", "==", userId)
.where("time", ">=", start)
.where("time", "<", end)
.orderBy("time", "asc")
.get()
.then((querySnapshot) => {
if (querySnapshot.empty) {
attendanceRecords.innerHTML = "<p>この月の出退勤記録はありません。</p>";
return;
}
let listHtml = "<ul>";
let lastClockIn = null;
let totalWorkedMs = 0;
let workDays = 0;
querySnapshot.forEach((doc) => {
const data = doc.data();
const type = data.type;
const time = data.time.toDate();
const timeString = time.toLocaleString('ja-JP');
if (type === "出勤") {
listHtml += `<li class="clock-in">✅ ${timeString} - 出勤</li>`;
lastClockIn = time;
workDays++;
} else if (type === "退勤") {
listHtml += `<li class="clock-out">🏁 ${timeString} - 退勤</li>`;
if (lastClockIn) {
totalWorkedMs += time - lastClockIn;
lastClockIn = null;
}
}
});
listHtml += "</ul>";
const totalHours = (totalWorkedMs / (1000 * 60 * 60)).toFixed(2);
listHtml += `<p>✅ 勤務日数: ${workDays}日</p>`;
listHtml += `<p>⏰ 総勤務時間: ${totalHours}時間</p>`;
attendanceRecords.innerHTML = listHtml;
})
.catch((error) => {
console.error("出退勤記録の取得エラー:", error);
});
}
window.onload = loadUsers;
</script>
</body>
</html>
改善ポイントまとめ
機能 | できること |
---|---|
✅未来制限 | 今月より未来には「次へ」できない! |
✅色分け | 出勤→✅緑色、退勤→🏁青色でわかりやすい |
✅合計表示 | 勤務日数と総勤務時間(小数点2桁)を月ごとに表示 |