修正
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<!doctype html>
|
||||
<!doctype html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
@@ -129,7 +129,7 @@
|
||||
}
|
||||
@media print {
|
||||
@page {
|
||||
margin: 20mm 20mm 25mm 20mm;
|
||||
margin: 5mm 15mm 20mm 15mm;
|
||||
@bottom-center {
|
||||
content: "ページ " counter(page);
|
||||
font-size: 0.75em;
|
||||
@@ -869,6 +869,40 @@
|
||||
<script>
|
||||
const API = "";
|
||||
|
||||
// カスタム通知トースト
|
||||
function showAlert(msg, type) {
|
||||
const configs = {
|
||||
success: {
|
||||
icon: "✔",
|
||||
iconColor: "#22a84b",
|
||||
bg: "#f0faf4",
|
||||
border: "#22a84b",
|
||||
},
|
||||
error: {
|
||||
icon: "✖",
|
||||
iconColor: "#e53935",
|
||||
bg: "#fff5f5",
|
||||
border: "#e53935",
|
||||
},
|
||||
warning: {
|
||||
icon: "⚠",
|
||||
iconColor: "#e67e00",
|
||||
bg: "#fffbf0",
|
||||
border: "#f0a500",
|
||||
},
|
||||
};
|
||||
const c = configs[type] || configs.warning;
|
||||
const container = document.getElementById("alertToastContainer");
|
||||
const toast = document.createElement("div");
|
||||
toast.style.cssText = `pointer-events:auto;display:flex;align-items:flex-start;gap:12px;background:${c.bg};border:1px solid ${c.border};border-left:5px solid ${c.border};border-radius:8px;padding:14px 16px;min-width:280px;max-width:420px;box-shadow:0 4px 16px rgba(0,0,0,0.14);animation:alertSlideIn 0.25s ease;`;
|
||||
const msgEsc = String(msg).replace(/&/g, "&").replace(/</g, "<");
|
||||
toast.innerHTML = `<span style="font-size:26px;color:${c.iconColor};line-height:1;flex-shrink:0;">${c.icon}</span><span style="font-size:14px;color:#333;flex:1;white-space:pre-wrap;margin-top:3px;">${msgEsc}</span><button onclick="this.parentElement.remove()" style="background:none;border:none;cursor:pointer;color:#aaa;font-size:20px;line-height:1;padding:0 0 0 8px;flex-shrink:0;">×</button>`;
|
||||
container.appendChild(toast);
|
||||
setTimeout(() => {
|
||||
if (toast.parentElement) toast.remove();
|
||||
}, 4500);
|
||||
}
|
||||
|
||||
// 千分位カンマフォーマット関数
|
||||
function formatNumberInput(input) {
|
||||
let value = input.value.replace(/,/g, ""); // 既存のカンマを削除
|
||||
@@ -1142,7 +1176,7 @@
|
||||
const res = await fetch(`${API}/accounts`);
|
||||
if (!res.ok) {
|
||||
console.error("❌ API 错误:", res.status);
|
||||
alert("科目一覧の取得に失敗しました");
|
||||
showAlert("科目一覧の取得に失敗しました", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1796,17 +1830,18 @@
|
||||
.value.trim();
|
||||
|
||||
if (dateInput.validity.badInput) {
|
||||
alert(
|
||||
showAlert(
|
||||
"日付が正しくありません。存在しない日付が入力されています(例:11月31日は無効です)",
|
||||
"warning",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!entryDate) {
|
||||
alert("仕訳日を入力してください");
|
||||
showAlert("仕訳日を入力してください", "warning");
|
||||
return;
|
||||
}
|
||||
if (!description) {
|
||||
alert("摘要を入力してください");
|
||||
showAlert("摘要を入力してください", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1824,12 +1859,15 @@
|
||||
if (debit === 0 && credit === 0) return; // 空行スキップ
|
||||
|
||||
if (!accountId) {
|
||||
alert("科目が選択されていない行があります");
|
||||
showAlert("科目が選択されていない行があります", "warning");
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
if (debit > 0 && credit > 0) {
|
||||
alert("1行に借方と貸方の両方を入力することはできません");
|
||||
showAlert(
|
||||
"1行に借方と貸方の両方を入力することはできません",
|
||||
"warning",
|
||||
);
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
@@ -1848,12 +1886,13 @@
|
||||
|
||||
if (!valid) return;
|
||||
if (lines.length < 2) {
|
||||
alert("仕訳明細は2行以上必要です");
|
||||
showAlert("仕訳明細は2行以上必要です", "warning");
|
||||
return;
|
||||
}
|
||||
if (debitSum !== creditSum) {
|
||||
alert(
|
||||
showAlert(
|
||||
`貸借が一致していません(差額:${Math.abs(debitSum - creditSum).toLocaleString()} 円)`,
|
||||
"warning",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -1883,7 +1922,7 @@
|
||||
}
|
||||
|
||||
saveDescriptionToHistory(description);
|
||||
alert("仕訳を登録しました");
|
||||
showAlert("仕訳を登録しました", "success");
|
||||
|
||||
const keep = document.getElementById("detailKeepAfterSubmit").checked;
|
||||
if (!keep) {
|
||||
@@ -1893,7 +1932,7 @@
|
||||
|
||||
searchJournals();
|
||||
} catch (e) {
|
||||
alert("登録エラー: " + e.message);
|
||||
showAlert("登録エラー: " + e.message, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1922,13 +1961,14 @@
|
||||
).value;
|
||||
|
||||
if (entryDateInput.validity.badInput) {
|
||||
alert(
|
||||
showAlert(
|
||||
"日付が正しくありません。存在しない日付が入力されています(例:11月31日は無効です)",
|
||||
"warning",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!entryDate) {
|
||||
alert("仕訳日を入力してください");
|
||||
showAlert("仕訳日を入力してください", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1948,15 +1988,15 @@
|
||||
);
|
||||
|
||||
if (!accountId) {
|
||||
alert("科目を選択してください");
|
||||
showAlert("科目を選択してください", "warning");
|
||||
return;
|
||||
}
|
||||
if (!methodId) {
|
||||
alert("取引手段を選択してください");
|
||||
showAlert("取引手段を選択してください", "warning");
|
||||
return;
|
||||
}
|
||||
if (amount <= 0) {
|
||||
alert("金額を入力してください");
|
||||
showAlert("金額を入力してください", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1978,6 +2018,7 @@
|
||||
account_id: accountId,
|
||||
debit: netAmount,
|
||||
credit: 0,
|
||||
...(taxRateNum !== null ? { tax_rate: taxRateNum } : {}),
|
||||
});
|
||||
|
||||
// 借方: 仮払消費税等(税額)※税額がある場合のみ
|
||||
@@ -1985,7 +2026,7 @@
|
||||
const taxPaidAcc =
|
||||
taxPaidAccounts.length > 0 ? taxPaidAccounts[0] : null;
|
||||
if (!taxPaidAcc) {
|
||||
alert("仮払消費税等の勘定科目が見つかりません");
|
||||
showAlert("仮払消費税等の勘定科目が見つかりません", "error");
|
||||
return;
|
||||
}
|
||||
lines.push({
|
||||
@@ -2015,6 +2056,7 @@
|
||||
account_id: accountId,
|
||||
debit: 0,
|
||||
credit: netAmount,
|
||||
...(taxRateNum !== null ? { tax_rate: taxRateNum } : {}),
|
||||
});
|
||||
|
||||
// 貸方: 仮受消費税等(税額)※税額がある場合のみ
|
||||
@@ -2022,7 +2064,7 @@
|
||||
const taxReceivedAcc =
|
||||
taxReceivedAccounts.length > 0 ? taxReceivedAccounts[0] : null;
|
||||
if (!taxReceivedAcc) {
|
||||
alert("仮受消費税等の勘定科目が見つかりません");
|
||||
showAlert("仮受消費税等の勘定科目が見つかりません", "error");
|
||||
return;
|
||||
}
|
||||
lines.push({
|
||||
@@ -2060,7 +2102,7 @@
|
||||
const errorMsg =
|
||||
errorData.detail || `登録に失敗しました (HTTP ${res.status})`;
|
||||
console.error("Error:", errorData);
|
||||
alert(errorMsg);
|
||||
showAlert(errorMsg, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2069,7 +2111,7 @@
|
||||
// 摘要を履歴に保存
|
||||
saveDescriptionToHistory(description);
|
||||
|
||||
alert(`登録完了(ID=${result.journal_entry_id})`);
|
||||
showAlert(`登録完了(ID=${result.journal_entry_id})`, "success");
|
||||
|
||||
// 「登録後に明細を保持する」チェックボックスを確認
|
||||
const keepDetails = document.getElementById(
|
||||
@@ -2092,8 +2134,9 @@
|
||||
searchJournals();
|
||||
} catch (error) {
|
||||
console.error("送信エラー:", error);
|
||||
alert(
|
||||
showAlert(
|
||||
`エラーが発生しました: ${error.message}\n\nサーバーが起動しているか確認してください。`,
|
||||
"error",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2387,6 +2430,16 @@
|
||||
const conditionsText =
|
||||
conditions.length > 0 ? conditions.join(" | ") : "検索条件: すべて";
|
||||
|
||||
// 印刷日時
|
||||
const printedAt = new Date().toLocaleString("ja-JP", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
});
|
||||
|
||||
// 月ごとにテーブルを生成(印刷用)
|
||||
Object.keys(monthGroups)
|
||||
.sort()
|
||||
@@ -2409,11 +2462,14 @@
|
||||
<table style="margin-bottom: 20px;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="6" style="text-align: center; font-size: 1.2em; padding: 8px; border: none; background: transparent;">仕訳検索結果</th>
|
||||
<th colspan="5" style="text-align: center; font-size: 1.2em; padding: 8px; border: none; background: transparent;">仕訳検索結果</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="5" style="text-align: right; font-weight: normal; font-size: 0.85em; padding: 2px 4px; border: none; background: transparent;">印刷日時: ${printedAt}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th colspan="3" style="text-align: left; font-weight: normal; font-size: 0.9em; padding: 4px; border: none; background: transparent;">${conditionsText}</th>
|
||||
<th colspan="3" style="text-align: right; font-weight: normal; font-size: 0.9em; padding: 4px; border: none; background: transparent;">${monthDisplay}</th>
|
||||
<th colspan="2" style="text-align: right; font-weight: normal; font-size: 0.9em; padding: 4px; border: none; background: transparent;">${monthDisplay}</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="white-space: nowrap;">日付</th>
|
||||
@@ -2421,7 +2477,6 @@
|
||||
<th style="white-space: nowrap;">借方合計</th>
|
||||
<th style="white-space: nowrap;">貸方合計</th>
|
||||
<th>税率</th>
|
||||
<th style="white-space: nowrap;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
@@ -2452,20 +2507,6 @@
|
||||
<td style="text-align:center">${
|
||||
e.tax_rates ? e.tax_rates + "%" : ""
|
||||
}</td>
|
||||
<td style="white-space: nowrap;">
|
||||
<button onclick="viewJournal(${
|
||||
e.journal_entry_id
|
||||
})">表示</button>
|
||||
<button onclick="copyJournal(${
|
||||
e.journal_entry_id
|
||||
})" style="color: green;">複製</button>
|
||||
<button onclick="reverseAndEdit(${
|
||||
e.journal_entry_id
|
||||
})">修正</button>
|
||||
<button onclick="deleteJournalEntry(${
|
||||
e.journal_entry_id
|
||||
})" style="color: red;">削除</button>
|
||||
</td>
|
||||
`;
|
||||
tbody.appendChild(tr);
|
||||
});
|
||||
@@ -2478,7 +2519,7 @@
|
||||
<td colspan="2" style="text-align:right; white-space: nowrap;">合計:</td>
|
||||
<td style="text-align:right; white-space: nowrap;">${monthDebitTotal.toLocaleString()}</td>
|
||||
<td style="text-align:right; white-space: nowrap;">${monthCreditTotal.toLocaleString()}</td>
|
||||
<td colspan="2"></td>
|
||||
<td></td>
|
||||
`;
|
||||
tbody.appendChild(totalRow);
|
||||
|
||||
@@ -2502,7 +2543,7 @@
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
alert(`検索に失敗しました: ${err.message}`);
|
||||
showAlert(`検索に失敗しました: ${err.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2722,7 +2763,7 @@
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
alert(`検索に失敗しました: ${err.message}`);
|
||||
showAlert(`検索に失敗しました: ${err.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2737,7 +2778,7 @@
|
||||
try {
|
||||
const res = await fetch(`${API}/journal-entries/${id}`);
|
||||
if (!res.ok) {
|
||||
alert("仕訳の取得に失敗しました");
|
||||
showAlert("仕訳の取得に失敗しました", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2916,14 +2957,13 @@
|
||||
const dateInput = document.getElementById("entryDate");
|
||||
dateInput.focus();
|
||||
|
||||
alert(
|
||||
`仕訳を複製しました。\n\n` +
|
||||
`※ このコピーは新規仕訳として独立した記録になります。\n` +
|
||||
`※ 日付と摘要を必要に応じて修正してから登録してください。`,
|
||||
showAlert(
|
||||
`仕訳を複製しました。\n\n※ このコピーは新規仕訳として独立した記録になります。\n※ 日付と摘要を必要に応じて修正してから登録してください。`,
|
||||
"success",
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
alert(`エラーが発生しました: ${error.message}`);
|
||||
showAlert(`エラーが発生しました: ${error.message}`, "error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2954,7 +2994,7 @@
|
||||
async function deleteJournalEntry(id) {
|
||||
const reason = prompt("削除理由を入力してください:");
|
||||
if (!reason || reason.trim() === "") {
|
||||
alert("削除理由の入力が必要です");
|
||||
showAlert("削除理由の入力が必要です", "warning");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2970,11 +3010,11 @@
|
||||
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
alert(data.detail || "削除に失敗しました");
|
||||
showAlert(data.detail || "削除に失敗しました", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
alert("削除しました");
|
||||
showAlert("削除しました", "success");
|
||||
searchJournals(); // リストを再読み込み
|
||||
}
|
||||
|
||||
@@ -3056,5 +3096,30 @@
|
||||
await searchJournals();
|
||||
});
|
||||
</script>
|
||||
<div
|
||||
id="alertToastContainer"
|
||||
style="
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
right: 24px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
pointer-events: none;
|
||||
"
|
||||
></div>
|
||||
<style>
|
||||
@keyframes alertSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(40px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user