This commit is contained in:
admin
2026-05-22 23:05:25 +09:00
parent cea3016fbe
commit e8690d130b
23 changed files with 581 additions and 187 deletions

View File

@@ -2,8 +2,10 @@
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>NJTS 会計システム - メイン</title>
<link rel="stylesheet" href="css/style.css" />
<link rel="stylesheet" href="/css/mobile.css" />
<script src="js/auth.js"></script>
<style>
body {
@@ -79,6 +81,50 @@
.logout-btn:hover {
background: #c82333;
}
.change-pw-btn {
padding: 8px 12px;
background: #6c757d;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.change-pw-btn:hover { background: #545b62; }
/* パスワード変更モーダル */
.modal-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-overlay.active { display: flex; }
.modal-box {
background: white;
border-radius: 10px;
padding: 32px;
width: 360px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
.modal-box h3 { margin: 0 0 20px; }
.modal-box .form-group { margin-bottom: 14px; }
.modal-box label { display: block; margin-bottom: 5px; font-size: 13px; font-weight: 600; color: #333; }
.modal-box input[type="password"] {
width: 100%; padding: 10px; border: 1px solid #ddd;
border-radius: 5px; font-size: 14px; box-sizing: border-box;
}
.modal-box .btn-row { display: flex; gap: 10px; margin-top: 20px; }
.modal-box .btn-row button { flex: 1; padding: 10px; border: none; border-radius: 5px; cursor: pointer; font-size: 14px; }
.modal-box .btn-submit { background: #007bff; color: white; }
.modal-box .btn-submit:hover { background: #0056b3; }
.modal-box .btn-cancel { background: #e9ecef; color: #333; }
.modal-box .btn-cancel:hover { background: #d0d5db; }
.modal-msg { padding: 8px 12px; border-radius: 4px; margin-bottom: 12px; display: none; font-size: 13px; }
.modal-msg.error { background: #fee; color: #c33; border: 1px solid #fcc; }
.modal-msg.success { background: #efe; color: #3a3; border: 1px solid #cfc; }
</style>
</head>
<body>
@@ -86,10 +132,35 @@
<h1>NJTS</h1>
<div class="user-info">
<span>ユーザー: <strong id="username">読み込み中...</strong></span>
<button class="change-pw-btn" onclick="openChangePw()">パスワード変更</button>
<button class="logout-btn" onclick="logout()">ログアウト</button>
</div>
</header>
<!-- パスワード変更モーダル -->
<div class="modal-overlay" id="changePwModal">
<div class="modal-box">
<h3>🔒 パスワード変更</h3>
<div class="modal-msg" id="changePwMsg"></div>
<div class="form-group">
<label>現在のパスワード</label>
<input type="password" id="cpCurrent" placeholder="現在のパスワード" />
</div>
<div class="form-group">
<label>新しいパスワード8文字以上</label>
<input type="password" id="cpNew" placeholder="新しいパスワード" />
</div>
<div class="form-group">
<label>新しいパスワード(確認)</label>
<input type="password" id="cpConfirm" placeholder="もう一度入力" />
</div>
<div class="btn-row">
<button class="btn-submit" onclick="submitChangePw()">変更する</button>
<button class="btn-cancel" onclick="closeChangePw()">キャンセル</button>
</div>
</div>
</div>
<main class="grid">
<section class="card">
<h2>会計システム</h2>
@@ -142,6 +213,56 @@
}
});
// パスワード変更モーダル
function openChangePw() {
document.getElementById("cpCurrent").value = "";
document.getElementById("cpNew").value = "";
document.getElementById("cpConfirm").value = "";
const msg = document.getElementById("changePwMsg");
msg.style.display = "none";
document.getElementById("changePwModal").classList.add("active");
}
function closeChangePw() {
document.getElementById("changePwModal").classList.remove("active");
}
function showChangePwMsg(text, isError) {
const msg = document.getElementById("changePwMsg");
msg.textContent = text;
msg.className = "modal-msg " + (isError ? "error" : "success");
msg.style.display = "block";
}
async function submitChangePw() {
const current = document.getElementById("cpCurrent").value;
const newPw = document.getElementById("cpNew").value;
const confirm = document.getElementById("cpConfirm").value;
const user = getCurrentUser();
if (!current || !newPw || !confirm) {
showChangePwMsg("すべての項目を入力してください", true); return;
}
if (newPw.length < 8) {
showChangePwMsg("新しいパスワードは8文字以上にしてください", true); return;
}
if (newPw !== confirm) {
showChangePwMsg("新しいパスワードが一致しません", true); return;
}
try {
const res = await fetch("/api/users/change-password", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: user.username, current_password: current, new_password: newPw })
});
const data = await res.json();
if (res.ok) {
showChangePwMsg("パスワードを変更しました。再ログインしてください", false);
setTimeout(() => { logout(); }, 2000);
} else {
showChangePwMsg(data.detail || "変更に失敗しました", true);
}
} catch (e) {
showChangePwMsg("エラー: " + e.message, true);
}
}
// dropdown toggle
const toggle = document.getElementById("accountingToggle");
const menu = document.getElementById("accountingMenu");