commit
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -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");
|
||||||
});
|
}
|
||||||
};
|
|
||||||
@@ -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 }) => {
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user