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.setDataSource(dataSource);
factory.setTransactionManager(transactionManager); factory.setTransactionManager(transactionManager);
factory.setJobFactory(jobFactory); factory.setJobFactory(jobFactory);
factory.setAutoStartup(true); factory.setAutoStartup(false);
factory.setWaitForJobsToCompleteOnShutdown(true); factory.setWaitForJobsToCompleteOnShutdown(true);
return factory; return factory;
} }

View File

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

View File

@@ -1,5 +1,20 @@
dayjs.locale('ko'); 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) => { export const formatDateTime = (dateTimeString) => {
if (!dateTimeString) return '-'; if (!dateTimeString) return '-';
const date = new Date(dateTimeString); 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'; import dashBoardService from '../../apis/dashboard-api.js';
let selectedMonth; let selectedMonth;
@@ -40,9 +40,8 @@ const fetchDataAndRender = async () => {
}; };
const setupEventListeners = () => { const setupEventListeners = () => {
document.getElementById('refreshBtn').addEventListener('click', async (e) => { const eventMap = {'refreshBtn': { event: 'click', handler: fetchDataAndRender }};
fetchDataAndRender(); addEvents(eventMap);
});
}; };
const chartOptions = { const chartOptions = {

View File

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

View File

@@ -1,3 +1,4 @@
import { addEvents } from '../../common/common.js';
import signService from '../../apis/sign-api.js'; import signService from '../../apis/sign-api.js';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
@@ -12,7 +13,7 @@ const initializeElements = () => {
const setupEventListeners = () => { const setupEventListeners = () => {
const eventMap = { const eventMap = {
'signIn': { event: 'click', handler: handleSignIn }, 'signinForm': { event: 'submit', handler: handleSignIn },
'signUp': { event: 'click', handler: () => signupModal.show() }, 'signUp': { event: 'click', handler: () => signupModal.show() },
'signupForm': { event: 'submit', handler: handleSignUp }, 'signupForm': { event: 'submit', handler: handleSignUp },
'signupModal': { event: 'hidden.bs.modal', handler: resetForm }, 'signupModal': { event: 'hidden.bs.modal', handler: resetForm },
@@ -20,21 +21,16 @@ const setupEventListeners = () => {
'changePasswordForm': { event: 'submit', handler: handleChangePassword }, 'changePasswordForm': { event: 'submit', handler: handleChangePassword },
'changePasswordModal': { event: 'hidden.bs.modal', handler: resetForm } 'changePasswordModal': { event: 'hidden.bs.modal', handler: resetForm }
}; };
addEvents(eventMap);
Object.entries(eventMap).forEach(([id, { event, handler }]) => {
document.getElementById(id)?.addEventListener(event, handler);
});
}; };
const handleSignIn = async () => { const handleSignIn = async (e) => {
const username = document.getElementById('username').value; const params = Object.fromEntries(new FormData(e.target));
const password = document.getElementById('password').value; const { status, redirectUrl } = await signService.signIn(params);
const { status, redirectUrl } = await signService.signIn(username, password);
if (status) window.location.href = redirectUrl; if (status) window.location.href = redirectUrl;
}; };
const handleSignUp = async (e) => { const handleSignUp = async (e) => {
e.preventDefault();
const userId = document.getElementById('userId').value; const userId = document.getElementById('userId').value;
const isConflict = await signService.isConflictUserId(userId); const isConflict = await signService.isConflictUserId(userId);
if (!isConflict) { if (!isConflict) {
@@ -46,9 +42,8 @@ const handleSignUp = async (e) => {
}; };
const handleChangePassword = async (e) => { const handleChangePassword = async (e) => {
e.preventDefault(); const params = Object.fromEntries(new FormData(e.target));
const [userId, email, newPassword] = ['changeUserId', 'changeEmail', 'newPassword'].map(id => document.getElementById(id).value); await signService.changePassword(params);
await signService.changePassword(userId, email, newPassword);
alert('비밀번호가 변경되었습니다.'); alert('비밀번호가 변경되었습니다.');
changePasswordModal.hide(); 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'; import userService from '../../apis/user-api.js';
let users = []; let users = [];
@@ -10,16 +10,11 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
const setupEventListeners = () => { const setupEventListeners = () => {
document.getElementById('searchForm').addEventListener('submit', async (e) => { const eventMap = {
e.preventDefault(); 'searchForm': { event: 'submit', handler: fetchDataAndRender },
fetchDataAndRender(); 'updateUserBtn': { event: 'click', handler: updateUser }
}); };
document.getElementById('updateUserBtn').addEventListener('click', () => { addEvents(eventMap);
const confirmUpdate = confirm('회원정보를 수정하시겠습니까?');
if (confirmUpdate) {
updateUser();
}
});
}; };
const fetchDataAndRender = async () => { const fetchDataAndRender = async () => {
@@ -53,39 +48,41 @@ const updateTable = (users) => {
</tr> </tr>
`).join(''); `).join('');
document.querySelectorAll('.delete-btn').forEach(btn => btn.addEventListener('click', (e) => { const eventMap = {'.delete-btn': { event: 'click', handler: deleteUser }};
const confirmUpdate = confirm('회원정보를 삭제하시겠습니까?'); addEvents(eventMap);
if (confirmUpdate) {
const {id} = e.target.closest('button').dataset;
deleteUser(id);
}
}));
}; };
const updateUser = async () => { const updateUser = async () => {
const updatedUsers = Array.from(document.querySelectorAll('tbody tr')).map(row => { const confirmUpdate = confirm('회원정보를 수정하시겠습니까?');
const id = row.dataset.key; if (confirmUpdate) {
const selectElement = row.querySelector(`#userRole-${id}`); const updatedUsers = Array.from(document.querySelectorAll('tbody tr')).map(row => {
const checkboxElement = row.querySelector(`#approved-${id}`); const id = row.dataset.key;
const userRole = selectElement ? selectElement.value : null; const selectElement = row.querySelector(`#userRole-${id}`);
const isApproved = checkboxElement ? checkboxElement.checked : false; const checkboxElement = row.querySelector(`#approved-${id}`);
return { const userRole = selectElement ? selectElement.value : null;
id: id, const isApproved = checkboxElement ? checkboxElement.checked : false;
userRole: userRole, return {
approved: isApproved id: id,
}; userRole: userRole,
}); approved: isApproved
};
});
await userService.changeRoleApprove(getModifiedRows(users, updatedUsers, "id")); await userService.changeRoleApprove(getModifiedRows(users, updatedUsers, "id"));
alert('회원정보가 수정 되었습니다.'); alert('회원정보가 수정 되었습니다.');
manageTooltips.hideAll(); manageTooltips.hideAll();
fetchDataAndRender(); fetchDataAndRender();
}
}; };
const deleteUser = async (id) => { const deleteUser = async (e) => {
await userService.deleteUser(id); const confirmDelete = confirm('사용자를 삭제하시겠습니까?');
alert('사용자가 삭제되었습니다.'); if (confirmDelete) {
fetchDataAndRender(); const { id } = e.target.closest('button').dataset;
await userService.deleteUser(id);
alert('사용자가 삭제되었습니다.');
fetchDataAndRender();
}
}; };
const manageTooltips = { const manageTooltips = {

View File

@@ -11,41 +11,43 @@
<div class="row justify-content-center align-items-center min-vh-100"> <div class="row justify-content-center align-items-center min-vh-100">
<div class="col-lg-4 col-md-6"> <div class="col-lg-4 col-md-6">
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-body p-5"> <form id="signinForm">
<div class="text-center mb-4"> <div class="card-body p-5">
<i class="bi bi-person-bounding-box text-primary" style="font-size: 4rem;"></i> <div class="text-center mb-4">
<h2 class="card-title mt-3" style="font-weight: bold;">Sign in to NXCUS-Agent</h2> <i class="bi bi-person-bounding-box text-primary" style="font-size: 4rem;"></i>
</div> <h2 class="card-title mt-3" style="font-weight: bold;">Sign in to NXCUS-Agent</h2>
<div class="mb-3"> </div>
<div class="input-group"> <div class="mb-3">
<span class="input-group-text"> <div class="input-group">
<i class="bi bi-person"></i> <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> </span>
<input type="text" id="username" name="username" class="form-control" placeholder="아이디" required>
</div> </div>
</div> </div>
<div class="mb-4"> </form>
<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>
</div> </div>
</div> </div>
</div> </div>