Initial commit
This commit is contained in:
141
static/js/add_user.js
Normal file
141
static/js/add_user.js
Normal file
@@ -0,0 +1,141 @@
|
||||
// API 基礎 URL
|
||||
const API_BASE_URL = '/v1/users';
|
||||
|
||||
// DOM 元素
|
||||
const addUserForm = document.getElementById('add-user-form');
|
||||
const nameInput = document.getElementById('name');
|
||||
const emailInput = document.getElementById('email');
|
||||
const ageInput = document.getElementById('age');
|
||||
const saveBtn = document.getElementById('save-btn');
|
||||
const resetBtn = document.getElementById('reset-btn');
|
||||
const cancelBtn = document.getElementById('cancel-btn');
|
||||
const messageDiv = document.getElementById('message');
|
||||
const importForm = document.getElementById('import-form');
|
||||
const importFileInput = document.getElementById('import-file');
|
||||
|
||||
// 頁面載入時設置事件監聽器
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
setupEventListeners();
|
||||
});
|
||||
|
||||
// 設置事件監聽器
|
||||
function setupEventListeners() {
|
||||
// 表單提交事件
|
||||
addUserForm.addEventListener('submit', handleFormSubmit);
|
||||
|
||||
// 重置按鈕事件
|
||||
resetBtn.addEventListener('click', resetForm);
|
||||
|
||||
// 取消按鈕事件
|
||||
cancelBtn.addEventListener('click', () => {
|
||||
window.location.href = 'index.html';
|
||||
});
|
||||
|
||||
// 檔案匯入表單提交事件
|
||||
importForm.addEventListener('submit', handleImportSubmit);
|
||||
}
|
||||
|
||||
// 處理表單提交
|
||||
async function handleFormSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const userData = {
|
||||
name: nameInput.value.trim(),
|
||||
email: emailInput.value.trim(),
|
||||
age: parseInt(ageInput.value)
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(API_BASE_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(userData)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
showMessage('用戶創建成功', 'success');
|
||||
resetForm();
|
||||
|
||||
// 延遲後跳轉回用戶列表頁面
|
||||
setTimeout(() => {
|
||||
window.location.href = 'index.html';
|
||||
}, 2000);
|
||||
} else {
|
||||
showMessage(result.message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存用戶失敗:', error);
|
||||
showMessage('保存用戶失敗', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表單
|
||||
function resetForm() {
|
||||
addUserForm.reset();
|
||||
}
|
||||
|
||||
// 顯示訊息
|
||||
function showMessage(message, type) {
|
||||
messageDiv.textContent = message;
|
||||
messageDiv.className = `message ${type}`;
|
||||
|
||||
// 5 秒後自動隱藏訊息
|
||||
setTimeout(() => {
|
||||
messageDiv.className = 'message';
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// 處理檔案匯入
|
||||
async function handleImportSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!importFileInput.files || importFileInput.files.length === 0) {
|
||||
showMessage('請選擇檔案', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const file = importFileInput.files[0];
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
try {
|
||||
showMessage('正在匯入資料,請稍候...');
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/import`, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
// 顯示匯入結果
|
||||
const successCount = result.data.success_count;
|
||||
const errorCount = result.data.error_count;
|
||||
let message = `匯入成功: ${successCount} 筆資料`;
|
||||
|
||||
if (errorCount > 0) {
|
||||
message += `, 失敗: ${errorCount} 筆資料`;
|
||||
}
|
||||
|
||||
showMessage(message, 'success');
|
||||
|
||||
// 重置表單
|
||||
importForm.reset();
|
||||
|
||||
// 延遲後跳轉回用戶列表頁面
|
||||
setTimeout(() => {
|
||||
window.location.href = 'index.html';
|
||||
}, 3000);
|
||||
} else {
|
||||
showMessage(`匯入失敗: ${result.message}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('匯入錯誤:', error);
|
||||
showMessage('匯入過程中發生錯誤,請稍後再試', 'error');
|
||||
}
|
||||
}
|
337
static/js/script.js
Normal file
337
static/js/script.js
Normal file
@@ -0,0 +1,337 @@
|
||||
// 全局變數
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
let limit = 10;
|
||||
let minAge = null;
|
||||
let maxAge = null;
|
||||
let editMode = false;
|
||||
let users = [];
|
||||
|
||||
// API 基礎 URL
|
||||
const API_BASE_URL = '/v1/users';
|
||||
|
||||
// DOM 元素
|
||||
const usersList = document.getElementById('users-list');
|
||||
const userForm = document.getElementById('user-form');
|
||||
const formTitle = document.getElementById('form-title');
|
||||
const userIdInput = document.getElementById('user-id');
|
||||
const nameInput = document.getElementById('name');
|
||||
const emailInput = document.getElementById('email');
|
||||
const ageInput = document.getElementById('age');
|
||||
const saveBtn = document.getElementById('save-btn');
|
||||
const cancelBtn = document.getElementById('cancel-btn');
|
||||
const minAgeInput = document.getElementById('min-age');
|
||||
const maxAgeInput = document.getElementById('max-age');
|
||||
const filterBtn = document.getElementById('filter-btn');
|
||||
const resetFilterBtn = document.getElementById('reset-filter-btn');
|
||||
const prevPageBtn = document.getElementById('prev-page');
|
||||
const nextPageBtn = document.getElementById('next-page');
|
||||
const currentPageSpan = document.getElementById('current-page');
|
||||
const totalPagesSpan = document.getElementById('total-pages');
|
||||
const pageLimitSelect = document.getElementById('page-limit');
|
||||
const messageDiv = document.getElementById('message');
|
||||
const importForm = document.getElementById('import-form');
|
||||
const importFileInput = document.getElementById('import-file');
|
||||
|
||||
// 頁面載入時獲取用戶列表
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
fetchUsers();
|
||||
setupEventListeners();
|
||||
});
|
||||
|
||||
// 設置事件監聽器
|
||||
function setupEventListeners() {
|
||||
// 表單提交事件
|
||||
userForm.addEventListener('submit', handleFormSubmit);
|
||||
|
||||
// 取消按鈕事件
|
||||
cancelBtn.addEventListener('click', resetForm);
|
||||
|
||||
// 過濾按鈕事件
|
||||
filterBtn.addEventListener('click', () => {
|
||||
minAge = minAgeInput.value ? parseInt(minAgeInput.value) : null;
|
||||
maxAge = maxAgeInput.value ? parseInt(maxAgeInput.value) : null;
|
||||
currentPage = 1;
|
||||
fetchUsers();
|
||||
});
|
||||
|
||||
// 重置過濾按鈕事件
|
||||
resetFilterBtn.addEventListener('click', () => {
|
||||
minAgeInput.value = '';
|
||||
maxAgeInput.value = '';
|
||||
minAge = null;
|
||||
maxAge = null;
|
||||
currentPage = 1;
|
||||
fetchUsers();
|
||||
});
|
||||
|
||||
// 分頁按鈕事件
|
||||
prevPageBtn.addEventListener('click', () => {
|
||||
if (currentPage > 1) {
|
||||
currentPage--;
|
||||
fetchUsers();
|
||||
}
|
||||
});
|
||||
|
||||
nextPageBtn.addEventListener('click', () => {
|
||||
if (currentPage < totalPages) {
|
||||
currentPage++;
|
||||
fetchUsers();
|
||||
}
|
||||
});
|
||||
|
||||
// 每頁顯示數量變更事件
|
||||
pageLimitSelect.addEventListener('change', () => {
|
||||
limit = parseInt(pageLimitSelect.value);
|
||||
currentPage = 1;
|
||||
fetchUsers();
|
||||
});
|
||||
|
||||
// 檔案匯入表單提交事件
|
||||
importForm.addEventListener('submit', handleImportSubmit);
|
||||
}
|
||||
|
||||
// 獲取用戶列表
|
||||
async function fetchUsers() {
|
||||
try {
|
||||
// 構建 URL 查詢參數
|
||||
const params = new URLSearchParams();
|
||||
params.append('page', currentPage);
|
||||
params.append('limit', limit);
|
||||
|
||||
if (minAge !== null) params.append('min_age', minAge);
|
||||
if (maxAge !== null) params.append('max_age', maxAge);
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}?${params.toString()}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
users = result.data.users;
|
||||
renderUsers(users);
|
||||
|
||||
// 更新分頁信息
|
||||
const meta = result.data.meta;
|
||||
totalPages = meta.total_pages;
|
||||
currentPageSpan.textContent = meta.page;
|
||||
totalPagesSpan.textContent = totalPages;
|
||||
|
||||
// 更新分頁按鈕狀態
|
||||
prevPageBtn.disabled = meta.page <= 1;
|
||||
nextPageBtn.disabled = meta.page >= totalPages;
|
||||
} else {
|
||||
showMessage(result.message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('獲取用戶列表失敗:', error);
|
||||
showMessage('獲取用戶列表失敗', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染用戶列表
|
||||
function renderUsers(users) {
|
||||
usersList.innerHTML = '';
|
||||
|
||||
if (users.length === 0) {
|
||||
const emptyRow = document.createElement('tr');
|
||||
emptyRow.innerHTML = `<td colspan="5" style="text-align: center;">沒有找到用戶</td>`;
|
||||
usersList.appendChild(emptyRow);
|
||||
return;
|
||||
}
|
||||
|
||||
users.forEach(user => {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${user.id}</td>
|
||||
<td>${user.name}</td>
|
||||
<td>${user.email}</td>
|
||||
<td>${user.age}</td>
|
||||
<td>
|
||||
<button class="action-btn edit-btn" data-id="${user.id}">編輯</button>
|
||||
<button class="action-btn delete-btn" data-id="${user.id}">刪除</button>
|
||||
</td>
|
||||
`;
|
||||
usersList.appendChild(row);
|
||||
});
|
||||
|
||||
// 添加編輯和刪除按鈕的事件監聽器
|
||||
document.querySelectorAll('.edit-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => editUser(parseInt(btn.dataset.id)));
|
||||
});
|
||||
|
||||
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => deleteUser(parseInt(btn.dataset.id)));
|
||||
});
|
||||
}
|
||||
|
||||
// 處理表單提交
|
||||
async function handleFormSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
// 如果不是編輯模式,重定向到新增用戶頁面
|
||||
if (!editMode) {
|
||||
window.location.href = 'add_user.html';
|
||||
return;
|
||||
}
|
||||
|
||||
const userData = {
|
||||
name: nameInput.value.trim(),
|
||||
email: emailInput.value.trim(),
|
||||
age: parseInt(ageInput.value)
|
||||
};
|
||||
|
||||
try {
|
||||
// 更新用戶
|
||||
const userId = parseInt(userIdInput.value);
|
||||
const url = `${API_BASE_URL}/${userId}`;
|
||||
const method = 'PATCH';
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(userData)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
showMessage(editMode ? '用戶更新成功' : '用戶創建成功', 'success');
|
||||
resetForm();
|
||||
fetchUsers();
|
||||
} else {
|
||||
showMessage(result.message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存用戶失敗:', error);
|
||||
showMessage('保存用戶失敗', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 編輯用戶
|
||||
async function editUser(userId) {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/${userId}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
const user = result.data.user;
|
||||
|
||||
// 填充表單
|
||||
userIdInput.value = user.id;
|
||||
nameInput.value = user.name;
|
||||
emailInput.value = user.email;
|
||||
ageInput.value = user.age;
|
||||
|
||||
// 切換到編輯模式
|
||||
editMode = true;
|
||||
|
||||
// 顯示編輯表單
|
||||
const editFormContainer = document.getElementById('edit-form-container');
|
||||
editFormContainer.style.display = 'block';
|
||||
|
||||
// 滾動到表單
|
||||
editFormContainer.scrollIntoView({ behavior: 'smooth' });
|
||||
} else {
|
||||
showMessage(result.message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('獲取用戶詳情失敗:', error);
|
||||
showMessage('獲取用戶詳情失敗', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 刪除用戶
|
||||
async function deleteUser(userId) {
|
||||
if (!confirm(`確定要刪除 ID 為 ${userId} 的用戶嗎?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/${userId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.status === 204) {
|
||||
showMessage('用戶刪除成功', 'success');
|
||||
fetchUsers();
|
||||
} else {
|
||||
const result = await response.json();
|
||||
showMessage(result.message, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('刪除用戶失敗:', error);
|
||||
showMessage('刪除用戶失敗', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表單
|
||||
function resetForm() {
|
||||
userForm.reset();
|
||||
userIdInput.value = '';
|
||||
editMode = false;
|
||||
|
||||
// 隱藏編輯表單
|
||||
const editFormContainer = document.getElementById('edit-form-container');
|
||||
editFormContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
// 顯示訊息
|
||||
function showMessage(message, type) {
|
||||
messageDiv.textContent = message;
|
||||
messageDiv.className = `message ${type}`;
|
||||
|
||||
// 5 秒後自動隱藏訊息
|
||||
setTimeout(() => {
|
||||
messageDiv.className = 'message';
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// 處理檔案匯入
|
||||
async function handleImportSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!importFileInput.files || importFileInput.files.length === 0) {
|
||||
showMessage('請選擇檔案', true);
|
||||
return;
|
||||
}
|
||||
|
||||
const file = importFileInput.files[0];
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
try {
|
||||
showMessage('正在匯入資料,請稍候...');
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/import`, {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
// 顯示匯入結果
|
||||
const successCount = result.data.success_count;
|
||||
const errorCount = result.data.error_count;
|
||||
let message = `匯入成功: ${successCount} 筆資料`;
|
||||
|
||||
if (errorCount > 0) {
|
||||
message += `, 失敗: ${errorCount} 筆資料`;
|
||||
}
|
||||
|
||||
showMessage(message);
|
||||
|
||||
// 重新載入用戶列表
|
||||
fetchUsers();
|
||||
|
||||
// 重置表單
|
||||
importForm.reset();
|
||||
} else {
|
||||
showMessage(`匯入失敗: ${result.message}`, true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('匯入錯誤:', error);
|
||||
showMessage('匯入過程中發生錯誤,請稍後再試', true);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user