notice-view.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th=http://www.thymeleaf.org>
  3. <head>
  4. <meta charset="utf-8"/>
  5. <meta name="viewport" content="width=device-width,initial-scale=1"/>
  6. <meta name="description" content="포항시 교통정보센터입니다"/>
  7. <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  8. <title>포항시 교통정보센터</title>
  9. <th:block th:include="include/head.html"></th:block>
  10. <link rel="stylesheet" th:href="@{/css/notice.css}">
  11. <script th:src="@{/js/naverEditor/js/HuskyEZCreator.js}" charset="UTF-8"></script>
  12. </head>
  13. <body id="body">
  14. <th:block th:include="include/admin-header.html"></th:block>
  15. <div class="noticeWrap">
  16. <div class="container view">
  17. <h2 class="admin-header">공지사항</h2>
  18. <div class="content admin-view">
  19. <div class="button-box">
  20. <div class="bl-button" onclick="movePath('/phits/notice-list')">목록</div>
  21. <div style="display: flex;">
  22. <div class="bl-button edit-btn" onclick="edit()">편집</div>
  23. <div class="bl-button off save-btn" onclick="save()">저장</div>
  24. <div class="wt-button del-btn" onclick="delEvent()">삭제</div>
  25. <div class="wt-button off x-btn" onclick="cancel()">취소</div>
  26. </div>
  27. </div>
  28. <div class="view-box">
  29. <div>
  30. <input class="title" name="b_subject" placeholder="제목" th:value="${notice.getBSubject()}" readonly>
  31. <div id="b_content" class="b_content"></div>
  32. <textarea id="content" placeholder="내용" style="display: none;" class="b_content" rows="16" name="b_content" readonly></textarea>
  33. <div class="attach-box admin">
  34. <div class="attach">
  35. <div th:if="${notice.getAttachFile() == '||' or #strings.isEmpty(notice.getAttachFile())}">첨부파일 없음</div>
  36. <div class="attach-file" th:if="${notice.getAttachFile() != '||' and not #strings.isEmpty(notice.getAttachFile())}"
  37. th:each="item, i : ${#strings.arraySplit(notice.getAttachFile(), '|')}"
  38. th:text="${item}" th:title="${item + ' 다운로드'}"
  39. th:onclick="attachFileDownload([[${i.index}]], [[${notice.getBoardNo()}]], [[${notice.getAttachFileId()}]],[[${item}]])"
  40. ></div>
  41. </div>
  42. <input type="file" name="attachFile" id="attach-file">
  43. <label for="hmpgDsplEn">표출여부</label>
  44. <input type="checkbox" id="hmpgDsplEn" name="hmpgDsplEn" th:if="${notice.getHmpgDsplEn() == 1}" checked disabled>
  45. <input type="checkbox" id="hmpgDsplEn" name="hmpgDsplEn" th:if="${notice.getHmpgDsplEn() == 0}" disabled>
  46. <div class="bl-button off attach-btn" onclick="attachFile()">파일첨부</div>
  47. </div>
  48. </div>
  49. </div>
  50. </div>
  51. </div>
  52. </div>
  53. <th:block th:include="include/footer.html"></th:block>
  54. <div class="modal loading">
  55. <img class="loading-img" width="150" height="150" src="/images/background/loading.png" alt="로딩 이미지">
  56. </div>
  57. </body>
  58. </html>
  59. <script th:inline="javascript">
  60. const $delete = $('.del-btn');
  61. const $save = $('.save-btn');
  62. const $edit = $('.edit-btn');
  63. const $cancel = $('.x-btn');
  64. const $title = $('.title');
  65. const $content = $('#content');
  66. const $bContent = $('#b_content');
  67. const $attach = $('.attach');
  68. const $attachBtn = $('.attach-btn');
  69. const $attachFile = $('#attach-file');
  70. const $hmpgDsplEn = $('#hmpgDsplEn');
  71. const notice = [[${notice}]];
  72. let object = [];
  73. $bContent.html(notice.b_content);
  74. let boardAArr = $('.b_content a');
  75. if (boardAArr.length > 0) {
  76. boardAArr.attr({target : '_blank', rel : 'noreferrer noopener'});
  77. }
  78. let isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
  79. if (isMobile) {
  80. $content.attr('rows', 10);
  81. }
  82. function attachFileDownload(index, id, attachFileId, fileName) {
  83. if (attachFileId && attachFileId.split('|').length > 0) {
  84. attachFileId = attachFileId.split('|')[index];
  85. }
  86. const param = {
  87. boardNo : id,
  88. fileId : attachFileId,
  89. }
  90. getDataAsync('/api/notice/attach', 'POST', param, null, (jsonData)=>{
  91. const attachFile = jsonData.attach_file;
  92. const ext = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length);
  93. if (attachFile && attachFile.length > 0) {
  94. if (!ext) {
  95. // return alert("파일 확장자명이 잘못 되었습니다.");
  96. return alertError('파일 확장자명이 잘못 되었습니다.', '공지사항', null);
  97. }
  98. const file = b64ToBlob(attachFile);
  99. const link = document.createElement('a');
  100. link.href = file;
  101. link.download = fileName;
  102. link.click();
  103. }
  104. else {
  105. alertError(jsonData.message, '공지사항', null);
  106. // alert(jsonData.message);
  107. }
  108. }, null);
  109. }
  110. const b64ToBlob = (byteData) => {
  111. const byteCharacters = atob(byteData);
  112. const byteNumbers = new Array(byteCharacters.length);
  113. for (let i = 0; i < byteCharacters.length; i++) {
  114. byteNumbers[i] = byteCharacters.charCodeAt(i);
  115. }
  116. const byteArray = new Uint8Array(byteNumbers);
  117. const blob = new Blob([byteArray]);
  118. const blobUrl = window.URL.createObjectURL(blob);
  119. return blobUrl;
  120. };
  121. function attachFile() {
  122. $attachFile.click();
  123. }
  124. $attachFile.on("change", function() {
  125. const changeFile = $(this)[0].files[0];
  126. if (changeFile) {
  127. const fileName = changeFile.name;
  128. $attach.html('<div><span class="attach-delete" title="첨부파일 제거" onclick="deleteAttach()"></span>' + fileName + '</div>');
  129. }
  130. })
  131. function edit() {
  132. $bContent.css({display: 'none'});
  133. $content.css({display : 'block'});
  134. $content.css({display : 'block'});
  135. initEditEditor();
  136. $delete.addClass('off');
  137. $edit.addClass('off');
  138. $save.removeClass('off');
  139. $cancel.removeClass('off');
  140. $title.addClass('modify');
  141. $content.addClass('modify');
  142. $attach.addClass('modify');
  143. $attachBtn.removeClass('off');
  144. $hmpgDsplEn.attr('disabled', false);
  145. $title.attr('readonly', false);
  146. $content.attr('readonly', false);
  147. const fileName = $attach.children().eq(0).text();
  148. if (fileName !== '첨부파일 없음') {
  149. $attach.html('<div><span class="attach-delete" title="첨부파일 제거" onclick="deleteAttach()"></span>' + fileName + '</div>')
  150. }
  151. }
  152. function deleteAttach() {
  153. $attachFile.val("");
  154. $attach.html("<div>첨부파일 없음</div>");
  155. }
  156. function delEvent() {
  157. const boardNo = [[${notice.getBoardNo()}]];
  158. const bSubject = [[${notice.getBSubject()}]];
  159. const message = '번호 : ' + boardNo + '<br>제목 : ' + bSubject + '<br>게시물을 삭제하시겠습니까?';
  160. alertMessage('red', message, '공지사항', null, ()=>{
  161. getDataAsync('/api/notice/deleteNotice', 'DELETE', {boardNo : boardNo}, null, (jsonData)=>{
  162. if (jsonData) {
  163. alertMessage('blue', jsonData.message, '공지사항', null, ()=>{
  164. if (jsonData.success === "S") {
  165. window.location.href = '/phits/notice-list';
  166. }
  167. }, true)
  168. }
  169. }, null);
  170. });
  171. }
  172. function save() {
  173. object.getById["content"].exec("UPDATE_CONTENTS_FIELD", []);
  174. const file = $attachFile[0].files[0];
  175. const title = $title.val();
  176. const attachNm = notice.attach_file.split("|")[0];
  177. const hmpgDsplEn = $hmpgDsplEn.is(':checked') ? 1 : 0;
  178. let content = $content.val();
  179. if (content && content.length >= 13) {
  180. let trimContent = content.replaceAll("<p>&nbsp;</p>", "");
  181. if (trimContent === "") {
  182. content = "";
  183. }
  184. else {
  185. let spaceGap = content.length - 13;
  186. let spaceEl = content.substring(spaceGap);
  187. if (spaceEl === '<p>&nbsp;</p>') {
  188. content = content.substring(0, spaceGap);
  189. }
  190. }
  191. }
  192. if (notice.b_subject === title && notice.b_content === content && notice.hmpg_dspl_en === hmpgDsplEn) {
  193. if (file) {
  194. if (file.name === attachNm) {
  195. return alertError('수정하신 내용이 없습니다. 내용을 확인해주세요.', '공지사항');
  196. }
  197. }
  198. else {
  199. const attachFileName = $attach.children().eq(0).text();
  200. if ( (attachFileName === "첨부파일 없음" && attachNm === "") || attachFileName === attachNm) {
  201. return alertError('수정하신 내용이 없습니다. 내용을 확인해주세요.', '공지사항');
  202. }
  203. }
  204. }
  205. if (isNull(title)) {
  206. return alertError('공지사항 제목을 입력해주세요', '공지사항', $title);
  207. }
  208. if (isNull(content)) {
  209. return alertError('공지사항 내용을 입력해주세요', '공지사항', $content);
  210. }
  211. const formData = new FormData();
  212. formData.append("boardNo", notice.board_no);
  213. formData.append("bSubject", title);
  214. formData.append("bContent", content);
  215. formData.append("hmpgDsplEn", hmpgDsplEn);
  216. const fileName = $('.attach.modify > div').text();
  217. if (file && file.name) {
  218. formData.append("attachFileNames", file.name + "||");
  219. formData.append("attachFile", file);
  220. }
  221. else if(fileName && fileName !== '첨부파일 없음') {
  222. formData.append("attachFileNames", fileName + '||');
  223. formData.append("attachFile", null);
  224. }
  225. else {
  226. formData.append("attachFile", null);
  227. formData.append("attachFileNames", "||");
  228. }
  229. $.ajax({
  230. url: '/api/notice/modifyNotice',
  231. processData : false,
  232. contentType: false,
  233. data: formData,
  234. type: 'POST',
  235. success: function(jsonData) {
  236. if (jsonData) {
  237. alertMessage('blue', jsonData.message, '공지사항', null, ()=>{
  238. if (jsonData.success === "S") {
  239. window.location.href = "/phits/notice-view/" + notice.board_no;
  240. }
  241. }, true);
  242. }
  243. },
  244. error: function(error) {
  245. sendErrorMsg(error);
  246. }
  247. });
  248. }
  249. function cancel() {
  250. $content.css('display', 'none');
  251. $bContent.css('display', 'block');
  252. $('iframe').remove();
  253. $delete.removeClass('off');
  254. $edit.removeClass('off');
  255. $save.addClass('off');
  256. $cancel.addClass('off');
  257. $title.removeClass('modify');
  258. $content.removeClass('modify');
  259. $attach.removeClass('modify');
  260. $attachBtn.addClass('off');
  261. $hmpgDsplEn.attr('disabled', true);
  262. $title.attr('readonly', true);
  263. $content.attr('readonly', true);
  264. const attachFileNames = notice.attach_file;
  265. if (attachFileNames) {
  266. const attachFileName = attachFileNames.split("|")[0];
  267. let attachText = "<div>첨부파일 없음</div>";
  268. if (attachFileName) {
  269. attachText = `<div class="attach-file" title="${attachFileName} 다운로드"
  270. onclick="attachFileDownload(0, ${notice.board_no}, '${notice.attach_file_id}','${attachFileName}')">
  271. ${attachFileName}
  272. </div>`;
  273. }
  274. $attach.html(attachText);
  275. }
  276. }
  277. function initEditEditor() {
  278. object = [];
  279. nhn.husky.EZCreator.createInIFrame({
  280. oAppRef: object,
  281. elPlaceHolder: "content",
  282. sSkinURI: "/js/naverEditor/SmartEditor2Skin.html",
  283. fCreator: "createSEditor2",
  284. htParams: {
  285. // 툴바 사용 여부 (true:사용/ false:사용하지 않음)
  286. bUseToolbar: true,
  287. // 입력창 크기 조절바 사용 여부 (true:사용/ false:사용하지 않음)
  288. bUseVerticalResizer: true,
  289. // 모드 탭(Editor | HTML | TEXT) 사용 여부 (true:사용/ false:사용하지 않음)
  290. bUseModeChanger: true
  291. },
  292. fOnAppLoad: function () {
  293. //기존 저장된 내용의 text 내용을 에디터상에 뿌려주고자 할때 사용
  294. object.getById["content"].exec("PASTE_HTML", [notice.b_content]);
  295. }
  296. });
  297. //SE2M_Configuration.js
  298. //nhn.husky.SE2M_Configuration.SE2M_Hyperlink -> bAutolink : true // 자동링크 생성 여부
  299. }
  300. $(window).ajaxStart(function () {
  301. $('.modal.loading').css('display', 'flex');
  302. })
  303. .ajaxStop(function () {
  304. $('.modal.loading').css('display', 'none');
  305. });
  306. </script>