342 lines
11 KiB
HTML
342 lines
11 KiB
HTML
<!doctype html>
|
||
<html lang="ja">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>給与管理 - 従業員管理</title>
|
||
<link rel="stylesheet" href="/css/style.css" />
|
||
<style>
|
||
.nav-tabs {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
border-bottom: 2px solid #ddd;
|
||
}
|
||
.nav-tab {
|
||
padding: 10px 20px;
|
||
cursor: pointer;
|
||
border: none;
|
||
background: #f0f0f0;
|
||
border-radius: 5px 5px 0 0;
|
||
}
|
||
.nav-tab.active {
|
||
background: #007bff;
|
||
color: white;
|
||
}
|
||
.tab-content {
|
||
display: none;
|
||
}
|
||
.tab-content.active {
|
||
display: block;
|
||
}
|
||
.employee-list {
|
||
margin-top: 20px;
|
||
}
|
||
.employee-item {
|
||
padding: 15px;
|
||
border: 1px solid #ddd;
|
||
margin-bottom: 10px;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
}
|
||
.employee-item:hover {
|
||
background: #f9f9f9;
|
||
}
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
font-weight: bold;
|
||
}
|
||
.form-group input,
|
||
.form-group select,
|
||
.form-group textarea {
|
||
width: 100%;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
}
|
||
.btn {
|
||
padding: 10px 20px;
|
||
margin-right: 10px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}
|
||
.btn-primary {
|
||
background: #007bff;
|
||
color: white;
|
||
}
|
||
.btn-secondary {
|
||
background: #6c757d;
|
||
color: white;
|
||
}
|
||
.btn-danger {
|
||
background: #dc3545;
|
||
color: white;
|
||
}
|
||
.dependent-list {
|
||
margin-top: 20px;
|
||
padding: 15px;
|
||
background: #f9f9f9;
|
||
border-radius: 5px;
|
||
}
|
||
.dependent-item {
|
||
padding: 10px;
|
||
border: 1px solid #ddd;
|
||
margin-bottom: 10px;
|
||
background: white;
|
||
border-radius: 4px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>給与管理 - 従業員管理</h1>
|
||
|
||
<div class="nav-tabs">
|
||
<button class="nav-tab active" onclick="showTab('list')">
|
||
従業員一覧
|
||
</button>
|
||
<button class="nav-tab" onclick="showTab('create')">新規登録</button>
|
||
<button
|
||
class="nav-tab"
|
||
onclick="showTab('detail')"
|
||
id="detailTab"
|
||
style="display: none"
|
||
>
|
||
従業員詳細
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 従業員一覧タブ -->
|
||
<div id="tab-list" class="tab-content active">
|
||
<div class="filters">
|
||
<label>
|
||
<input
|
||
type="checkbox"
|
||
id="filterActive"
|
||
checked
|
||
onchange="loadEmployees()"
|
||
/>
|
||
在職中のみ表示
|
||
</label>
|
||
</div>
|
||
<div id="employeeList" class="employee-list"></div>
|
||
</div>
|
||
|
||
<!-- 新規登録タブ -->
|
||
<div id="tab-create" class="tab-content">
|
||
<h2>従業員の新規登録</h2>
|
||
<form id="createForm" onsubmit="createEmployee(event)">
|
||
<div class="form-group">
|
||
<label>従業員コード *</label>
|
||
<input type="text" name="employee_code" required />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>氏名 *</label>
|
||
<input type="text" name="name" required />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>フリガナ</label>
|
||
<input type="text" name="name_kana" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>メールアドレス</label>
|
||
<input type="email" name="email" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>電話番号</label>
|
||
<input type="tel" name="phone" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>入社日 *</label>
|
||
<input type="date" name="hire_date" required />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>銀行名</label>
|
||
<input type="text" name="bank_name" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>支店名</label>
|
||
<input type="text" name="bank_branch" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>口座番号</label>
|
||
<input type="text" name="bank_account_number" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>口座種別</label>
|
||
<select name="bank_account_type">
|
||
<option value="">選択してください</option>
|
||
<option value="普通">普通</option>
|
||
<option value="当座">当座</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>備考</label>
|
||
<textarea name="notes" rows="3"></textarea>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary">登録</button>
|
||
<button
|
||
type="button"
|
||
class="btn btn-secondary"
|
||
onclick="showTab('list')"
|
||
>
|
||
キャンセル
|
||
</button>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- 従業員詳細タブ -->
|
||
<div id="tab-detail" class="tab-content">
|
||
<div id="employeeDetail"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const API_BASE = "";
|
||
let currentEmployee = null;
|
||
|
||
function showTab(tabName) {
|
||
document
|
||
.querySelectorAll(".nav-tab")
|
||
.forEach((tab) => tab.classList.remove("active"));
|
||
document
|
||
.querySelectorAll(".tab-content")
|
||
.forEach((content) => content.classList.remove("active"));
|
||
|
||
if (tabName === "list") {
|
||
document.querySelector(".nav-tab").classList.add("active");
|
||
document.getElementById("tab-list").classList.add("active");
|
||
loadEmployees();
|
||
} else if (tabName === "create") {
|
||
document.querySelectorAll(".nav-tab")[1].classList.add("active");
|
||
document.getElementById("tab-create").classList.add("active");
|
||
} else if (tabName === "detail") {
|
||
document.getElementById("detailTab").classList.add("active");
|
||
document.getElementById("tab-detail").classList.add("active");
|
||
}
|
||
}
|
||
|
||
async function loadEmployees() {
|
||
const isActive = document.getElementById("filterActive").checked;
|
||
const url = `${API_BASE}/payroll/employees/${isActive ? "?is_active=true" : ""}`;
|
||
|
||
try {
|
||
const response = await fetch(url);
|
||
const employees = await response.json();
|
||
|
||
const html = employees
|
||
.map(
|
||
(emp) => `
|
||
<div class="employee-item" onclick="viewEmployee(${emp.employee_id})">
|
||
<strong>${emp.employee_code}</strong> - ${emp.name}
|
||
${emp.name_kana ? `(${emp.name_kana})` : ""}
|
||
<br>
|
||
<small>入社日: ${emp.hire_date} ${emp.termination_date ? ` | 退職日: ${emp.termination_date}` : ""}</small>
|
||
</div>
|
||
`,
|
||
)
|
||
.join("");
|
||
|
||
document.getElementById("employeeList").innerHTML =
|
||
html || "<p>従業員が登録されていません</p>";
|
||
} catch (error) {
|
||
alert("従業員一覧の取得に失敗しました");
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
async function createEmployee(event) {
|
||
event.preventDefault();
|
||
const form = event.target;
|
||
const formData = new FormData(form);
|
||
const data = Object.fromEntries(formData.entries());
|
||
|
||
// 空の値を除外
|
||
Object.keys(data).forEach((key) => {
|
||
if (data[key] === "") {
|
||
delete data[key];
|
||
}
|
||
});
|
||
|
||
try {
|
||
const response = await fetch(`${API_BASE}/payroll/employees/`, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify(data),
|
||
});
|
||
|
||
if (response.ok) {
|
||
alert("従業員を登録しました");
|
||
form.reset();
|
||
showTab("list");
|
||
} else {
|
||
const error = await response.json();
|
||
alert("登録に失敗しました: " + error.detail);
|
||
}
|
||
} catch (error) {
|
||
alert("登録に失敗しました");
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
async function viewEmployee(employeeId) {
|
||
try {
|
||
const response = await fetch(
|
||
`${API_BASE}/payroll/employees/${employeeId}`,
|
||
);
|
||
const employee = await response.json();
|
||
currentEmployee = employee;
|
||
|
||
const html = `
|
||
<h2>${employee.name} (${employee.employee_code})</h2>
|
||
<p><strong>フリガナ:</strong> ${employee.name_kana || "-"}</p>
|
||
<p><strong>メール:</strong> ${employee.email || "-"}</p>
|
||
<p><strong>電話:</strong> ${employee.phone || "-"}</p>
|
||
<p><strong>入社日:</strong> ${employee.hire_date}</p>
|
||
<p><strong>退職日:</strong> ${employee.termination_date || "-"}</p>
|
||
<p><strong>銀行:</strong> ${employee.bank_name || "-"} ${employee.bank_branch || ""}</p>
|
||
<p><strong>口座:</strong> ${employee.bank_account_type || ""} ${employee.bank_account_number || "-"}</p>
|
||
<p><strong>備考:</strong> ${employee.notes || "-"}</p>
|
||
|
||
<div class="dependent-list">
|
||
<h3>扶養家族</h3>
|
||
${
|
||
employee.dependents
|
||
.map(
|
||
(dep) => `
|
||
<div class="dependent-item">
|
||
<strong>${dep.name}</strong> (${dep.relationship})
|
||
${dep.birth_date ? ` - 生年月日: ${dep.birth_date}` : ""}
|
||
${dep.is_spouse ? ' <span style="color:blue;">[配偶者]</span>' : ""}
|
||
${dep.is_disabled ? ' <span style="color:red;">[障害者]</span>' : ""}
|
||
<br><small>有効期間: ${dep.valid_from} ~ ${dep.valid_to || "現在"}</small>
|
||
</div>
|
||
`,
|
||
)
|
||
.join("") || "<p>扶養家族が登録されていません</p>"
|
||
}
|
||
</div>
|
||
|
||
<button class="btn btn-secondary" onclick="showTab('list')">戻る</button>
|
||
`;
|
||
|
||
document.getElementById("employeeDetail").innerHTML = html;
|
||
document.getElementById("detailTab").style.display = "block";
|
||
showTab("detail");
|
||
} catch (error) {
|
||
alert("従業員情報の取得に失敗しました");
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
// 初期化
|
||
loadEmployees();
|
||
</script>
|
||
</body>
|
||
</html>
|