This commit is contained in:
mindol1004
2024-10-22 12:11:09 +09:00
parent 868bb01453
commit d63b268765
9 changed files with 126 additions and 117 deletions

View File

@@ -94,7 +94,7 @@ public class QuartzConfig {
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
factory.setJobFactory(jobFactory);
factory.setAutoStartup(true);
factory.setAutoStartup(false);
factory.setWaitForJobsToCompleteOnShutdown(true);
return factory;
}

View File

@@ -2,8 +2,8 @@ import apiClient, { saveAccessToken, removeTokens } from '../common/axios-instan
const signService = {
signIn: async (username, password) => {
const response = await apiClient.post('/sign-in', { username, password });
signIn: async (params) => {
const response = await apiClient.post('/sign-in', params);
const accessToken = response.headers['authorization'].split(' ')[1];
saveAccessToken(accessToken);
return response.data;
@@ -24,8 +24,8 @@ const signService = {
return response.data.data;
},
changePassword: async (userId, email, newPassword) => {
const response = await apiClient.post('/api/user/change-password', { userId, email, newPassword });
changePassword: async (params) => {
const response = await apiClient.post('/api/user/change-password', params);
return response.data.data;
}

View File

@@ -1,5 +1,20 @@
dayjs.locale('ko');
export const addEvents = (eventMap) => {
Object.entries(eventMap).forEach(([selector, { event, handler }]) => {
const elements = selector.startsWith('#') || selector.startsWith('.') || document.getElementsByName(selector).length > 0
? document.querySelectorAll(selector)
: document.querySelectorAll(`[id="${selector}"], [class="${selector}"], [name="${selector}"]`);
elements.forEach(element => {
element.addEventListener(event, (e) => {
e.preventDefault();
handler(e);
});
});
});
}
export const formatDateTime = (dateTimeString) => {
if (!dateTimeString) return '-';
const date = new Date(dateTimeString);

View File

@@ -1,4 +1,4 @@
import { formatDateTime } from '../../common/common.js';
import { addEvents, formatDateTime } from '../../common/common.js';
import dashBoardService from '../../apis/dashboard-api.js';
let selectedMonth;
@@ -40,9 +40,8 @@ const fetchDataAndRender = async () => {
};
const setupEventListeners = () => {
document.getElementById('refreshBtn').addEventListener('click', async (e) => {
fetchDataAndRender();
});
const eventMap = {'refreshBtn': { event: 'click', handler: fetchDataAndRender }};
addEvents(eventMap);
};
const chartOptions = {

View File

@@ -1,3 +1,4 @@
import { addEvents } from '../../common/common.js';
import signService from '../../apis/sign-api.js';
document.addEventListener('DOMContentLoaded', () => {
@@ -5,13 +6,14 @@ document.addEventListener('DOMContentLoaded', () => {
});
const setupEventListeners = () => {
document.getElementById('signOut').addEventListener('click', (e) => {
e.preventDefault();
signService.signOut();
});
const eventMap = {
'signOut': { event: 'click', handler: signService.signOut },
'toggleSidebar': { event: 'click', handler: toggleSidebar }
};
addEvents(eventMap);
};
document.getElementById('toggleSidebar').addEventListener('click', () => {
const body = document.body;
body.classList.toggle("toggle-sidebar");
});
};
const toggleSidebar = () => {
const body = document.body;
body.classList.toggle("toggle-sidebar");
}

View File

@@ -1,4 +1,4 @@
import { formatDateTime } from '../../common/common.js';
import { addEvents, formatDateTime } from '../../common/common.js';
import scheduleService from '../../apis/schedule-api.js';
document.addEventListener('DOMContentLoaded', () => {
@@ -8,16 +8,11 @@ document.addEventListener('DOMContentLoaded', () => {
});
const setupEventListeners = () => {
document.getElementById('searchForm').addEventListener('submit', async (e) => {
e.preventDefault();
fetchDataAndRender();
});
document.getElementById('refreshJobBtn').addEventListener('click', () => {
const confirmUpdate = confirm('스케줄 재적용 하시겠습니까?');
if (confirmUpdate) {
refreshJobs();
}
});
const eventMap = {
'searchForm': { event: 'submit', handler: fetchDataAndRender },
'refreshJobBtn': { event: 'click', handler: refreshJobs }
};
addEvents(eventMap);
};
const fetchDataAndRender = async () => {
@@ -27,10 +22,13 @@ const fetchDataAndRender = async () => {
};
const refreshJobs = async () => {
if (await scheduleService.refreshJob()) {
alert('스케줄이 재적용 되었습니다.');
manageTooltips.hideAll();
fetchDataAndRender();
const confirmRefresh = confirm('스케줄 재적용 하시겠습니까?');
if (confirmRefresh) {
if (await scheduleService.refreshJob()) {
alert('스케줄이 재적용 되었습니다.');
manageTooltips.hideAll();
fetchDataAndRender();
}
}
};
@@ -50,7 +48,8 @@ const updateTable = (jobs) => {
</tr>
`).join('');
document.querySelectorAll('.detail-btn').forEach(btn => btn.addEventListener('click', showJobDetail));
const eventMap = {'.detail-btn': { event: 'click', handler: showJobDetail }};
addEvents(eventMap);
};
const showJobDetail = async ({ target }) => {

View File

@@ -1,3 +1,4 @@
import { addEvents } from '../../common/common.js';
import signService from '../../apis/sign-api.js';
document.addEventListener('DOMContentLoaded', () => {
@@ -12,7 +13,7 @@ const initializeElements = () => {
const setupEventListeners = () => {
const eventMap = {
'signIn': { event: 'click', handler: handleSignIn },
'signinForm': { event: 'submit', handler: handleSignIn },
'signUp': { event: 'click', handler: () => signupModal.show() },
'signupForm': { event: 'submit', handler: handleSignUp },
'signupModal': { event: 'hidden.bs.modal', handler: resetForm },
@@ -20,21 +21,16 @@ const setupEventListeners = () => {
'changePasswordForm': { event: 'submit', handler: handleChangePassword },
'changePasswordModal': { event: 'hidden.bs.modal', handler: resetForm }
};
Object.entries(eventMap).forEach(([id, { event, handler }]) => {
document.getElementById(id)?.addEventListener(event, handler);
});
addEvents(eventMap);
};
const handleSignIn = async () => {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const { status, redirectUrl } = await signService.signIn(username, password);
const handleSignIn = async (e) => {
const params = Object.fromEntries(new FormData(e.target));
const { status, redirectUrl } = await signService.signIn(params);
if (status) window.location.href = redirectUrl;
};
const handleSignUp = async (e) => {
e.preventDefault();
const userId = document.getElementById('userId').value;
const isConflict = await signService.isConflictUserId(userId);
if (!isConflict) {
@@ -46,9 +42,8 @@ const handleSignUp = async (e) => {
};
const handleChangePassword = async (e) => {
e.preventDefault();
const [userId, email, newPassword] = ['changeUserId', 'changeEmail', 'newPassword'].map(id => document.getElementById(id).value);
await signService.changePassword(userId, email, newPassword);
const params = Object.fromEntries(new FormData(e.target));
await signService.changePassword(params);
alert('비밀번호가 변경되었습니다.');
changePasswordModal.hide();
};

View File

@@ -1,4 +1,4 @@
import { getModifiedRows } from '../../common/common.js';
import { addEvents, getModifiedRows } from '../../common/common.js';
import userService from '../../apis/user-api.js';
let users = [];
@@ -10,16 +10,11 @@ document.addEventListener('DOMContentLoaded', () => {
});
const setupEventListeners = () => {
document.getElementById('searchForm').addEventListener('submit', async (e) => {
e.preventDefault();
fetchDataAndRender();
});
document.getElementById('updateUserBtn').addEventListener('click', () => {
const confirmUpdate = confirm('회원정보를 수정하시겠습니까?');
if (confirmUpdate) {
updateUser();
}
});
const eventMap = {
'searchForm': { event: 'submit', handler: fetchDataAndRender },
'updateUserBtn': { event: 'click', handler: updateUser }
};
addEvents(eventMap);
};
const fetchDataAndRender = async () => {
@@ -53,39 +48,41 @@ const updateTable = (users) => {
</tr>
`).join('');
document.querySelectorAll('.delete-btn').forEach(btn => btn.addEventListener('click', (e) => {
const confirmUpdate = confirm('회원정보를 삭제하시겠습니까?');
if (confirmUpdate) {
const {id} = e.target.closest('button').dataset;
deleteUser(id);
}
}));
const eventMap = {'.delete-btn': { event: 'click', handler: deleteUser }};
addEvents(eventMap);
};
const updateUser = async () => {
const updatedUsers = Array.from(document.querySelectorAll('tbody tr')).map(row => {
const id = row.dataset.key;
const selectElement = row.querySelector(`#userRole-${id}`);
const checkboxElement = row.querySelector(`#approved-${id}`);
const userRole = selectElement ? selectElement.value : null;
const isApproved = checkboxElement ? checkboxElement.checked : false;
return {
id: id,
userRole: userRole,
approved: isApproved
};
});
const confirmUpdate = confirm('회원정보를 수정하시겠습니까?');
if (confirmUpdate) {
const updatedUsers = Array.from(document.querySelectorAll('tbody tr')).map(row => {
const id = row.dataset.key;
const selectElement = row.querySelector(`#userRole-${id}`);
const checkboxElement = row.querySelector(`#approved-${id}`);
const userRole = selectElement ? selectElement.value : null;
const isApproved = checkboxElement ? checkboxElement.checked : false;
return {
id: id,
userRole: userRole,
approved: isApproved
};
});
await userService.changeRoleApprove(getModifiedRows(users, updatedUsers, "id"));
alert('회원정보가 수정 되었습니다.');
manageTooltips.hideAll();
fetchDataAndRender();
await userService.changeRoleApprove(getModifiedRows(users, updatedUsers, "id"));
alert('회원정보가 수정 되었습니다.');
manageTooltips.hideAll();
fetchDataAndRender();
}
};
const deleteUser = async (id) => {
await userService.deleteUser(id);
alert('사용자가 삭제되었습니다.');
fetchDataAndRender();
const deleteUser = async (e) => {
const confirmDelete = confirm('사용자를 삭제하시겠습니까?');
if (confirmDelete) {
const { id } = e.target.closest('button').dataset;
await userService.deleteUser(id);
alert('사용자가 삭제되었습니다.');
fetchDataAndRender();
}
};
const manageTooltips = {

View File

@@ -11,41 +11,43 @@
<div class="row justify-content-center align-items-center min-vh-100">
<div class="col-lg-4 col-md-6">
<div class="card shadow-sm">
<div class="card-body p-5">
<div class="text-center mb-4">
<i class="bi bi-person-bounding-box text-primary" style="font-size: 4rem;"></i>
<h2 class="card-title mt-3" style="font-weight: bold;">Sign in to NXCUS-Agent</h2>
</div>
<div class="mb-3">
<div class="input-group">
<span class="input-group-text">
<i class="bi bi-person"></i>
<form id="signinForm">
<div class="card-body p-5">
<div class="text-center mb-4">
<i class="bi bi-person-bounding-box text-primary" style="font-size: 4rem;"></i>
<h2 class="card-title mt-3" style="font-weight: bold;">Sign in to NXCUS-Agent</h2>
</div>
<div class="mb-3">
<div class="input-group">
<span class="input-group-text">
<i class="bi bi-person"></i>
</span>
<input type="text" id="username" name="username" class="form-control" placeholder="아이디" required>
</div>
</div>
<div class="mb-4">
<div class="input-group">
<span class="input-group-text">
<i class="bi bi-lock"></i>
</span>
<input type="password" id="password" name="password" class="form-control" placeholder="비밀번호" required>
</div>
</div>
<div class="d-grid gap-2">
<button id="signIn" type="submit" class="btn btn-primary">
<i class="bi bi-box-arrow-in-right me-2"></i>Sign in
</button>
<button id="signUp" type="button" class="btn btn-outline-secondary">
<i class="bi bi-person-plus-fill me-2"></i>Sign up
</button>
</div>
<div class="text-end mt-3">
<span id="changePassword" class="text-info text-decoration-none" style="cursor: pointer;">
<small><i class="bi bi-key-fill me-1"></i>Reset your password</small>
</span>
<input type="text" id="username" name="username" class="form-control" placeholder="아이디" required>
</div>
</div>
<div class="mb-4">
<div class="input-group">
<span class="input-group-text">
<i class="bi bi-lock"></i>
</span>
<input type="password" id="password" name="password" class="form-control" placeholder="비밀번호" required>
</div>
</div>
<div class="d-grid gap-2">
<button id="signIn" type="button" class="btn btn-primary">
<i class="bi bi-box-arrow-in-right me-2"></i>Sign in
</button>
<button id="signUp" type="button" class="btn btn-outline-secondary">
<i class="bi bi-person-plus-fill me-2"></i>Sign up
</button>
</div>
<div class="text-end mt-3">
<span id="changePassword" class="text-info text-decoration-none" style="cursor: pointer;">
<small><i class="bi bi-key-fill me-1"></i>Reset your password</small>
</span>
</div>
</div>
</form>
</div>
</div>
</div>