admin.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. $(function ()
  2. {
  3. /*$('.datepicker').datetimepicker({
  4. dayViewHeaderFormat: 'YYYY MMMM',
  5. format: 'YYYY-MM-DD',
  6. useCurrent: false,
  7. ignoreReadonly: true,
  8. // defaultDate: new Date(),
  9. allowInputToggle: true
  10. });*/
  11. $(".date-picker").datepicker({
  12. dayViewHeaderFormat: 'YYYY MMMM',
  13. format: 'YYYY-MM-DD',
  14. useCurrent: false,
  15. dateFormat: 'yy-mm-dd', // 날짜 포맷이다. 보통 yy-mm-dd 를 많이 사용하는것 같다.
  16. prevText: '이전 달', // 마우스 오버시 이전달 텍스트
  17. nextText: '다음 달', // 마우스 오버시 다음달 텍스트
  18. closeText: '닫기', // 닫기 버튼 텍스트 변경
  19. currentText: '오늘', // 오늘 텍스트 변경
  20. monthNames: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], //한글 캘린더중 월 표시를 위한 부분
  21. monthNamesShort: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], //한글 캘린더 중 월 표시를 위한 부분
  22. dayNames: ['일', '월', '화', '수', '목', '금', '토'], //한글 캘린더 요일 표시 부분
  23. dayNamesShort: ['일', '월', '화', '수', '목', '금', '토'], //한글 요일 표시 부분
  24. dayNamesMin: ['일', '월', '화', '수', '목', '금', '토'], // 한글 요일 표시 부분
  25. showMonthAfterYear: true, // true : 년 월 false : 월 년 순으로 보여줌
  26. yearSuffix: '년', //
  27. showButtonPanel: true, // 오늘로 가는 버튼과 달력 닫기 버튼 보기 옵션
  28. // showOn: "button", // 이미지로 사용 , both : 엘리먼트와 이미지 동시사용
  29. // buttonImage: "/admin/common/images/btn_cal.gif", // 이미지 주소
  30. // buttonImageOnly: true // 이미지만 보이기
  31. onClose: function(value) {
  32. let date = getOnlyDigit(value);
  33. if(date) {
  34. this.value = moment(date, "YYYY-MM-DD").format("YYYY-MM-DD");
  35. }else{
  36. this.value = "";
  37. }
  38. }
  39. });
  40. // 로그아웃
  41. $(document).on("click", "#logout", function() {
  42. $("#logoutForm").submit();
  43. });
  44. var isSubmit = 0;
  45. var $fAdminWrite = $('#fAdminWrite');
  46. var $formOrigin = $fAdminWrite.serialize().trim();
  47. $(window).on('beforeunload', function() {
  48. if ($('#fAdminWrite').serialize().trim() !== $formOrigin && !isSubmit) {
  49. return '저장하지 않은 정보가 있습니다. 저장하지 않은 상태로 이동하시겠습니까 ?';
  50. }
  51. });
  52. $fAdminWrite.submit(function(){
  53. isSubmit = 1;
  54. });
  55. // 이미지 없으면 기본값으로
  56. function imgError() {
  57. event.srcElement.src = BASE_URL + "/images/default/no_image.png";
  58. event.srcElement.style.width = "60";
  59. event.srcElement.style.height = "60";
  60. }
  61. let allImage = document.getElementsByTagName("img");
  62. if (allImage.length > 0) {
  63. for (let i = 0; i < allImage.length; i++) {
  64. allImage[i].onerror = imgError;
  65. }
  66. }
  67. if(typeof select2 != "undefined" && document.querySelectorAll(".select2").length > 0) {
  68. $('.select2').select2();
  69. }
  70. });
  71. $.validator.setDefaults({ // Bootstrap Required.
  72. ignore: [], // hidden
  73. debug: false,
  74. invalidHandler: function (event, validator) {
  75. return onlyInputUnComma(event.currentTarget);
  76. },
  77. submitHandler: function (form) {
  78. return onlyInputUnComma(form);
  79. },
  80. showErrors: function (errorMap, errorList) {
  81. $.each(this.successList, function (index, value) {
  82. let field = $(value);
  83. if (field.is(':hidden')) {
  84. field = field.parent();
  85. }
  86. if (typeof field.tooltip !== "undefined") { // 3.3.7은 destroy 4.0 이후 dispose
  87. field.tooltip('dispose');
  88. }
  89. });
  90. if (errorList.length <= 0) {
  91. $(".tooltip").tooltip("dispose");
  92. }
  93. $.each(errorList, function (index, value) {
  94. let field = $(value.element);
  95. if (field.is(':hidden')) {
  96. field = field.parent();
  97. }
  98. field.tooltip('dispose').tooltip({
  99. placement: 'bottom',
  100. title: value.message,
  101. trigger: 'manual'
  102. }).tooltip('show');
  103. });
  104. }
  105. });
  106. let tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
  107. let tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
  108. return new bootstrap.Tooltip(tooltipTriggerEl)
  109. });
  110. let popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
  111. let popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
  112. return new bootstrap.Popover(popoverTriggerEl)
  113. });
  114. // 목록 버튼상자
  115. function formSubmit(f, actType, actPage, actDesc)
  116. {
  117. if ($("input:checkbox.list-check-box:checked", f).length < 1) {
  118. alert('자료를 하나 이상 선택하세요.');
  119. return false;
  120. }
  121. let msg;
  122. let input = document.createElement('input');
  123. input.setAttribute('type', 'hidden');
  124. input.setAttribute('name', '_method');
  125. switch(actType) {
  126. case 'update' :
  127. msg = '선택한 자료를 정말 수정 하시겠습니까?';
  128. input.setAttribute('value', 'PUT');
  129. break;
  130. case 'save' :
  131. msg = '선택한 자료를 정말 저장 하시겠습니까?';
  132. break;
  133. case 'delete' :
  134. msg = '선택한 자료를 정말 삭제 하시겠습니까?';
  135. input.setAttribute('value', 'DELETE');
  136. break;
  137. case 'recover' :
  138. msg = '선택한 자료를 정말 복원 하시겠습니까?';
  139. break;
  140. case 'trash' :
  141. msg = '선택한 자료를 정말 휴지통으로 이동하시겠습니까?';
  142. break;
  143. case 'action' :
  144. msg = '선택한 자료를 정말 ' + actDesc + ' 처리 하시겠습니까?';
  145. break;
  146. }
  147. if(!confirm(msg)) {
  148. return false;
  149. }
  150. f.appendChild(input);
  151. f.action = actPage;
  152. f.submit();
  153. }
  154. // 선택삭제
  155. function deleteCheck()
  156. {
  157. if (confirm('정말 삭제하시겠습니까? 삭제하신 후에는 복구가 불가능합니다.')) {
  158. return true;
  159. } else {
  160. return false;
  161. }
  162. }
  163. // 모든 라디오, 체크박스 선택/해제
  164. function allCheckThis(obj) {
  165. let that = (obj || null);
  166. if (that) {
  167. if (that.name) {
  168. let checkBoxs = document.getElementsByName(that.name + '[]');
  169. checkBoxs.forEach(function (item, index) {
  170. if (item.checked) {
  171. item.checked = false;
  172. } else {
  173. item.checked = true;
  174. }
  175. });
  176. } else { // name이 설정되지 않으면 근처 input 검색하여 처리
  177. let checkBoxs = $(that).parent().parent().find('input');
  178. checkBoxs.each(function () {
  179. if (this.value != '') {
  180. if (this.checked) {
  181. this.checked = false;
  182. } else {
  183. this.checked = true;
  184. }
  185. }
  186. });
  187. }
  188. }
  189. }
  190. // 팝업창 생성
  191. // http://naiyumie.tistory.com/entry/windowopen-windowshowModalDialog-%EC%98%B5%EC%85%98-%EC%9C%88%EB%8F%84%EC%9A%B0-%EC%98%A4%ED%94%88 사용법 참조
  192. function ShowModalWindow(url, winName, width, height, reload) {
  193. var reload = (reload || true);
  194. /*
  195. var ua = window.navigator.userAgent;
  196. if(ua.indexOf('MSIE') > 0 || ua.indexOf('Trident') > 0){
  197. aWindow = window.showModalDialog(url, self, 'dialogWidth='+width+'px;dialogHeight='+height+'px;scroll:yes;');
  198. if(!reload){
  199. if(typeof aWindow != "undefined" && aWindow) {
  200. document.location.reload();
  201. }
  202. }
  203. }else{
  204. aWindow = window.open(url, winName, 'menubar=no,status=no,toolbar=no,resizable=no,width='+width+',height='+height+',titlebar=no,scrollbars=no,alwaysRaised=yes,directories=no');
  205. }
  206. */
  207. var aWindow = window.open(url, winName, 'menubar=no,status=no,toolbar=no,resizable=no,width=' + width + ',height=' + height + ',titlebar=no,scrollbars=no,alwaysRaised=yes,directories=no');
  208. function bodyLoaded() {
  209. if ((aWindow && aWindow.document && aWindow.document.body)) { // Loaded
  210. aWindow.focus();
  211. } else if (aWindow && !aWindow.closed) { // looks like we have a pop up blocker
  212. aWindow.location.reload(true);
  213. aWindow.focus();
  214. } else {
  215. window.setTimeout(function () {
  216. bodyLoaded();
  217. }, 100);
  218. }
  219. }
  220. bodyLoaded();
  221. return aWindow;
  222. }
  223. // 팝업 크기 자동조절
  224. function popupAutoResize() {
  225. let strWidth;
  226. let strHeight;
  227. // innerWidth / innerHeight / outerWidth / outerHeight 지원 브라우저
  228. if (window.innerWidth && window.innerHeight && window.outerWidth && window.outerHeight) {
  229. strWidth = parseInt(document.body.children[1].scrollWidth) + (window.outerWidth - window.innerWidth);
  230. strHeight = parseInt(document.body.children[1].scrollHeight) + (window.outerHeight - window.innerHeight);
  231. } else {
  232. let strDocumentWidth = $(document).outerWidth();
  233. let strDocumentHeight = $(document).outerHeight();
  234. window.resizeTo(strDocumentWidth, strDocumentHeight);
  235. let strMenuWidth = strDocumentWidth - $(window).width();
  236. let strMenuHeight = strDocumentHeight - $(window).height();
  237. strWidth = parseInt(document.body.children[1].scrollWidth) + strMenuWidth;
  238. strHeight = parseInt(document.body.children[1].scrollHeight) + strMenuHeight;
  239. }
  240. window.resizeTo(strWidth, strHeight);
  241. }
  242. // 모달 열기
  243. function initializeModal(element, url) {
  244. if (typeof (element) == undefined || typeof (url) == undefined) {
  245. return false;
  246. }
  247. let modalPopup = $(element);
  248. modalPopup.load(url, function (response, status, xhr) {
  249. let msg = null;
  250. switch (status) {
  251. case 'error' :
  252. msg = '페이지를 호출 할 수 없습니다.';
  253. break;
  254. case 'timeout' :
  255. msg = '호출 시간이 초과 되었습니다.';
  256. break;
  257. case 'notmodified' :
  258. msg = 'NOT MODIFIED';
  259. break;
  260. case 'parsererror' :
  261. msg = 'PARSE ERROR';
  262. break;
  263. case 'success' :
  264. modalPopup.modal('show');
  265. break;
  266. }
  267. if (msg) {
  268. alert(msg);
  269. return false;
  270. }
  271. });
  272. }
  273. // 검색기간 지정
  274. function setDateRange(type, so, eo)
  275. {
  276. let w = '';
  277. let m = '';
  278. let y = '';
  279. let d = new Date();
  280. let c = new Date(new Date(new Date().toLocaleDateString()).getTime()+24*60*60*1000-1);
  281. let endDate = $.datepicker.formatDate('yy-mm-dd', d);
  282. $((typeof eo !== "undefined" ? eo : '.s-end-date')).val(endDate);
  283. switch(type) {
  284. case '1d' :
  285. d.setDate(d.getDate() - 1);
  286. break;
  287. case '7d' :
  288. w = d.getDate();
  289. d.setDate(w - 7);
  290. break;
  291. case '15d' :
  292. w = d.getDate();
  293. d.setDate(w - 15);
  294. break;
  295. case '1m' :
  296. m = d.getMonth();
  297. d.setMonth(m - 1);
  298. break;
  299. case '2m' :
  300. m = d.getMonth();
  301. d.setMonth(m - 2);
  302. break;
  303. case '3m' :
  304. m = d.getMonth();
  305. d.setMonth(m - 3);
  306. break;
  307. case '6m' :
  308. m = d.getMonth();
  309. d.setMonth(m - 6);
  310. break;
  311. default :
  312. // y = d.getFullYear();
  313. // d.setFullYear(y - 1);
  314. break;
  315. }
  316. let startDate = d.toISOString().split('T')[0];
  317. $((typeof so !== "undefined" ? so : '.s-start-date')).val(startDate);
  318. }
  319. function byteCheck(txt, byte) {
  320. txt = document.getElementById(txt);
  321. byte = document.getElementById(byte);
  322. let i = 0;
  323. let cnt = 0;
  324. let exceed = 0;
  325. let ch = '';
  326. let maxByte = 2000;
  327. for (i = 0; i < txt.value.length; i++) {
  328. ch = txt.value.charAt(i);
  329. if (escape(ch).length > 4) {
  330. cnt += 2;
  331. } else {
  332. cnt += 1;
  333. }
  334. }
  335. byte.innerHTML = cnt;
  336. if (cnt > maxByte) {
  337. exceed = cnt - maxByte;
  338. alert('메시지 내용은 80바이트를 넘을수 없습니다.\n\n작성하신 메세지 내용은 ' + exceed + 'byte 가 초과되었습니다.\n\n초과된 부분은 자동으로 삭제됩니다.');
  339. let tcnt = 0;
  340. let xcnt = 0;
  341. let tmp = txt.value;
  342. for (i = 0; i < tmp.length; i++) {
  343. ch = tmp.charAt(i);
  344. if (escape(ch).length > 4) {
  345. tcnt += 2;
  346. } else {
  347. tcnt += 1;
  348. }
  349. if (tcnt > 80) {
  350. tmp = tmp.substring(0, i);
  351. break;
  352. } else {
  353. xcnt = tcnt;
  354. }
  355. }
  356. txt.value = tmp;
  357. byte.innerHTML = xcnt;
  358. return true;
  359. }
  360. }
  361. $(document).on('click', '.btn-list-update', function () { // 선택수정
  362. formSubmit(document.f_admin_list, 'update', this.dataset.listUpdateUrl);
  363. });
  364. $(document).on('click', '.btn-list-save', function () { // 선택저장
  365. formSubmit(document.f_admin_list, 'save', this.dataset.listSaveUrl);
  366. });
  367. $(document).on('click', '.btn-list-delete', function () { // 선택삭제
  368. formSubmit(document.f_admin_list, 'delete', this.dataset.listDeleteUrl);
  369. });
  370. $(document).on('click', '.btn-list-trash', function () { // 전체삭제
  371. formSubmit(document.f_admin_list, 'trash', this.dataset.listTrashUrl);
  372. });
  373. $(document).on('click', '.btn-list-recover', function () { // 전체복구
  374. formSubmit(document.f_admin_list, 'recover', this.dataset.listRecoverUrl);
  375. });
  376. $(document).on('click', '.btn-list-action', function () { // 전체복구
  377. formSubmit(document.f_admin_list, 'action', this.dataset.listActionUrl, this.dataset.desc);
  378. });
  379. $(document).on('click', '.btn-write-cancel', function () { // 취소하기
  380. location.href = this.value;
  381. });
  382. $(document).on('click', '.btn-popup-cancel', function () { // 팝업 닫기
  383. window.close();
  384. });
  385. $(document).on('click', '.btn-one-delete', function () {
  386. if (confirm("한번 삭제한 자료는 복구할 방법이 없습니다.\n\n정말 삭제하시겠습니까?")) {
  387. document.location.href = $(this).attr('data-one-delete-url');
  388. return true;
  389. } else {
  390. return false;
  391. }
  392. });
  393. $(document).on('click', '.btn-list-truncate', function () {
  394. if (confirm("휴지통 전체를 비웁니다.\n\n비운 자료는 절대 복구가 불가능합니다. \n\n그래도 진행하시겠습니까?")) {
  395. document.location.href = $(this).attr('data-list-truncate-url');
  396. return true;
  397. } else {
  398. return false;
  399. }
  400. });
  401. $(document).on('click', '.btn-one-recover', function () {
  402. if (confirm('선택한 자료를 정말 복원하시겠습니까?')) {
  403. document.location.href = $(this).attr('data-one-recover-url');
  404. return true;
  405. } else {
  406. return false;
  407. }
  408. });
  409. $(document).on('click', '.btn-one-trash', function () {
  410. if (confirm('선택한 자료를 정말 휴지통으로 이동하시겠습니까?')) {
  411. document.location.href = $(this).attr('data-one-trash-url');
  412. return true;
  413. } else {
  414. return false;
  415. }
  416. });
  417. // 목록에 행 선택시 선택관련 버튼 활성화
  418. $(document).on('click', '.list-check-box, #chkAll', function (e) {
  419. setTimeout(function () {
  420. let $checkedCheckboxes = $('.list-check-box:checked');
  421. let $btnListUpdate = $('.btn-list-update');
  422. let $btnListSelected = $('.btn-list-selected');
  423. if ($checkedCheckboxes.length > 0) {
  424. $btnListUpdate.removeClass('disabled');
  425. $btnListSelected.removeClass('disabled');
  426. } else {
  427. $btnListUpdate.addClass('disabled');
  428. $btnListSelected.addClass('disabled');
  429. }
  430. }, 300);
  431. });
  432. // 목록 전체선택
  433. $(document).on('click', '#chkAll', function (e) {
  434. let chk = document.getElementsByClassName('list-check-box');
  435. for (let i = 0; i < chk.length; i++) {
  436. if (e.target.getAttribute('form') == chk[i].getAttribute('form')) {
  437. chk[i].checked = this.checked;
  438. }
  439. }
  440. if (this.checked) {
  441. $('[data-action]').prop('disabled', false);
  442. } else {
  443. $('[data-action]').prop('disabled', true);
  444. }
  445. });
  446. // 부트스트랩 모달 열기
  447. $(document).on("change click", ".modal-popup", function (e) {
  448. if (typeof (this.dataset.href) != undefined && this.dataset.href != '') {
  449. let index = $('.modal-popup').index(this);
  450. let href = this.dataset.href;
  451. if (params('index', href) != 1) {
  452. if (href.indexOf('?') != -1) {
  453. // this.dataset.href = href + '&index=' + index;
  454. } else {
  455. this.dataset.href = href + '/?index=' + index;
  456. }
  457. }
  458. initializeModal('#modal-popup', this.dataset.href);
  459. }
  460. });
  461. // 체크박스 하나만 선택하기
  462. $(document).on('change', '.only-one-checked', function (e) {
  463. if (this.checked) {
  464. let obj = document.getElementsByName(e.target.name);
  465. for (let i = 0; i < obj.length; i++) {
  466. if (obj[i].value != e.target.value) {
  467. obj[i].checked = false;
  468. }
  469. }
  470. }
  471. });
  472. // 데이터 테이블
  473. if ($.isFunction($.fn.dataTable)) {
  474. $.extend(true, $.fn.dataTable.defaults, {
  475. columnDefs: [
  476. {
  477. targets: 'actions',
  478. className: 'actions',
  479. searchable: false,
  480. sortable: false
  481. }
  482. ],
  483. lengthMenu: [5, 10, 25, 50, 100, 250, 500],
  484. pageLength: 25,
  485. language: {
  486. search: '',
  487. searchPlaceholder: 'Search'
  488. },
  489. processing: true,
  490. stateSave: true,
  491. stateDuration: 0,
  492. responsive: true,
  493. stateSaveParams: function (settings, data) {
  494. data.search.search = "";
  495. data.start = 0;
  496. },
  497. stateSaveCallback: function (settings, data) {
  498. localStorage.setItem($(this).attr('id'), JSON.stringify(data));
  499. },
  500. stateLoadCallback: function () {
  501. return JSON.parse(localStorage.getItem($(this).attr('id')));
  502. },
  503. initComplete: function (settings, json) {
  504. let self = this.api();
  505. let filter_input = $('#' + settings.nTable.id + '_filter input').unbind();
  506. let search_button = $('<button type="button" class="btn btn-link btn-sm btn-icon ms-2 mb-1" data-bs-toggle="tooltip" title="Search"><i class="fa fa-fw fa-search"></i></button>').click(function () {
  507. self.search(filter_input.val()).draw();
  508. });
  509. let reset_button = $('<button type="button" class="btn btn-link btn-sm btn-icon mb-1" data-bs-toggle="tooltip" title="Reset"><i class="fa fa-fw fa-undo"></i></button>').click(function () {
  510. filter_input.val('');
  511. search_button.click();
  512. });
  513. $(document).keypress(function (event) {
  514. if (event.which === 13) {
  515. search_button.click();
  516. }
  517. });
  518. $('#' + settings.nTable.id + '_filter').append(search_button, reset_button);
  519. }
  520. });
  521. }
  522. // 체크박스 클릭 시 해당 컨텐츠 내용을 숨김/표시 처리
  523. $(document).on("change", ".content-collapse", function (e) {
  524. let target = e.target.dataset.target;
  525. let content = $("#" + target);
  526. if (this.checked) {
  527. content.show();
  528. } else {
  529. content.hide();
  530. }
  531. });
  532. // 맨 위로
  533. $(document).on("click", "#btnScrollTop", function() {
  534. $("#main").scrollTop(0);
  535. });