This commit is contained in:
admin
2026-02-05 16:47:38 +09:00
parent 7e67f9d422
commit 9d1ad5594d

View File

@@ -1,104 +1,228 @@
<!DOCTYPE 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="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/css/style.css" />
<style>
body {
font-family: "Noto Sans JP", Arial, sans-serif;
background: #f6f8fa;
color: #222;
margin: 0;
}
.container {
max-width: 900px;
margin: 30px auto 40px auto;
background: #fff;
border-radius: 16px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
padding: 32px 24px 24px 24px;
}
h1 {
font-size: 2.1rem;
font-weight: 700;
margin-bottom: 24px;
letter-spacing: 0.02em;
color: #007bff;
text-align: center;
}
h2,
h3 {
font-weight: 700;
color: #0056b3;
margin-top: 24px;
margin-bottom: 12px;
}
.nav-tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
border-bottom: 2px solid #ddd;
margin-bottom: 24px;
border-bottom: 2px solid #e3e7ee;
justify-content: center;
}
.nav-tab {
padding: 10px 20px;
padding: 12px 32px;
cursor: pointer;
border: none;
background: #f0f0f0;
border-radius: 5px 5px 0 0;
background: #e9f2ff;
border-radius: 8px 8px 0 0;
font-size: 1.05rem;
font-weight: 500;
color: #007bff;
transition:
background 0.2s,
color 0.2s;
}
.nav-tab.active {
background: #007bff;
color: white;
color: #fff;
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.08);
}
.nav-tab:not(.active):hover {
background: #d0e6ff;
color: #0056b3;
}
.tab-content {
display: none;
animation: fadeIn 0.3s;
}
.tab-content.active {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.employee-list {
margin-top: 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 18px;
}
.employee-item {
padding: 15px;
border: 1px solid #ddd;
margin-bottom: 10px;
border-radius: 5px;
background: #fff;
padding: 18px 16px;
border: 1px solid #e3e7ee;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
cursor: pointer;
transition:
box-shadow 0.2s,
border 0.2s,
background 0.2s;
}
.employee-item:hover {
background: #f9f9f9;
background: #f0f8ff;
border-color: #007bff;
box-shadow: 0 4px 16px rgba(0, 123, 255, 0.08);
}
.form-group {
margin-bottom: 15px;
margin-bottom: 18px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
margin-bottom: 6px;
font-weight: 700;
color: #0056b3;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
border: 1px solid #e3e7ee;
border-radius: 6px;
font-size: 1rem;
background: #f8fbff;
transition: border 0.2s;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
border-color: #007bff;
outline: none;
background: #fff;
}
.btn {
padding: 10px 20px;
padding: 10px 24px;
margin-right: 10px;
border: none;
border-radius: 4px;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
transition:
background 0.2s,
color 0.2s,
box-shadow 0.2s;
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.06);
}
.btn-primary {
background: #007bff;
color: white;
background: linear-gradient(90deg, #007bff 0%, #0056b3 100%);
color: #fff;
}
.btn-primary:hover {
background: linear-gradient(90deg, #0056b3 0%, #007bff 100%);
color: #fff;
box-shadow: 0 4px 16px rgba(0, 123, 255, 0.12);
}
.btn-secondary {
background: #6c757d;
color: white;
background: #e3e7ee;
color: #007bff;
}
.btn-secondary:hover {
background: #d0e6ff;
color: #0056b3;
}
.btn-danger {
background: #dc3545;
color: white;
color: #fff;
}
.btn-danger:hover {
background: #b71c1c;
color: #fff;
}
.filters {
margin-bottom: 18px;
text-align: right;
}
.dependent-list {
margin-top: 20px;
padding: 15px;
background: #f9f9f9;
border-radius: 5px;
margin-top: 24px;
padding: 18px;
background: #f8fbff;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.04);
}
.dependent-item {
padding: 10px;
border: 1px solid #ddd;
padding: 12px 10px;
border: 1px solid #e3e7ee;
margin-bottom: 10px;
background: white;
border-radius: 4px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.dependent-item strong {
color: #007bff;
}
.back-link {
display: inline-block;
margin-bottom: 20px;
margin-bottom: 24px;
color: #007bff;
text-decoration: none;
font-size: 14px;
font-size: 15px;
font-weight: 500;
transition: color 0.2s;
}
.back-link:hover {
text-decoration: underline;
color: #0056b3;
}
@media (max-width: 600px) {
.container {
padding: 12px 4px;
}
h1 {
font-size: 1.3rem;
}
.nav-tabs {
flex-direction: column;
gap: 4px;
}
.employee-list {
grid-template-columns: 1fr;
}
}
</style>
</head>
@@ -597,7 +721,7 @@
async function uploadFileToServer(
file,
employeeCode,
fileType = "image"
fileType = "image",
) {
const formData = new FormData();
formData.append("file", file);
@@ -609,7 +733,7 @@
{
method: "POST",
body: formData,
}
},
);
if (!response.ok) {
@@ -676,10 +800,12 @@
${emp.name_kana ? `(${emp.name_kana})` : ""}
<br>
<small>入社日: ${emp.hire_date} ${
emp.termination_date ? ` | 退職日: ${emp.termination_date}` : ""
}</small>
emp.termination_date
? ` | 退職日: ${emp.termination_date}`
: ""
}</small>
</div>
`
`,
)
.join("");
@@ -719,7 +845,7 @@
const filePath = await uploadFileToServer(
fileInput.files[0],
employeeCode,
"image"
"image",
);
photoUploads[field] = filePath;
} catch (error) {
@@ -783,7 +909,7 @@
async function viewEmployee(employeeId) {
try {
const response = await fetch(
`${API_BASE}/payroll/employees/${employeeId}`
`${API_BASE}/payroll/employees/${employeeId}`,
);
const employee = await response.json();
currentEmployee = employee;
@@ -796,19 +922,19 @@
<p><strong>生年月日:</strong> ${
employee.birth_date || "-"
} ${
employee.birth_date
? `(${calculateAge(employee.birth_date)}歳)`
: ""
}</p>
employee.birth_date
? `(${calculateAge(employee.birth_date)}歳)`
: ""
}</p>
<p><strong>性別:</strong> ${employee.gender || "-"}</p>
<p><strong>マイナンバー:</strong> ${
employee.my_number
? `${employee.my_number.substring(
0,
4
4,
)}-${employee.my_number.substring(
4,
8
8,
)}-${employee.my_number.substring(8, 12)}`
: "-"
}</p>
@@ -823,8 +949,8 @@
employee.termination_date || "-"
}</p>
<p><strong>銀行:</strong> ${employee.bank_name || "-"} ${
employee.bank_branch || ""
}</p>
employee.bank_branch || ""
}</p>
<p><strong>口座:</strong> ${
employee.bank_account_type || ""
} ${employee.bank_account_number || "-"}</p>
@@ -853,7 +979,7 @@
<strong>マイナンバーカード</strong><br>
<img src="${
employee.my_number_card_image_url.startsWith(
"data:"
"data:",
)
? employee.my_number_card_image_url
: API_BASE + employee.my_number_card_image_url
@@ -869,7 +995,7 @@
<strong>在留カード</strong><br>
<img src="${
employee.residence_card_image_url.startsWith(
"data:"
"data:",
)
? employee.residence_card_image_url
: API_BASE + employee.residence_card_image_url
@@ -885,7 +1011,7 @@
<strong>健康保険証</strong><br>
<img src="${
employee.health_insurance_card_image_url.startsWith(
"data:"
"data:",
)
? employee.health_insurance_card_image_url
: API_BASE +
@@ -924,7 +1050,7 @@
) {
koureiCount = employee.dependents.filter((dep) => {
const taxStatus = getTaxDeductionStatus(
dep.birth_date
dep.birth_date,
);
// 源泉税控除対象は16歳以上一般扶養親族16-18歳、特定扶養親族19-22歳、老人扶養親族70歳以上
return (
@@ -950,13 +1076,13 @@
? employee.dependents
.map((dep) => {
const taxStatus = getTaxDeductionStatus(
dep.birth_date
dep.birth_date,
);
return `
<div class="dependent-item">
<strong>${dep.name}</strong> (${
dep.relationship
})
dep.relationship
})
${
dep.birth_date
? ` - 生年月日: ${dep.birth_date} (${taxStatus?.age}歳)`
@@ -978,10 +1104,10 @@
: ""
}
<br><small>有効期間: ${dep.valid_from} ${
dep.valid_to || "現在"
}</small>
dep.valid_to || "現在"
}</small>
<button class="btn btn-primary" onclick='editDependent(${JSON.stringify(
dep
dep,
)})' style="padding: 3px 8px; font-size: 11px; margin-left: 10px;">編集</button>
<button class="btn btn-secondary" onclick="deleteDependent(${
dep.dependent_id
@@ -1001,7 +1127,7 @@
) {
koureiCount = employee.dependents.filter((dep) => {
const taxStatus = getTaxDeductionStatus(
dep.birth_date
dep.birth_date,
);
return (
taxStatus?.isDeductible &&
@@ -1048,7 +1174,7 @@
async function editEmployee(employeeId) {
try {
const response = await fetch(
`${API_BASE}/payroll/employees/${employeeId}`
`${API_BASE}/payroll/employees/${employeeId}`,
);
const employee = await response.json();
currentEmployee = employee;
@@ -1178,7 +1304,7 @@
const filePath = await uploadFileToServer(
fileInput.files[0],
employeeCode,
"image"
"image",
);
photoUploads[field] = filePath;
} catch (error) {
@@ -1214,7 +1340,7 @@
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
}
},
);
if (response.ok) {
@@ -1326,7 +1452,7 @@
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
}
},
);
if (response.ok) {
@@ -1408,7 +1534,7 @@
`${API_BASE}/payroll/employees/dependents/${dependentId}`,
{
method: "DELETE",
}
},
);
if (response.ok) {
@@ -1542,7 +1668,7 @@
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
}
},
);
if (response.ok) {