修正
This commit is contained in:
@@ -10,7 +10,6 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 767px) {
|
@media screen and (max-width: 767px) {
|
||||||
|
|
||||||
/* ── body 余白を縮小 ── */
|
/* ── body 余白を縮小 ── */
|
||||||
body {
|
body {
|
||||||
padding: 12px !important;
|
padding: 12px !important;
|
||||||
@@ -18,8 +17,12 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── h1・h2 フォントサイズ ── */
|
/* ── h1・h2 フォントサイズ ── */
|
||||||
h1 { font-size: 1.35rem !important; }
|
h1 {
|
||||||
h2 { font-size: 1.1rem !important; }
|
font-size: 1.35rem !important;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 1.1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
テーブル: 横スクロール
|
テーブル: 横スクロール
|
||||||
@@ -320,5 +323,4 @@ html {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
box-sizing: border-box !important;
|
box-sizing: border-box !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -863,7 +863,19 @@
|
|||||||
<div class="search-buttons">
|
<div class="search-buttons">
|
||||||
<button onclick="searchJournals()">🔍 検索</button>
|
<button onclick="searchJournals()">🔍 検索</button>
|
||||||
<button onclick="printSearchResults()">🖨️ 印刷</button>
|
<button onclick="printSearchResults()">🖨️ 印刷</button>
|
||||||
<button onclick="clearSearchConditions()" style="background: #6c757d; color: white; border: none; padding: 6px 14px; border-radius: 4px; cursor: pointer;">🔄 条件クリア</button>
|
<button
|
||||||
|
onclick="clearSearchConditions()"
|
||||||
|
style="
|
||||||
|
background: #6c757d;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
🔄 条件クリア
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -2830,7 +2842,8 @@
|
|||||||
// 複数行フォームへのコピー
|
// 複数行フォームへのコピー
|
||||||
function copyJournalToDetailForm(data) {
|
function copyJournalToDetailForm(data) {
|
||||||
document.getElementById("detailEntryDate").value = data.entry_date;
|
document.getElementById("detailEntryDate").value = data.entry_date;
|
||||||
document.getElementById("detailDescription").value = data.description || "";
|
document.getElementById("detailDescription").value =
|
||||||
|
data.description || "";
|
||||||
|
|
||||||
// 既存行をクリア
|
// 既存行をクリア
|
||||||
document.getElementById("detailLinesTbody").innerHTML = "";
|
document.getElementById("detailLinesTbody").innerHTML = "";
|
||||||
@@ -2846,10 +2859,14 @@
|
|||||||
accountInput.dataset.accountId = acc.account_id;
|
accountInput.dataset.accountId = acc.account_id;
|
||||||
}
|
}
|
||||||
if (Number(line.debit) > 0) {
|
if (Number(line.debit) > 0) {
|
||||||
tr.querySelector(".detail-debit").value = Number(line.debit).toLocaleString();
|
tr.querySelector(".detail-debit").value = Number(
|
||||||
|
line.debit,
|
||||||
|
).toLocaleString();
|
||||||
}
|
}
|
||||||
if (Number(line.credit) > 0) {
|
if (Number(line.credit) > 0) {
|
||||||
tr.querySelector(".detail-credit").value = Number(line.credit).toLocaleString();
|
tr.querySelector(".detail-credit").value = Number(
|
||||||
|
line.credit,
|
||||||
|
).toLocaleString();
|
||||||
}
|
}
|
||||||
if (line.line_description) {
|
if (line.line_description) {
|
||||||
tr.querySelector(".detail-line-memo").value = line.line_description;
|
tr.querySelector(".detail-line-memo").value = line.line_description;
|
||||||
@@ -2927,16 +2944,14 @@
|
|||||||
if (kamokuAcc) {
|
if (kamokuAcc) {
|
||||||
document.getElementById("entryAccountInput").value =
|
document.getElementById("entryAccountInput").value =
|
||||||
`${kamokuAcc.account_code} ${kamokuAcc.account_name}`;
|
`${kamokuAcc.account_code} ${kamokuAcc.account_name}`;
|
||||||
document.getElementById(
|
document.getElementById("entryAccountInput").dataset.accountId =
|
||||||
"entryAccountInput",
|
kamokuAcc.account_id;
|
||||||
).dataset.accountId = kamokuAcc.account_id;
|
|
||||||
}
|
}
|
||||||
if (methodAcc) {
|
if (methodAcc) {
|
||||||
document.getElementById("entryMethodInput").value =
|
document.getElementById("entryMethodInput").value =
|
||||||
`${methodAcc.account_code} ${methodAcc.account_name}`;
|
`${methodAcc.account_code} ${methodAcc.account_name}`;
|
||||||
document.getElementById(
|
document.getElementById("entryMethodInput").dataset.accountId =
|
||||||
"entryMethodInput",
|
methodAcc.account_id;
|
||||||
).dataset.accountId = methodAcc.account_id;
|
|
||||||
}
|
}
|
||||||
const totalAmount = Number(mainCredit.credit);
|
const totalAmount = Number(mainCredit.credit);
|
||||||
document.getElementById("entryAmount").value =
|
document.getElementById("entryAmount").value =
|
||||||
@@ -2958,16 +2973,14 @@
|
|||||||
if (kamokuAcc) {
|
if (kamokuAcc) {
|
||||||
document.getElementById("entryAccountInput").value =
|
document.getElementById("entryAccountInput").value =
|
||||||
`${kamokuAcc.account_code} ${kamokuAcc.account_name}`;
|
`${kamokuAcc.account_code} ${kamokuAcc.account_name}`;
|
||||||
document.getElementById(
|
document.getElementById("entryAccountInput").dataset.accountId =
|
||||||
"entryAccountInput",
|
kamokuAcc.account_id;
|
||||||
).dataset.accountId = kamokuAcc.account_id;
|
|
||||||
}
|
}
|
||||||
if (methodAcc) {
|
if (methodAcc) {
|
||||||
document.getElementById("entryMethodInput").value =
|
document.getElementById("entryMethodInput").value =
|
||||||
`${methodAcc.account_code} ${methodAcc.account_name}`;
|
`${methodAcc.account_code} ${methodAcc.account_name}`;
|
||||||
document.getElementById(
|
document.getElementById("entryMethodInput").dataset.accountId =
|
||||||
"entryMethodInput",
|
methodAcc.account_id;
|
||||||
).dataset.accountId = methodAcc.account_id;
|
|
||||||
}
|
}
|
||||||
const totalAmount = Number(mainDebit.debit);
|
const totalAmount = Number(mainDebit.debit);
|
||||||
document.getElementById("entryAmount").value =
|
document.getElementById("entryAmount").value =
|
||||||
@@ -2993,9 +3006,8 @@
|
|||||||
).checked = true;
|
).checked = true;
|
||||||
document.getElementById("entryAccountInput").value =
|
document.getElementById("entryAccountInput").value =
|
||||||
`${kamokuAccD.account_code} ${kamokuAccD.account_name}`;
|
`${kamokuAccD.account_code} ${kamokuAccD.account_name}`;
|
||||||
document.getElementById(
|
document.getElementById("entryAccountInput").dataset.accountId =
|
||||||
"entryAccountInput",
|
kamokuAccD.account_id;
|
||||||
).dataset.accountId = kamokuAccD.account_id;
|
|
||||||
const methodAcc = accounts.find(
|
const methodAcc = accounts.find(
|
||||||
(a) => a.account_id === mainCredit.account_id,
|
(a) => a.account_id === mainCredit.account_id,
|
||||||
);
|
);
|
||||||
@@ -3025,9 +3037,8 @@
|
|||||||
}
|
}
|
||||||
document.getElementById("entryMethodInput").value =
|
document.getElementById("entryMethodInput").value =
|
||||||
`${kamokuAccD.account_code} ${kamokuAccD.account_name}`;
|
`${kamokuAccD.account_code} ${kamokuAccD.account_name}`;
|
||||||
document.getElementById(
|
document.getElementById("entryMethodInput").dataset.accountId =
|
||||||
"entryMethodInput",
|
kamokuAccD.account_id;
|
||||||
).dataset.accountId = kamokuAccD.account_id;
|
|
||||||
document.getElementById("entryAmount").value = Number(
|
document.getElementById("entryAmount").value = Number(
|
||||||
mainDebit.debit,
|
mainDebit.debit,
|
||||||
).toLocaleString();
|
).toLocaleString();
|
||||||
|
|||||||
@@ -9,7 +9,13 @@
|
|||||||
<link rel="stylesheet" href="/css/mobile.css" />
|
<link rel="stylesheet" href="/css/mobile.css" />
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: system-ui, -apple-system, "Yu Gothic UI", "Hiragino Kaku Gothic ProN", "メイリオ", sans-serif;
|
font-family:
|
||||||
|
system-ui,
|
||||||
|
-apple-system,
|
||||||
|
"Yu Gothic UI",
|
||||||
|
"Hiragino Kaku Gothic ProN",
|
||||||
|
"メイリオ",
|
||||||
|
sans-serif;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
background: #f5f7fa;
|
background: #f5f7fa;
|
||||||
}
|
}
|
||||||
@@ -20,7 +26,10 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.page-header h1 { margin: 0; font-size: 20px; }
|
.page-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
.back-link {
|
.back-link {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
background: #007bff;
|
background: #007bff;
|
||||||
@@ -31,7 +40,9 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
.back-link:hover { background: #0056b3; }
|
.back-link:hover {
|
||||||
|
background: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── アップロードゾーン ── */
|
/* ── アップロードゾーン ── */
|
||||||
.upload-zone {
|
.upload-zone {
|
||||||
@@ -43,15 +54,27 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.2s, background 0.2s;
|
transition:
|
||||||
|
border-color 0.2s,
|
||||||
|
background 0.2s;
|
||||||
}
|
}
|
||||||
.upload-zone.dragover {
|
.upload-zone.dragover {
|
||||||
border-color: #007bff;
|
border-color: #007bff;
|
||||||
background: #e8f4ff;
|
background: #e8f4ff;
|
||||||
}
|
}
|
||||||
.upload-zone h3 { margin: 0 0 8px; font-size: 16px; color: #495057; }
|
.upload-zone h3 {
|
||||||
.upload-zone p { margin: 0; color: #6c757d; font-size: 13px; }
|
margin: 0 0 8px;
|
||||||
.upload-zone input[type=file] { display: none; }
|
font-size: 16px;
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
.upload-zone p {
|
||||||
|
margin: 0;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.upload-zone input[type="file"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.upload-btn {
|
.upload-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
@@ -63,15 +86,23 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
.upload-btn:hover { background: #0056b3; }
|
.upload-btn:hover {
|
||||||
|
background: #0056b3;
|
||||||
|
}
|
||||||
#upload-status {
|
#upload-status {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 0 auto 12px;
|
margin: 0 auto 12px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
min-height: 24px;
|
min-height: 24px;
|
||||||
}
|
}
|
||||||
.status-ok { color: #28a745; font-weight: bold; }
|
.status-ok {
|
||||||
.status-err { color: #dc3545; font-weight: bold; }
|
color: #28a745;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.status-err {
|
||||||
|
color: #dc3545;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── フィルターバー ── */
|
/* ── フィルターバー ── */
|
||||||
.filter-bar {
|
.filter-bar {
|
||||||
@@ -82,7 +113,11 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
.type-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
|
.type-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
.type-tab {
|
.type-tab {
|
||||||
padding: 5px 14px;
|
padding: 5px 14px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@@ -93,8 +128,15 @@
|
|||||||
color: #495057;
|
color: #495057;
|
||||||
transition: all 0.15s;
|
transition: all 0.15s;
|
||||||
}
|
}
|
||||||
.type-tab:hover { border-color: #007bff; color: #007bff; }
|
.type-tab:hover {
|
||||||
.type-tab.active { background: #007bff; color: #fff; border-color: #007bff; }
|
border-color: #007bff;
|
||||||
|
color: #007bff;
|
||||||
|
}
|
||||||
|
.type-tab.active {
|
||||||
|
background: #007bff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
.filter-select {
|
.filter-select {
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border: 1px solid #ced4da;
|
border: 1px solid #ced4da;
|
||||||
@@ -130,9 +172,15 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.1s;
|
transition: background 0.1s;
|
||||||
}
|
}
|
||||||
.doc-table tbody tr:hover { background: #f0f7ff; }
|
.doc-table tbody tr:hover {
|
||||||
.doc-table tbody tr.selected { background: #dbeafe; }
|
background: #f0f7ff;
|
||||||
.doc-table tbody td { padding: 10px 12px; }
|
}
|
||||||
|
.doc-table tbody tr.selected {
|
||||||
|
background: #dbeafe;
|
||||||
|
}
|
||||||
|
.doc-table tbody td {
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
.badge {
|
.badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
@@ -140,11 +188,27 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.badge-shakai { background: #d1ecf1; color: #0c5460; }
|
.badge-shakai {
|
||||||
.badge-nounyu { background: #d4edda; color: #155724; }
|
background: #d1ecf1;
|
||||||
.badge-shoyo { background: #fff3cd; color: #856404; }
|
color: #0c5460;
|
||||||
.badge-unknown { background: #e2e3e5; color: #383d41; }
|
}
|
||||||
.no-data { text-align: center; color: #aaa; padding: 40px; }
|
.badge-nounyu {
|
||||||
|
background: #d4edda;
|
||||||
|
color: #155724;
|
||||||
|
}
|
||||||
|
.badge-shoyo {
|
||||||
|
background: #fff3cd;
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
.badge-unknown {
|
||||||
|
background: #e2e3e5;
|
||||||
|
color: #383d41;
|
||||||
|
}
|
||||||
|
.no-data {
|
||||||
|
text-align: center;
|
||||||
|
color: #aaa;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── 詳細パネル ── */
|
/* ── 詳細パネル ── */
|
||||||
#detail-panel {
|
#detail-panel {
|
||||||
@@ -156,14 +220,19 @@
|
|||||||
padding: 24px;
|
padding: 24px;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#detail-panel.visible { display: block; }
|
#detail-panel.visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.detail-header {
|
.detail-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.detail-header h2 { margin: 0; font-size: 18px; }
|
.detail-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
.detail-close {
|
.detail-close {
|
||||||
background: none;
|
background: none;
|
||||||
border: 1px solid #ced4da;
|
border: 1px solid #ced4da;
|
||||||
@@ -173,7 +242,9 @@
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
}
|
}
|
||||||
.detail-close:hover { background: #f8f9fa; }
|
.detail-close:hover {
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
/* 事業所情報カード */
|
/* 事業所情報カード */
|
||||||
.info-cards {
|
.info-cards {
|
||||||
@@ -189,12 +260,27 @@
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
}
|
}
|
||||||
.info-card .label { font-size: 11px; color: #6c757d; margin-bottom: 4px; }
|
.info-card .label {
|
||||||
.info-card .value { font-size: 14px; font-weight: 600; color: #212529; }
|
font-size: 11px;
|
||||||
|
color: #6c757d;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.info-card .value {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
/* 金額テーブル */
|
/* 金額テーブル */
|
||||||
.amount-section { margin-bottom: 20px; }
|
.amount-section {
|
||||||
.amount-section h3 { font-size: 15px; margin: 0 0 12px; border-left: 3px solid #007bff; padding-left: 8px; }
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.amount-section h3 {
|
||||||
|
font-size: 15px;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
border-left: 3px solid #007bff;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
.amount-grid {
|
.amount-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
@@ -213,7 +299,10 @@
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
.amount-row .amt { font-family: monospace; font-size: 15px; }
|
.amount-row .amt {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 告知額 vs 領収済額 サイドバイサイド */
|
/* 告知額 vs 領収済額 サイドバイサイド */
|
||||||
.nounyu-compare {
|
.nounyu-compare {
|
||||||
@@ -222,17 +311,32 @@
|
|||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@media (max-width: 640px) { .nounyu-compare { grid-template-columns: 1fr; } }
|
@media (max-width: 640px) {
|
||||||
|
.nounyu-compare {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
.nounyu-box {
|
.nounyu-box {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
.nounyu-box.kokuchi { background: #fff3cd; border: 1px solid #ffc107; }
|
.nounyu-box.kokuchi {
|
||||||
.nounyu-box.ryoshu { background: #d4edda; border: 1px solid #28a745; }
|
background: #fff3cd;
|
||||||
.nounyu-box h4 { margin: 0 0 12px; font-size: 14px; }
|
border: 1px solid #ffc107;
|
||||||
|
}
|
||||||
|
.nounyu-box.ryoshu {
|
||||||
|
background: #d4edda;
|
||||||
|
border: 1px solid #28a745;
|
||||||
|
}
|
||||||
|
.nounyu-box h4 {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 賞与明細テーブル */
|
/* 賞与明細テーブル */
|
||||||
.shoyo-table-wrap { overflow-x: auto; }
|
.shoyo-table-wrap {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
.shoyo-table {
|
.shoyo-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@@ -251,17 +355,22 @@
|
|||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
.shoyo-table td.name { text-align: left; font-weight: 600; }
|
.shoyo-table td.name {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
.shoyo-table tfoot td {
|
.shoyo-table tfoot td {
|
||||||
background: #e8f4ff;
|
background: #e8f4ff;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
border-top: 2px solid #007bff;
|
border-top: 2px solid #007bff;
|
||||||
}
|
}
|
||||||
.shoyo-table .empty-cell { color: #ccc; text-align: center; }
|
.shoyo-table .empty-cell {
|
||||||
|
color: #ccc;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>社会保険電子文書ポータル</h1>
|
<h1>社会保険電子文書ポータル</h1>
|
||||||
<a class="back-link" href="payroll.html">← 給与管理メニューに戻る</a>
|
<a class="back-link" href="payroll.html">← 給与管理メニューに戻る</a>
|
||||||
@@ -272,8 +381,11 @@
|
|||||||
<h3>📥 社会保険 ZIP ファイルをここにドロップ</h3>
|
<h3>📥 社会保険 ZIP ファイルをここにドロップ</h3>
|
||||||
<p>またはボタンから選択してください(複数ファイル対応)</p>
|
<p>またはボタンから選択してください(複数ファイル対応)</p>
|
||||||
<input type="file" id="zip-input" accept=".zip" multiple />
|
<input type="file" id="zip-input" accept=".zip" multiple />
|
||||||
<br>
|
<br />
|
||||||
<button class="upload-btn" onclick="document.getElementById('zip-input').click()">
|
<button
|
||||||
|
class="upload-btn"
|
||||||
|
onclick="document.getElementById('zip-input').click()"
|
||||||
|
>
|
||||||
ファイルを選択
|
ファイルを選択
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -292,12 +404,18 @@
|
|||||||
</select>
|
</select>
|
||||||
<select class="filter-select" id="month-select">
|
<select class="filter-select" id="month-select">
|
||||||
<option value="">月(すべて)</option>
|
<option value="">月(すべて)</option>
|
||||||
<option value="1">1月</option><option value="2">2月</option>
|
<option value="1">1月</option>
|
||||||
<option value="3">3月</option><option value="4">4月</option>
|
<option value="2">2月</option>
|
||||||
<option value="5">5月</option><option value="6">6月</option>
|
<option value="3">3月</option>
|
||||||
<option value="7">7月</option><option value="8">8月</option>
|
<option value="4">4月</option>
|
||||||
<option value="9">9月</option><option value="10">10月</option>
|
<option value="5">5月</option>
|
||||||
<option value="11">11月</option><option value="12">12月</option>
|
<option value="6">6月</option>
|
||||||
|
<option value="7">7月</option>
|
||||||
|
<option value="8">8月</option>
|
||||||
|
<option value="9">9月</option>
|
||||||
|
<option value="10">10月</option>
|
||||||
|
<option value="11">11月</option>
|
||||||
|
<option value="12">12月</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -316,7 +434,9 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="doc-list-body">
|
<tbody id="doc-list-body">
|
||||||
<tr><td colspan="7" class="no-data">データを読み込んでいます...</td></tr>
|
<tr>
|
||||||
|
<td colspan="7" class="no-data">データを読み込んでいます...</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -338,27 +458,33 @@ let selectedDocId = null;
|
|||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
// ページ初期化
|
// ページ初期化
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
checkAuth();
|
checkAuth();
|
||||||
loadDocuments();
|
loadDocuments();
|
||||||
loadFilterOptions();
|
loadFilterOptions();
|
||||||
initUploadZone();
|
initUploadZone();
|
||||||
|
|
||||||
document.getElementById('type-tabs').addEventListener('click', e => {
|
document.getElementById("type-tabs").addEventListener("click", (e) => {
|
||||||
const tab = e.target.closest('.type-tab');
|
const tab = e.target.closest(".type-tab");
|
||||||
if (!tab) return;
|
if (!tab) return;
|
||||||
document.querySelectorAll('.type-tab').forEach(t => t.classList.remove('active'));
|
document
|
||||||
tab.classList.add('active');
|
.querySelectorAll(".type-tab")
|
||||||
|
.forEach((t) => t.classList.remove("active"));
|
||||||
|
tab.classList.add("active");
|
||||||
currentFilter.type = tab.dataset.type;
|
currentFilter.type = tab.dataset.type;
|
||||||
loadDocuments();
|
loadDocuments();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('year-select').addEventListener('change', e => {
|
document
|
||||||
|
.getElementById("year-select")
|
||||||
|
.addEventListener("change", (e) => {
|
||||||
currentFilter.year = e.target.value;
|
currentFilter.year = e.target.value;
|
||||||
loadDocuments();
|
loadDocuments();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('month-select').addEventListener('change', e => {
|
document
|
||||||
|
.getElementById("month-select")
|
||||||
|
.addEventListener("change", (e) => {
|
||||||
currentFilter.month = e.target.value;
|
currentFilter.month = e.target.value;
|
||||||
loadDocuments();
|
loadDocuments();
|
||||||
});
|
});
|
||||||
@@ -369,49 +495,62 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
async function loadDocuments() {
|
async function loadDocuments() {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
if (currentFilter.type) params.set('doc_type', currentFilter.type);
|
if (currentFilter.type) params.set("doc_type", currentFilter.type);
|
||||||
if (currentFilter.year) params.set('year', currentFilter.year);
|
if (currentFilter.year) params.set("year", currentFilter.year);
|
||||||
if (currentFilter.month) params.set('month', currentFilter.month);
|
if (currentFilter.month) params.set("month", currentFilter.month);
|
||||||
|
|
||||||
const url = `${API}/nenkin/documents${params.toString() ? '?' + params : ''}`;
|
const url = `${API}/nenkin/documents${params.toString() ? "?" + params : ""}`;
|
||||||
try {
|
try {
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
const docs = await res.json();
|
const docs = await res.json();
|
||||||
renderDocList(docs);
|
renderDocList(docs);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.getElementById('doc-list-body').innerHTML =
|
document.getElementById("doc-list-body").innerHTML =
|
||||||
`<tr><td colspan="7" class="no-data" style="color:#dc3545">読み込みエラー: ${e.message}</td></tr>`;
|
`<tr><td colspan="7" class="no-data" style="color:#dc3545">読み込みエラー: ${e.message}</td></tr>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDocList(docs) {
|
function renderDocList(docs) {
|
||||||
const tbody = document.getElementById('doc-list-body');
|
const tbody = document.getElementById("doc-list-body");
|
||||||
if (!docs.length) {
|
if (!docs.length) {
|
||||||
tbody.innerHTML = '<tr><td colspan="7" class="no-data">文書が登録されていません</td></tr>';
|
tbody.innerHTML =
|
||||||
|
'<tr><td colspan="7" class="no-data">文書が登録されていません</td></tr>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody.innerHTML = docs.map(d => {
|
tbody.innerHTML = docs
|
||||||
const period = d.purpose_year && d.purpose_month
|
.map((d) => {
|
||||||
|
const period =
|
||||||
|
d.purpose_year && d.purpose_month
|
||||||
? `${d.purpose_year}年${d.purpose_month}月`
|
? `${d.purpose_year}年${d.purpose_month}月`
|
||||||
: '−';
|
: "−";
|
||||||
const issueDate = d.issue_date ? d.issue_date.replace(/-/g, '/') : '−';
|
const issueDate = d.issue_date
|
||||||
const uploadedAt = d.uploaded_at ? d.uploaded_at.slice(0, 16).replace('T', ' ') : '−';
|
? d.issue_date.replace(/-/g, "/")
|
||||||
const selected = d.id === selectedDocId ? 'selected' : '';
|
: "−";
|
||||||
|
const uploadedAt = d.uploaded_at
|
||||||
|
? d.uploaded_at.slice(0, 16).replace("T", " ")
|
||||||
|
: "−";
|
||||||
|
const selected = d.id === selectedDocId ? "selected" : "";
|
||||||
return `<tr class="${selected}" onclick="loadDetail(${d.id})" data-id="${d.id}">
|
return `<tr class="${selected}" onclick="loadDetail(${d.id})" data-id="${d.id}">
|
||||||
<td>${badgeHtml(d.document_type, d.document_type_name)}</td>
|
<td>${badgeHtml(d.document_type, d.document_type_name)}</td>
|
||||||
<td>${period}</td>
|
<td>${period}</td>
|
||||||
<td>${escHtml(d.office_name || '−')}</td>
|
<td>${escHtml(d.office_name || "−")}</td>
|
||||||
<td><small>${escHtml(d.office_kigo || '')} ${escHtml(d.office_number || '')}</small></td>
|
<td><small>${escHtml(d.office_kigo || "")} ${escHtml(d.office_number || "")}</small></td>
|
||||||
<td>${escHtml(d.nenkin_jimusho || '−')}</td>
|
<td>${escHtml(d.nenkin_jimusho || "−")}</td>
|
||||||
<td>${issueDate}</td>
|
<td>${issueDate}</td>
|
||||||
<td><small>${uploadedAt}</small></td>
|
<td><small>${uploadedAt}</small></td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}).join('');
|
})
|
||||||
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function badgeHtml(type, name) {
|
function badgeHtml(type, name) {
|
||||||
const cls = {SHAKAI:'badge-shakai', NOUNYU:'badge-nounyu', SHOYO:'badge-shoyo'}[type] || 'badge-unknown';
|
const cls =
|
||||||
|
{
|
||||||
|
SHAKAI: "badge-shakai",
|
||||||
|
NOUNYU: "badge-nounyu",
|
||||||
|
SHOYO: "badge-shoyo",
|
||||||
|
}[type] || "badge-unknown";
|
||||||
return `<span class="badge ${cls}">${escHtml(name || type)}</span>`;
|
return `<span class="badge ${cls}">${escHtml(name || type)}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,11 +561,14 @@ async function loadFilterOptions() {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(`${API}/nenkin/filter-options`);
|
const res = await fetch(`${API}/nenkin/filter-options`);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const sel = document.getElementById('year-select');
|
const sel = document.getElementById("year-select");
|
||||||
const years = [...new Set(data.periods.map(p => p.purpose_year))].sort((a,b) => b-a);
|
const years = [
|
||||||
years.forEach(y => {
|
...new Set(data.periods.map((p) => p.purpose_year)),
|
||||||
const opt = document.createElement('option');
|
].sort((a, b) => b - a);
|
||||||
opt.value = y; opt.textContent = `${y}年`;
|
years.forEach((y) => {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.value = y;
|
||||||
|
opt.textContent = `${y}年`;
|
||||||
sel.appendChild(opt);
|
sel.appendChild(opt);
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@@ -438,8 +580,8 @@ async function loadFilterOptions() {
|
|||||||
async function loadDetail(docId) {
|
async function loadDetail(docId) {
|
||||||
// 選択行のハイライト
|
// 選択行のハイライト
|
||||||
selectedDocId = docId;
|
selectedDocId = docId;
|
||||||
document.querySelectorAll('.doc-table tbody tr').forEach(tr => {
|
document.querySelectorAll(".doc-table tbody tr").forEach((tr) => {
|
||||||
tr.classList.toggle('selected', parseInt(tr.dataset.id) === docId);
|
tr.classList.toggle("selected", parseInt(tr.dataset.id) === docId);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -453,18 +595,21 @@ async function loadDetail(docId) {
|
|||||||
|
|
||||||
function closeDetail() {
|
function closeDetail() {
|
||||||
selectedDocId = null;
|
selectedDocId = null;
|
||||||
document.getElementById('detail-panel').classList.remove('visible');
|
document.getElementById("detail-panel").classList.remove("visible");
|
||||||
document.querySelectorAll('.doc-table tbody tr').forEach(tr => tr.classList.remove('selected'));
|
document
|
||||||
|
.querySelectorAll(".doc-table tbody tr")
|
||||||
|
.forEach((tr) => tr.classList.remove("selected"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDetail({ document: doc, detail }) {
|
function renderDetail({ document: doc, detail }) {
|
||||||
const panel = document.getElementById('detail-panel');
|
const panel = document.getElementById("detail-panel");
|
||||||
const title = document.getElementById('detail-title');
|
const title = document.getElementById("detail-title");
|
||||||
const body = document.getElementById('detail-body');
|
const body = document.getElementById("detail-body");
|
||||||
|
|
||||||
const period = doc.purpose_year && doc.purpose_month
|
const period =
|
||||||
|
doc.purpose_year && doc.purpose_month
|
||||||
? `${doc.purpose_year}年${doc.purpose_month}月分`
|
? `${doc.purpose_year}年${doc.purpose_month}月分`
|
||||||
: '';
|
: "";
|
||||||
title.textContent = `${doc.document_type_name} ${period}`;
|
title.textContent = `${doc.document_type_name} ${period}`;
|
||||||
|
|
||||||
// 共通事業所カード
|
// 共通事業所カード
|
||||||
@@ -472,50 +617,61 @@ function renderDetail({ document: doc, detail }) {
|
|||||||
<div class="info-cards">
|
<div class="info-cards">
|
||||||
<div class="info-card">
|
<div class="info-card">
|
||||||
<div class="label">事業所名</div>
|
<div class="label">事業所名</div>
|
||||||
<div class="value">${escHtml(doc.office_name || '−')}</div>
|
<div class="value">${escHtml(doc.office_name || "−")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card">
|
<div class="info-card">
|
||||||
<div class="label">事業所番号 / 整理記号</div>
|
<div class="label">事業所番号 / 整理記号</div>
|
||||||
<div class="value">${escHtml(doc.office_number || '')} / ${escHtml(doc.office_kigo || '')}</div>
|
<div class="value">${escHtml(doc.office_number || "")} / ${escHtml(doc.office_kigo || "")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-card">
|
<div class="info-card">
|
||||||
<div class="label">担当年金事務所</div>
|
<div class="label">担当年金事務所</div>
|
||||||
<div class="value">${escHtml(doc.nenkin_jimusho || '−')}</div>
|
<div class="value">${escHtml(doc.nenkin_jimusho || "−")}</div>
|
||||||
</div>
|
</div>
|
||||||
${doc.issue_date ? `<div class="info-card">
|
${
|
||||||
|
doc.issue_date
|
||||||
|
? `<div class="info-card">
|
||||||
<div class="label">発行日</div>
|
<div class="label">発行日</div>
|
||||||
<div class="value">${doc.issue_date.replace(/-/g,'/')}</div>
|
<div class="value">${doc.issue_date.replace(/-/g, "/")}</div>
|
||||||
</div>` : ''}
|
</div>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
let typeHtml = '';
|
let typeHtml = "";
|
||||||
if (doc.document_type === 'SHAKAI') {
|
if (doc.document_type === "SHAKAI") {
|
||||||
typeHtml = renderShakai(detail);
|
typeHtml = renderShakai(detail);
|
||||||
} else if (doc.document_type === 'NOUNYU') {
|
} else if (doc.document_type === "NOUNYU") {
|
||||||
typeHtml = renderNounyu(detail);
|
typeHtml = renderNounyu(detail);
|
||||||
} else if (doc.document_type === 'SHOYO') {
|
} else if (doc.document_type === "SHOYO") {
|
||||||
typeHtml = renderShoyo(detail);
|
typeHtml = renderShoyo(detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.innerHTML = infoHtml + typeHtml;
|
body.innerHTML = infoHtml + typeHtml;
|
||||||
panel.classList.add('visible');
|
panel.classList.add("visible");
|
||||||
panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
panel.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
// 社会保険料額情報 (SHAKAI)
|
// 社会保険料額情報 (SHAKAI)
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
function renderShakai(d) {
|
function renderShakai(d) {
|
||||||
const kigen = d.nofu_kigen_date ? d.nofu_kigen_date.replace(/-/g, '/') : '−';
|
const kigen = d.nofu_kigen_date
|
||||||
const addr = [d.office_postcode ? `〒${d.office_postcode}` : '', d.office_address].filter(Boolean).join(' ');
|
? d.nofu_kigen_date.replace(/-/g, "/")
|
||||||
|
: "−";
|
||||||
|
const addr = [
|
||||||
|
d.office_postcode ? `〒${d.office_postcode}` : "",
|
||||||
|
d.office_address,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ");
|
||||||
return `
|
return `
|
||||||
<div class="amount-section">
|
<div class="amount-section">
|
||||||
<h3>保険料額</h3>
|
<h3>保険料額</h3>
|
||||||
<div class="amount-grid">
|
<div class="amount-grid">
|
||||||
${amtRow('健康保険料', d.kenkou_hokenryo)}
|
${amtRow("健康保険料", d.kenkou_hokenryo)}
|
||||||
${amtRow('厚生年金保険料', d.kousei_nenkin_hokenryo)}
|
${amtRow("厚生年金保険料", d.kousei_nenkin_hokenryo)}
|
||||||
${amtRow('子ども・子育て拠出金', d.kodomo_kyoshutsukin)}
|
${amtRow("子ども・子育て拠出金", d.kodomo_kyoshutsukin)}
|
||||||
${amtRow('合 計', d.total, true)}
|
${amtRow("合 計", d.total, true)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-cards">
|
<div class="info-cards">
|
||||||
@@ -523,10 +679,14 @@ function renderShakai(d) {
|
|||||||
<div class="label">納付期限</div>
|
<div class="label">納付期限</div>
|
||||||
<div class="value">${kigen}</div>
|
<div class="value">${kigen}</div>
|
||||||
</div>
|
</div>
|
||||||
${addr ? `<div class="info-card" style="flex:2">
|
${
|
||||||
|
addr
|
||||||
|
? `<div class="info-card" style="flex:2">
|
||||||
<div class="label">事業所所在地</div>
|
<div class="label">事業所所在地</div>
|
||||||
<div class="value">${escHtml(addr)}</div>
|
<div class="value">${escHtml(addr)}</div>
|
||||||
</div>` : ''}
|
</div>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,36 +694,39 @@ function renderShakai(d) {
|
|||||||
// 保険料納入告知額・領収済額 (NOUNYU)
|
// 保険料納入告知額・領収済額 (NOUNYU)
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
function renderNounyu(d) {
|
function renderNounyu(d) {
|
||||||
const kigen = d.kokuchi_nofu_kigen ? d.kokuchi_nofu_kigen.replace(/-/g, '/') : '−';
|
const kigen = d.kokuchi_nofu_kigen
|
||||||
const ryoshuDt = d.ryoshu_date ? d.ryoshu_date.replace(/-/g, '/') : '−';
|
? d.kokuchi_nofu_kigen.replace(/-/g, "/")
|
||||||
const ryoshuPeriod = d.ryoshu_nofu_year && d.ryoshu_nofu_month
|
: "−";
|
||||||
|
const ryoshuDt = d.ryoshu_date ? d.ryoshu_date.replace(/-/g, "/") : "−";
|
||||||
|
const ryoshuPeriod =
|
||||||
|
d.ryoshu_nofu_year && d.ryoshu_nofu_month
|
||||||
? `${d.ryoshu_nofu_year}年${d.ryoshu_nofu_month}月分`
|
? `${d.ryoshu_nofu_year}年${d.ryoshu_nofu_month}月分`
|
||||||
: '−';
|
: "−";
|
||||||
return `
|
return `
|
||||||
<div class="nounyu-compare">
|
<div class="nounyu-compare">
|
||||||
<div class="nounyu-box kokuchi">
|
<div class="nounyu-box kokuchi">
|
||||||
<h4>📋 今月の保険料告知額(納付期限: ${kigen})</h4>
|
<h4>📋 今月の保険料告知額(納付期限: ${kigen})</h4>
|
||||||
<div class="amount-grid">
|
<div class="amount-grid">
|
||||||
${amtRow('健康保険料', d.kokuchi_kenkou)}
|
${amtRow("健康保険料", d.kokuchi_kenkou)}
|
||||||
${amtRow('厚生年金保険料', d.kokuchi_kounen)}
|
${amtRow("厚生年金保険料", d.kokuchi_kounen)}
|
||||||
${amtRow('子ども・子育て拠出金', d.kokuchi_kodomo)}
|
${amtRow("子ども・子育て拠出金", d.kokuchi_kodomo)}
|
||||||
${amtRow('合 計', d.kokuchi_total, true)}
|
${amtRow("合 計", d.kokuchi_total, true)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nounyu-box ryoshu">
|
<div class="nounyu-box ryoshu">
|
||||||
<h4>✅ 前月分領収済額(${ryoshuPeriod}・領収日: ${ryoshuDt})</h4>
|
<h4>✅ 前月分領収済額(${ryoshuPeriod}・領収日: ${ryoshuDt})</h4>
|
||||||
<div class="amount-grid">
|
<div class="amount-grid">
|
||||||
${amtRow('健康保険料', d.ryoshu_kenkou)}
|
${amtRow("健康保険料", d.ryoshu_kenkou)}
|
||||||
${amtRow('厚生年金保険料', d.ryoshu_kounen)}
|
${amtRow("厚生年金保険料", d.ryoshu_kounen)}
|
||||||
${amtRow('子ども・子育て拠出金', d.ryoshu_kodomo)}
|
${amtRow("子ども・子育て拠出金", d.ryoshu_kodomo)}
|
||||||
${amtRow('合 計', d.ryoshu_total, true)}
|
${amtRow("合 計", d.ryoshu_total, true)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-cards">
|
<div class="info-cards">
|
||||||
<div class="info-card">
|
<div class="info-card">
|
||||||
<div class="label">事業所所在地</div>
|
<div class="label">事業所所在地</div>
|
||||||
<div class="value">${escHtml([d.office_postcode ? '〒'+d.office_postcode : '', d.office_address].filter(Boolean).join(' '))}</div>
|
<div class="value">${escHtml([d.office_postcode ? "〒" + d.office_postcode : "", d.office_address].filter(Boolean).join(" "))}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
@@ -572,20 +735,21 @@ function renderNounyu(d) {
|
|||||||
// 賞与保険料算出内訳書 (SHOYO)
|
// 賞与保険料算出内訳書 (SHOYO)
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
function renderShoyo(d) {
|
function renderShoyo(d) {
|
||||||
if (!d || !d.items) return '<p>詳細データなし</p>';
|
if (!d || !d.items) return "<p>詳細データなし</p>";
|
||||||
|
|
||||||
const totKenpo = sum(d.items, 'kenpo_hongetsu');
|
const totKenpo = sum(d.items, "kenpo_hongetsu");
|
||||||
const totKounen = sum(d.items, 'kounen_hongetsu');
|
const totKounen = sum(d.items, "kounen_hongetsu");
|
||||||
const totHKenpo = sum(d.items, 'hyojun_shoyo_kenpo');
|
const totHKenpo = sum(d.items, "hyojun_shoyo_kenpo");
|
||||||
const totHKounen = sum(d.items, 'hyojun_shoyo_kounen');
|
const totHKounen = sum(d.items, "hyojun_shoyo_kounen");
|
||||||
|
|
||||||
const rows = d.items.map(it => {
|
const rows = d.items
|
||||||
|
.map((it) => {
|
||||||
const hassei = it.hassei_date_iso
|
const hassei = it.hassei_date_iso
|
||||||
? it.hassei_date_iso.replace(/-/g, '/')
|
? it.hassei_date_iso.replace(/-/g, "/")
|
||||||
: (it.hassei_ymd || '−');
|
: it.hassei_ymd || "−";
|
||||||
return `<tr>
|
return `<tr>
|
||||||
<td>${escHtml(it.seiri_num || '')}</td>
|
<td>${escHtml(it.seiri_num || "")}</td>
|
||||||
<td class="name">${escHtml(it.shimei || '')}</td>
|
<td class="name">${escHtml(it.shimei || "")}</td>
|
||||||
<td>${hassei}</td>
|
<td>${hassei}</td>
|
||||||
<td>${fmtAmt(it.hyojun_shoyo_kenpo)}</td>
|
<td>${fmtAmt(it.hyojun_shoyo_kenpo)}</td>
|
||||||
<td>${fmtAmt(it.hyojun_shoyo_kounen)}</td>
|
<td>${fmtAmt(it.hyojun_shoyo_kounen)}</td>
|
||||||
@@ -594,7 +758,8 @@ function renderShoyo(d) {
|
|||||||
<td>${fmtAmt(it.kounen_hongetsu)}</td>
|
<td>${fmtAmt(it.kounen_hongetsu)}</td>
|
||||||
<td>${it.kounen_zengetsu ? fmtAmt(it.kounen_zengetsu) : '<span class="empty-cell">−</span>'}</td>
|
<td>${it.kounen_zengetsu ? fmtAmt(it.kounen_zengetsu) : '<span class="empty-cell">−</span>'}</td>
|
||||||
</tr>`;
|
</tr>`;
|
||||||
}).join('');
|
})
|
||||||
|
.join("");
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="info-cards" style="margin-bottom:16px">
|
<div class="info-cards" style="margin-bottom:16px">
|
||||||
@@ -602,10 +767,14 @@ function renderShoyo(d) {
|
|||||||
<div class="label">対象人員</div>
|
<div class="label">対象人員</div>
|
||||||
<div class="value">${d.jin_in_num} 名</div>
|
<div class="value">${d.jin_in_num} 名</div>
|
||||||
</div>
|
</div>
|
||||||
${d.menjyo_hokenryo_ritsu ? `<div class="info-card">
|
${
|
||||||
|
d.menjyo_hokenryo_ritsu
|
||||||
|
? `<div class="info-card">
|
||||||
<div class="label">免除保険料率</div>
|
<div class="label">免除保険料率</div>
|
||||||
<div class="value">${escHtml(d.menjyo_hokenryo_ritsu)}</div>
|
<div class="value">${escHtml(d.menjyo_hokenryo_ritsu)}</div>
|
||||||
</div>` : ''}
|
</div>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="shoyo-table-wrap">
|
<div class="shoyo-table-wrap">
|
||||||
<table class="shoyo-table">
|
<table class="shoyo-table">
|
||||||
@@ -647,36 +816,48 @@ function renderShoyo(d) {
|
|||||||
// アップロードゾーン
|
// アップロードゾーン
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
function initUploadZone() {
|
function initUploadZone() {
|
||||||
const zone = document.getElementById('upload-zone');
|
const zone = document.getElementById("upload-zone");
|
||||||
const input = document.getElementById('zip-input');
|
const input = document.getElementById("zip-input");
|
||||||
|
|
||||||
zone.addEventListener('dragover', e => { e.preventDefault(); zone.classList.add('dragover'); });
|
zone.addEventListener("dragover", (e) => {
|
||||||
zone.addEventListener('dragleave', () => zone.classList.remove('dragover'));
|
|
||||||
zone.addEventListener('drop', e => {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
zone.classList.remove('dragover');
|
zone.classList.add("dragover");
|
||||||
const files = [...e.dataTransfer.files].filter(f => f.name.endsWith('.zip'));
|
});
|
||||||
|
zone.addEventListener("dragleave", () =>
|
||||||
|
zone.classList.remove("dragover"),
|
||||||
|
);
|
||||||
|
zone.addEventListener("drop", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
zone.classList.remove("dragover");
|
||||||
|
const files = [...e.dataTransfer.files].filter((f) =>
|
||||||
|
f.name.endsWith(".zip"),
|
||||||
|
);
|
||||||
if (files.length) uploadFiles(files);
|
if (files.length) uploadFiles(files);
|
||||||
});
|
});
|
||||||
|
|
||||||
input.addEventListener('change', () => {
|
input.addEventListener("change", () => {
|
||||||
const files = [...input.files];
|
const files = [...input.files];
|
||||||
if (files.length) uploadFiles(files);
|
if (files.length) uploadFiles(files);
|
||||||
input.value = '';
|
input.value = "";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadFiles(files) {
|
async function uploadFiles(files) {
|
||||||
const status = document.getElementById('upload-status');
|
const status = document.getElementById("upload-status");
|
||||||
status.innerHTML = `<span style="color:#6c757d">アップロード中... (${files.length}件)</span>`;
|
status.innerHTML = `<span style="color:#6c757d">アップロード中... (${files.length}件)</span>`;
|
||||||
|
|
||||||
let ok = 0, skipped = 0, errors = [];
|
let ok = 0,
|
||||||
|
skipped = 0,
|
||||||
|
errors = [];
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('file', file);
|
fd.append("file", file);
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API}/nenkin/upload`, { method: 'POST', body: fd });
|
const res = await fetch(`${API}/nenkin/upload`, {
|
||||||
|
method: "POST",
|
||||||
|
body: fd,
|
||||||
|
});
|
||||||
const json = await res.json();
|
const json = await res.json();
|
||||||
if (res.status === 409) {
|
if (res.status === 409) {
|
||||||
skipped++;
|
skipped++;
|
||||||
@@ -690,10 +871,12 @@ async function uploadFiles(files) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = '';
|
let msg = "";
|
||||||
if (ok > 0) msg += `<span class="status-ok">✓ ${ok}件登録完了</span> `;
|
if (ok > 0) msg += `<span class="status-ok">✓ ${ok}件登録完了</span> `;
|
||||||
if (skipped > 0) msg += `<span style="color:#856404">⚠ ${skipped}件は既登録のためスキップ</span> `;
|
if (skipped > 0)
|
||||||
if (errors.length) msg += `<span class="status-err">✗ エラー: ${errors.join(' / ')}</span>`;
|
msg += `<span style="color:#856404">⚠ ${skipped}件は既登録のためスキップ</span> `;
|
||||||
|
if (errors.length)
|
||||||
|
msg += `<span class="status-err">✗ エラー: ${errors.join(" / ")}</span>`;
|
||||||
status.innerHTML = msg;
|
status.innerHTML = msg;
|
||||||
|
|
||||||
if (ok > 0) {
|
if (ok > 0) {
|
||||||
@@ -706,16 +889,26 @@ async function uploadFiles(files) {
|
|||||||
// ユーティリティ
|
// ユーティリティ
|
||||||
// ──────────────────────────────────
|
// ──────────────────────────────────
|
||||||
function escHtml(s) {
|
function escHtml(s) {
|
||||||
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
return String(s)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fmtAmt(v) {
|
function fmtAmt(v) {
|
||||||
if (v == null || v === '') return '<span class="empty-cell">−</span>';
|
if (v == null || v === "") return '<span class="empty-cell">−</span>';
|
||||||
return '¥' + Number(v).toLocaleString('ja-JP', { minimumFractionDigits: 0, maximumFractionDigits: 0 });
|
return (
|
||||||
|
"¥" +
|
||||||
|
Number(v).toLocaleString("ja-JP", {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function amtRow(label, value, isTotal = false) {
|
function amtRow(label, value, isTotal = false) {
|
||||||
return `<div class="amount-row${isTotal ? ' total' : ''}">
|
return `<div class="amount-row${isTotal ? " total" : ""}">
|
||||||
<span>${label}</span>
|
<span>${label}</span>
|
||||||
<span class="amt">${fmtAmt(value)}</span>
|
<span class="amt">${fmtAmt(value)}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
@@ -726,10 +919,10 @@ function sum(items, key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showDetailError(msg) {
|
function showDetailError(msg) {
|
||||||
const panel = document.getElementById('detail-panel');
|
const panel = document.getElementById("detail-panel");
|
||||||
document.getElementById('detail-body').innerHTML =
|
document.getElementById("detail-body").innerHTML =
|
||||||
`<p style="color:#dc3545">エラー: ${escHtml(msg)}</p>`;
|
`<p style="color:#dc3545">エラー: ${escHtml(msg)}</p>`;
|
||||||
panel.classList.add('visible');
|
panel.classList.add("visible");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1783,14 +1783,18 @@
|
|||||||
// 源泉税控除対象人数を計算(給与と同じロジック)
|
// 源泉税控除対象人数を計算(給与と同じロジック)
|
||||||
const bDependentCount = employee.dependents
|
const bDependentCount = employee.dependents
|
||||||
? employee.dependents.filter((d) => {
|
? employee.dependents.filter((d) => {
|
||||||
if (d.valid_to && new Date(d.valid_to) < new Date()) return false;
|
if (d.valid_to && new Date(d.valid_to) < new Date())
|
||||||
|
return false;
|
||||||
if (!d.birth_date) return false;
|
if (!d.birth_date) return false;
|
||||||
const birthDate = new Date(d.birth_date);
|
const birthDate = new Date(d.birth_date);
|
||||||
const targetYear = bonus.bonus_year;
|
const targetYear = bonus.bonus_year;
|
||||||
const yearEnd = new Date(targetYear, 11, 31);
|
const yearEnd = new Date(targetYear, 11, 31);
|
||||||
let age = yearEnd.getFullYear() - birthDate.getFullYear();
|
let age = yearEnd.getFullYear() - birthDate.getFullYear();
|
||||||
const monthDiff = yearEnd.getMonth() - birthDate.getMonth();
|
const monthDiff = yearEnd.getMonth() - birthDate.getMonth();
|
||||||
if (monthDiff < 0 || (monthDiff === 0 && yearEnd.getDate() < birthDate.getDate())) {
|
if (
|
||||||
|
monthDiff < 0 ||
|
||||||
|
(monthDiff === 0 && yearEnd.getDate() < birthDate.getDate())
|
||||||
|
) {
|
||||||
age--;
|
age--;
|
||||||
}
|
}
|
||||||
return age >= 16;
|
return age >= 16;
|
||||||
@@ -1969,10 +1973,10 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>賞与種別</label>
|
<label>賞与種別</label>
|
||||||
<select name="bonus_type">
|
<select name="bonus_type">
|
||||||
<option value="夏季賞与" ${bonus.bonus_type === '夏季賞与' ? 'selected' : ''}>夏季賞与</option>
|
<option value="夏季賞与" ${bonus.bonus_type === "夏季賞与" ? "selected" : ""}>夏季賞与</option>
|
||||||
<option value="冬季賞与" ${bonus.bonus_type === '冬季賞与' ? 'selected' : ''}>冬季賞与</option>
|
<option value="冬季賞与" ${bonus.bonus_type === "冬季賞与" ? "selected" : ""}>冬季賞与</option>
|
||||||
<option value="決算賞与" ${bonus.bonus_type === '決算賞与' ? 'selected' : ''}>決算賞与</option>
|
<option value="決算賞与" ${bonus.bonus_type === "決算賞与" ? "selected" : ""}>決算賞与</option>
|
||||||
<option value="その他" ${bonus.bonus_type === 'その他' ? 'selected' : ''}>その他</option>
|
<option value="その他" ${bonus.bonus_type === "その他" ? "selected" : ""}>その他</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2451,7 +2455,7 @@
|
|||||||
const bonusPaymentDate = bonus.payment_date
|
const bonusPaymentDate = bonus.payment_date
|
||||||
? (() => {
|
? (() => {
|
||||||
const d = new Date(bonus.payment_date);
|
const d = new Date(bonus.payment_date);
|
||||||
return `${d.getFullYear()}年${String(d.getMonth()+1).padStart(2,'0')}月${String(d.getDate()).padStart(2,'0')}日`;
|
return `${d.getFullYear()}年${String(d.getMonth() + 1).padStart(2, "0")}月${String(d.getDate()).padStart(2, "0")}日`;
|
||||||
})()
|
})()
|
||||||
: `${bonus.bonus_year}年${String(bonus.bonus_month).padStart(2, "0")}月${getLastDayOfMonth(bonus.bonus_year, bonus.bonus_month)}日`;
|
: `${bonus.bonus_year}年${String(bonus.bonus_month).padStart(2, "0")}月${getLastDayOfMonth(bonus.bonus_year, bonus.bonus_month)}日`;
|
||||||
if (currentKey && currentKey !== currentKey_new) {
|
if (currentKey && currentKey !== currentKey_new) {
|
||||||
|
|||||||
@@ -118,16 +118,17 @@
|
|||||||
>
|
>
|
||||||
<div class="icon">📄</div>
|
<div class="icon">📄</div>
|
||||||
<h2>源泉徴収票</h2>
|
<h2>源泉徴収票</h2>
|
||||||
<p>給与所得の源泉徴収票を発行します(本人用・区役所用・税務署用 各1部)</p>
|
<p>
|
||||||
|
給与所得の源泉徴収票を発行します(本人用・区役所用・税務署用 各1部)
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="menu-card" onclick="location.href = 'nenkin-portal.html'">
|
||||||
class="menu-card"
|
|
||||||
onclick="location.href = 'nenkin-portal.html'"
|
|
||||||
>
|
|
||||||
<div class="icon">📋</div>
|
<div class="icon">📋</div>
|
||||||
<h2>社会保険電子文書</h2>
|
<h2>社会保険電子文書</h2>
|
||||||
<p>日本年金機構からの電子文書(保険料通知・賞与内訳等)を管理します</p>
|
<p>
|
||||||
|
日本年金機構からの電子文書(保険料通知・賞与内訳等)を管理します
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user