Files
hr-position-system/login.html
DonaldFang 方士碩 12ceccc3d3 refactor: 新增 ui.js 和 main.js 模組,啟用 ES6 Modules
新增檔案:
- js/ui.js - UI 操作、模組切換、預覽更新、表單資料收集
- js/main.js - 主程式初始化、事件監聽器設置、快捷鍵

更新檔案:
- index.html - 引用 ES6 模組 (type="module")

功能:
 模組切換功能
 標籤頁切換
 表單欄位監聽
 JSON 預覽更新
 快捷鍵支援 (Ctrl+S, Ctrl+N)
 用戶信息載入
 登出功能

注意:
- 大部分 JavaScript 代碼仍在 HTML 中(約 2400 行)
- 已建立核心模組架構,便於後續逐步遷移
- 使用 ES6 Modules,需要通過 HTTP Server 運行

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 17:18:28 +08:00

472 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>那都AI寫的不要問我 - 登入</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft JhengHei', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.login-container {
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
overflow: hidden;
max-width: 450px;
width: 100%;
animation: slideIn 0.5s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.login-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 40px 30px;
text-align: center;
color: white;
}
.logo-container {
margin-bottom: 20px;
}
.logo-container img {
width: 150px;
height: 150px;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
.system-title {
font-size: 28px;
font-weight: bold;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}
.system-subtitle {
font-size: 14px;
opacity: 0.9;
font-style: italic;
}
.login-body {
padding: 40px 30px;
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 500;
font-size: 14px;
}
.form-group input {
width: 100%;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 15px;
transition: all 0.3s;
}
.form-group input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.btn {
width: 100%;
padding: 14px;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
}
.btn-primary:active {
transform: translateY(0);
}
.divider {
text-align: center;
margin: 30px 0 20px 0;
position: relative;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #e0e0e0;
}
.divider span {
background: white;
padding: 0 15px;
color: #999;
font-size: 14px;
position: relative;
z-index: 1;
}
.quick-login {
margin-top: 20px;
}
.quick-login-title {
font-size: 14px;
color: #666;
margin-bottom: 15px;
text-align: center;
font-weight: 500;
}
.btn-test {
background: white;
color: #333;
border: 2px solid #e0e0e0;
font-size: 14px;
padding: 12px;
}
.btn-test:hover {
background: #f8f9fa;
border-color: #667eea;
color: #667eea;
}
.btn-test .role-badge {
display: inline-block;
padding: 3px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.btn-test.user .role-badge {
background: #e3f2fd;
color: #1976d2;
}
.btn-test.admin .role-badge {
background: #fff3e0;
color: #f57c00;
}
.btn-test.superadmin .role-badge {
background: #fce4ec;
color: #c2185b;
}
.footer-note {
margin-top: 25px;
text-align: center;
font-size: 12px;
color: #999;
line-height: 1.6;
}
.icon {
width: 20px;
height: 20px;
fill: currentColor;
}
@media (max-width: 480px) {
.login-container {
margin: 10px;
}
.system-title {
font-size: 24px;
}
.login-body {
padding: 30px 20px;
}
}
</style>
</head>
<body>
<div class="login-container">
<div class="login-header">
<div class="logo-container">
<img src="logo.svg" alt="System Logo">
</div>
<h1 class="system-title">那都AI寫的不要問我</h1>
<p class="system-subtitle">HR Position Management System</p>
</div>
<div class="login-body">
<form id="loginForm" onsubmit="handleLogin(event)">
<div class="form-group">
<label for="username">
<svg class="icon" viewBox="0 0 24 24" style="width: 16px; height: 16px; vertical-align: middle; margin-right: 5px;">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
工號 / 帳號
</label>
<input type="text" id="username" name="username" placeholder="請輸入工號" required>
</div>
<div class="form-group">
<label for="password">
<svg class="icon" viewBox="0 0 24 24" style="width: 16px; height: 16px; vertical-align: middle; margin-right: 5px;">
<path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/>
</svg>
密碼
</label>
<input type="password" id="password" name="password" placeholder="請輸入密碼" required>
</div>
<button type="submit" class="btn btn-primary">
<svg class="icon" viewBox="0 0 24 24">
<path d="M10 17l5-5-5-5v10z" fill="currentColor"/>
</svg>
登入系統
</button>
</form>
<div class="divider">
<span>或使用測試帳號快速登入</span>
</div>
<div class="quick-login">
<p class="quick-login-title">選擇測試角色</p>
<button type="button" class="btn btn-test user" onclick="quickLogin('user')">
<svg class="icon" viewBox="0 0 24 24">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
<span class="role-badge">一般使用者</span>
<span style="flex: 1; text-align: left; margin-left: 10px; font-size: 13px; color: #666;">A003 / employee</span>
</button>
<button type="button" class="btn btn-test admin" onclick="quickLogin('admin')">
<svg class="icon" viewBox="0 0 24 24">
<path d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"/>
</svg>
<span class="role-badge">管理者</span>
<span style="flex: 1; text-align: left; margin-left: 10px; font-size: 13px; color: #666;">A002 / hr_manager</span>
</button>
<button type="button" class="btn btn-test superadmin" onclick="quickLogin('superadmin')">
<svg class="icon" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
</svg>
<span class="role-badge">最高管理者</span>
<span style="flex: 1; text-align: left; margin-left: 10px; font-size: 13px; color: #666;">A001 / admin</span>
</button>
</div>
<div class="footer-note">
這個系統真的都是 AI 寫的<br>
如果有問題... 那就是 AI 的問題 ¯\_(ツ)_/¯
</div>
</div>
</div>
<script>
// 測試帳號資料
const testAccounts = {
'user': {
username: 'A003',
password: 'employee',
role: 'user',
name: '一般員工'
},
'admin': {
username: 'A002',
password: 'hr_manager',
role: 'admin',
name: '人資主管'
},
'superadmin': {
username: 'A001',
password: 'admin',
role: 'superadmin',
name: '系統管理員'
}
};
// 處理一般登入
function handleLogin(event) {
event.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// 簡單的驗證邏輯(實際應該調用後端 API
let validUser = null;
for (const [key, account] of Object.entries(testAccounts)) {
if (account.username === username && account.password === password) {
validUser = account;
break;
}
}
if (validUser) {
// 儲存登入資訊
localStorage.setItem('currentUser', JSON.stringify(validUser));
// 顯示登入成功訊息
showLoginSuccess(validUser.name, validUser.role);
// 延遲跳轉到主頁面
setTimeout(() => {
window.location.href = 'index.html';
}, 1500);
} else {
alert('帳號或密碼錯誤!\n\n提示您可以使用下方的測試帳號快速登入');
}
}
// 快速登入
function quickLogin(role) {
const account = testAccounts[role];
// 填入表單
document.getElementById('username').value = account.username;
document.getElementById('password').value = account.password;
// 儲存登入資訊
localStorage.setItem('currentUser', JSON.stringify(account));
// 顯示登入成功訊息
showLoginSuccess(account.name, account.role);
// 延遲跳轉到主頁面
setTimeout(() => {
window.location.href = 'index.html';
}, 1500);
}
// 顯示登入成功訊息
function showLoginSuccess(name, role) {
const roleNames = {
'user': '一般使用者',
'admin': '管理者',
'superadmin': '最高管理者'
};
// 創建成功訊息元素
const successDiv = document.createElement('div');
successDiv.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px 30px;
border-radius: 10px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
z-index: 9999;
animation: slideInRight 0.5s ease-out;
font-size: 16px;
`;
successDiv.innerHTML = `
<div style="display: flex; align-items: center; gap: 15px;">
<svg viewBox="0 0 24 24" style="width: 32px; height: 32px; fill: white;">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
</svg>
<div>
<div style="font-weight: 600; margin-bottom: 5px;">登入成功!</div>
<div style="font-size: 14px; opacity: 0.9;">${name} (${roleNames[role]})</div>
</div>
</div>
`;
// 添加動畫樣式
const style = document.createElement('style');
style.textContent = `
@keyframes slideInRight {
from {
transform: translateX(400px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
`;
document.head.appendChild(style);
document.body.appendChild(successDiv);
}
// 頁面載入時檢查是否已登入
window.addEventListener('DOMContentLoaded', function() {
const currentUser = localStorage.getItem('currentUser');
if (currentUser) {
const user = JSON.parse(currentUser);
// 如果已經登入,詢問是否要繼續使用或重新登入
const confirm = window.confirm(`偵測到您已經以「${user.name}」身份登入。\n\n是否要繼續使用此帳號?\n(取消將重新登入)`);
if (confirm) {
window.location.href = 'index.html';
} else {
localStorage.removeItem('currentUser');
}
}
});
</script>
</body>
</html>