├── .env.development ├── .env.production ├── .eslintrc.cjs ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── feature_request.yml │ └── improvement_plan.yml ├── pull_request_template.md └── workflows │ └── node.js.yml ├── .gitignore ├── .project ├── Docs └── development-env-setting.md ├── LICENSE ├── README.md ├── index.html ├── jsconfig.json ├── package-lock.json ├── package.json ├── public ├── assets │ └── images │ │ ├── banner_m_01.png │ │ ├── banner_m_02.png │ │ ├── banner_w_01.png │ │ ├── banner_w_02.png │ │ ├── img_business_intro.png │ │ ├── img_business_intro_m.png │ │ ├── img_sample.png │ │ ├── img_sample2.png │ │ ├── img_simple_main.png │ │ ├── img_template_intro.png │ │ ├── logo_footer_m.png │ │ ├── logo_footer_w.png │ │ ├── logo_m.png │ │ ├── logo_w.png │ │ ├── map.png │ │ ├── qrcode.png │ │ ├── reply_arrow.gif │ │ └── sample_pds_list.png ├── index.html └── vite.svg ├── src ├── App.js ├── App.jsx ├── App.test.jsx ├── EgovMain.test.jsx ├── api │ ├── egovFetch.js │ └── egovFetch.jsx ├── assets │ └── react.svg ├── components │ ├── EgovAttachFile.jsx │ ├── EgovCondition.jsx │ ├── EgovContainer.jsx │ ├── EgovError.jsx │ ├── EgovFooter.jsx │ ├── EgovHeader.jsx │ ├── EgovImageGallery.jsx │ ├── EgovInfoPopup.jsx │ ├── EgovLeftNav.jsx │ ├── EgovPaging.jsx │ ├── EgovRadioButton.jsx │ ├── EgovRadioButtonGroup.jsx │ ├── EgovSelect.jsx │ ├── EgovViewTemplate.jsx │ ├── leftmenu │ │ ├── EgovLeftNavAbout.jsx │ │ ├── EgovLeftNavAdmin.jsx │ │ ├── EgovLeftNavInform.jsx │ │ ├── EgovLeftNavIntro.jsx │ │ └── EgovLeftNavSupport.jsx │ └── sns │ │ ├── SnsKakaoBt.jsx │ │ ├── SnsKakaoCallback.jsx │ │ ├── SnsNaverBt.jsx │ │ └── SnsNaverCallback.jsx ├── config.js ├── config │ ├── index.js │ └── index.jsx ├── constants │ ├── code.js │ ├── code.jsx │ ├── url.js │ └── url.jsx ├── css │ ├── base.css │ ├── component.css │ ├── images │ │ ├── bg_btn_calendar.png │ │ ├── bg_ds_t2.png │ │ ├── bg_form_chk.png │ │ ├── bg_form_chk_on.png │ │ ├── bg_form_rdo.png │ │ ├── bg_form_rdo_on.png │ │ ├── ico_address.png │ │ ├── ico_allmenu.png │ │ ├── ico_allmenu_close.png │ │ ├── ico_arrow_black_36x20.png │ │ ├── ico_arrow_gray_15x9.png │ │ ├── ico_arrow_r_gray_4x7.png │ │ ├── ico_arrow_r_gray_9x15.png │ │ ├── ico_arrow_up_gray_16x9.png │ │ ├── ico_bn01.png │ │ ├── ico_bn02.png │ │ ├── ico_bn03.png │ │ ├── ico_bn04.png │ │ ├── ico_call.png │ │ ├── ico_close_black44.png │ │ ├── ico_delete.png │ │ ├── ico_down.png │ │ ├── ico_error.png │ │ ├── ico_file.png │ │ ├── ico_home.png │ │ ├── ico_mail.png │ │ ├── ico_more.png │ │ ├── ico_person.png │ │ ├── ico_plus.png │ │ ├── ico_prev.png │ │ ├── ico_question.png │ │ ├── ico_reply.png │ │ ├── ico_req.png │ │ ├── ico_search_b.png │ │ ├── ico_service_intro1.png │ │ ├── ico_service_intro2.png │ │ ├── ico_subway.png │ │ ├── ico_v.png │ │ ├── icon_google.png │ │ ├── icon_kakao.png │ │ ├── icon_naver.png │ │ └── logo.jpg │ ├── layout.css │ ├── page.css │ └── response.css ├── index.js ├── js │ └── ui.js ├── main.jsx ├── pages │ ├── about │ │ ├── EgovAboutHistory.jsx │ │ ├── EgovAboutLocation.jsx │ │ ├── EgovAboutOrganization.jsx │ │ └── EgovAboutSite.jsx │ ├── admin │ │ ├── board │ │ │ ├── EgovAdminBoardEdit.jsx │ │ │ └── EgovAdminBoardList.jsx │ │ ├── gallery │ │ │ ├── EgovAdminGalleryDetail.jsx │ │ │ ├── EgovAdminGalleryEdit.jsx │ │ │ └── EgovAdminGalleryList.jsx │ │ ├── manager │ │ │ └── EgovAdminPasswordUpdate.jsx │ │ ├── members │ │ │ ├── EgovAdminMemberEdit.jsx │ │ │ └── EgovAdminMemberList.jsx │ │ ├── notice │ │ │ ├── EgovAdminNoticeDetail.jsx │ │ │ ├── EgovAdminNoticeEdit.jsx │ │ │ └── EgovAdminNoticeList.jsx │ │ ├── schedule │ │ │ ├── EgovAdminScheduleDetail.jsx │ │ │ ├── EgovAdminScheduleEdit.jsx │ │ │ └── EgovAdminScheduleList.jsx │ │ └── usage │ │ │ ├── EgovAdminUsageEdit.jsx │ │ │ └── EgovAdminUsageList.jsx │ ├── inform │ │ ├── daily │ │ │ ├── EgovDailyDetail.jsx │ │ │ └── EgovDailyList.jsx │ │ ├── gallery │ │ │ ├── EgovGalleryDetail.jsx │ │ │ ├── EgovGalleryEdit.jsx │ │ │ └── EgovGalleryList.jsx │ │ ├── notice │ │ │ ├── EgovNoticeDetail.jsx │ │ │ ├── EgovNoticeEdit.jsx │ │ │ └── EgovNoticeList.jsx │ │ └── weekly │ │ │ └── EgovWeeklyList.jsx │ ├── intro │ │ ├── EgovIntroService.jsx │ │ └── EgovIntroWork.jsx │ ├── login │ │ ├── EgovLogin.jsx │ │ └── EgovLoginContent.jsx │ ├── main │ │ └── EgovMain.jsx │ ├── mypage │ │ └── EgovMypageEdit.jsx │ └── support │ │ ├── apply │ │ └── EgovSupportApply.jsx │ │ ├── download │ │ ├── EgovDownloadCreate.jsx │ │ ├── EgovDownloadDetail.jsx │ │ └── EgovDownloadList.jsx │ │ └── qna │ │ ├── EgovQnaDetail.jsx │ │ └── EgovQnaList.jsx ├── reportWebVitals.js ├── routes │ └── index.jsx └── utils │ ├── bbsFormVaildator.js │ ├── bbsFormVaildator.jsx │ ├── calc.js │ ├── calc.jsx │ └── storage.js ├── vite.config.js └── vitest.setup.js /.env.development: -------------------------------------------------------------------------------- 1 | # 필수 지정 값 2 | 3 | ## 절대경로 지정 4 | NODE_PATH=src/ 5 | 6 | ## 절대경로 지정 7 | VITE_APP_EGOV_CONTEXT_URL=localhost:8080 8 | 9 | #SNS 간편로그인 변수 10 | VITE_APP_NAVER_CLIENTID=YOUR_CLIENT_ID 11 | VITE_APP_NAVER_CALLBACKURL=http://localhost:3000/login/naver/callback 12 | VITE_APP_STATE=egovframe 13 | VITE_APP_KAKAO_CLIENTID=YOUR_CLIENT_ID 14 | VITE_APP_KAKAO_CALLBACKURL=http://localhost:3000/login/kakao/callback -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # 필수 지정 값 2 | 3 | ## 절대경로 지정 4 | NODE_PATH=src/ 5 | 6 | ## 절대경로 지정 7 | VITE_EGOV_CONTEXT_URL=127.0.0.1:8080 8 | 9 | ## [보안] 소스맵 삭제 10 | GENERATE_SOURCEMAP=false 11 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true, node: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:react/recommended", 7 | "plugin:react/jsx-runtime", 8 | "plugin:react-hooks/recommended", 9 | ], 10 | ignorePatterns: ["dist", ".eslintrc.cjs"], 11 | parserOptions: { ecmaVersion: "latest", sourceType: "module" }, 12 | settings: { react: { version: "18.2" } }, 13 | plugins: ["react-refresh"], 14 | rules: { 15 | "react/jsx-no-target-blank": "off", 16 | "react/prop-types": ["off"], 17 | "react-refresh/only-export-components": [ 18 | "warn", 19 | { allowConstantExport: true }, 20 | ], 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 버그 리포트 Bug report 2 | description: 오류 내용을 이슈로 등록하는 템플릿입니다. Template to register an error as an issue. 3 | title: "[Bug]: " 4 | labels: ["bug", "triage"] 5 | assignees: 6 | - rukegithub 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | 시간을 내어 버그 리포트를 작성해 주셔서 감사합니다. Thank you for taking the time to fill out a bug report. 12 | - type: input 13 | id: contact 14 | attributes: 15 | label: 연락처 Contact 16 | description: 추가 정보 필요 시, 연락할 수 있는 이메일을 적어 주세요. Please include an email where we can reach you if we need more information. (Optional) 17 | placeholder: 예) email@example.com 18 | validations: 19 | required: false 20 | - type: textarea 21 | id: what-happened 22 | attributes: 23 | label: 오류 내용 Error Description 24 | description: 오류 내용을 기입해 주세요. Please provide a description of the error. 25 | placeholder: Tell us what you see! 26 | value: "오류를 발견했어요. I found an error." 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: reproduce 31 | attributes: 32 | label: 오류 재현 방법 How to reproduce the error 33 | description: 오류 발생을 재현하려면, 어떻게 해야하나요? How can we reproduce the error you reported? 34 | placeholder: 오류 재현 방법 How to reproduce the error 35 | value: "(다음은 예시이며, 내용을 덮어 써 주세요. The following is an example, please overwrite the content.)\n\n 36 | 1. 다음 메뉴를 선택한다. Select the following menu '...'\n 37 | 2. 다음 버튼을 클릭한다. Click the Next button. '....'\n 38 | 3. 다음 문구까지 스크롤 다운한다. Scroll down to the following phrase '....'\n 39 | 4. 오류를 확인한다. Check for errors." 40 | validations: 41 | required: false 42 | - type: textarea 43 | id: environment 44 | attributes: 45 | label: 환경정보 Environmental Information 46 | description: 오류가 발생한 환경정보를 작성해 주세요. Please describe the environment in which the error occurred. 47 | placeholder: 오류 환경정보 Error Environment Information 48 | value: " - OS정보 Operating System: \n 49 | - 표준프레임워크 버전 eGovFrame Version: \n 50 | - JDK(JRE) 정보: \n 51 | - WAS 정보: \n 52 | - DB 정보: \n 53 | - 기타 환경 정보 Other environmental information:" 54 | validations: 55 | required: false 56 | - type: dropdown 57 | id: browsers 58 | attributes: 59 | label: 어느 브라우저를 사용했나요? Which browser did you use? 60 | multiple: true 61 | options: 62 | - Chrome 63 | - Firefox 64 | - Microsoft Edge 65 | - Opera 66 | - Safari 67 | - Internet Explorer 68 | - Others 69 | - type: textarea 70 | id: logs 71 | attributes: 72 | label: 에러 로그 Error Logs 73 | description: 관련 에러 로그를 복사하여 붙여넣어 주세요. Please copy and paste the relevant error logs. 74 | render: shell 75 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 기능 요구 Feature Request 2 | description: 기능 요구를 이슈로 등록하는 템플릿입니다. Suggest a new feature for improving eGovFrame. 3 | title: "[기능요구(Feature)]: " 4 | labels: ["feature"] 5 | assignees: 6 | - rukegithub 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | 시간을 내어 의견을 작성해 주셔서 감사합니다. Thank you for taking the time to fill out a request. 12 | - type: input 13 | id: contact 14 | attributes: 15 | label: 연락처 Contact 16 | description: 추가 정보 필요 시, 연락할 수 있는 이메일을 적어 주세요. Please include an email where we can reach you if we need more information. (Optional) 17 | placeholder: 예) email@example.com 18 | validations: 19 | required: false 20 | - type: input 21 | id: feature-title 22 | attributes: 23 | label: 추가 요청 기능명 Feature Name 24 | description: 추가를 원하는 기능명칭을 간략히 적어주세요. Write the title of the feature you'd like to add. 25 | placeholder: 예) 게시판 첨부기능 추가 Example) Adding a bulletin board attachment 26 | validations: 27 | required: true 28 | - type: textarea 29 | id: feature-request-details 30 | attributes: 31 | label: 기능 상세 설명 Feature Description 32 | description: 추가를 원하는 기능에 대해 상세히 기술해 주세요. Please describe in detail the features you would like to see added. 33 | placeholder: 추가를 원하는 기능은 다음과 같습니다. Here are the features I'd like to see added 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: solution 38 | attributes: 39 | label: 솔루션 상세 Solution Details 40 | description: 위 기능을 구현하는데 도움이 되는 기술내용이 있으면 적어 주세요. If you have any technical details to help us implement the above features, please let us know. 41 | placeholder: 위 기능을 구현하는데 도움이 되는 기술내용은 다음과 같습니다. Here are some technical details to help you implement the above features. 42 | validations: 43 | required: false 44 | - type: input 45 | id: solution-url 46 | attributes: 47 | label: 솔루션 관련 URL Solution-related URLs 48 | description: 위 기능을 구현하는데 도움이 되는 웹사이트 주소가 있으면 적어 주세요. If you have a website address that can help us implement the above features, please write it down. 49 | placeholder: Example) egovframe.go.kr 50 | validations: 51 | required: false 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/improvement_plan.yml: -------------------------------------------------------------------------------- 1 | name: 발전 방안 제안 Improvement Plan 2 | description: 발전 방안을 이슈로 등록하는 템플릿입니다. Suggest a new plan for improving eGovFrame. 3 | title: "[발전 방안 제안(Improvement Plan)]: " 4 | labels: ["Improvement"] 5 | assignees: 6 | - yongfire38 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | 시간을 내어 의견을 작성해 주셔서 감사합니다. Thank you for taking the time to fill out a request. 12 | - type: input 13 | id: idea-name 14 | attributes: 15 | label: 아이디어명 Idea Name 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: idea-summary 20 | attributes: 21 | label: 아이디어 요약 Idea Summary 22 | description: 과제 내용을 300자 이내로 간결하게 요약 및 정의해 주세요 Please summarize and define your content in 300 characters or less 23 | placeholder: 예) 게시판 첨부기능 추가 Example) Adding a bulletin board attachment 24 | validations: 25 | required: true 26 | - type: textarea 27 | id: suggestion-background 28 | attributes: 29 | label: 제안배경 Suggestion Background 30 | description: 아이디어를 제안하게 된 배경 및 필요성을 기술해 주세요. Please describe the background and need for the idea. 31 | placeholder: 아이디어를 제안하게 된 배경은 다음과 같습니다. The background to suggesting the idea is as follows. 32 | validations: 33 | required: true 34 | - type: textarea 35 | id: expectations 36 | attributes: 37 | label: 기대효과 Expectations 38 | description: 아이디어의 실현 가능성과 예상되는 기대효과를 제시하여 주세요. Please describe the expected impact and outcome of the idea. 39 | placeholder: 해당 아이디어의 기대효과는 다음과 같습니다. Here are the expected effects of this idea. 40 | validations: 41 | required: false 42 | - type: textarea 43 | id: free-writing 44 | attributes: 45 | label: 자유기술 Free Writing 46 | description: 추가 기재하고 싶은 항목 및 내용을 자유롭게 기재하여 주세요. Please feel free to add anything else you'd like to include. 47 | validations: 48 | required: false 49 | - type: textarea 50 | id: reference 51 | attributes: 52 | label: 참고문헌 Reference 53 | description: 참고문헌이 있는 경우 작성하여 주세요. If you have references, please include them. 54 | validations: 55 | required: false 56 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## 수정 사유 Reason for modification 2 | 3 | 소스를 수정한 사유가 무엇인지 체크해 주세요. Please check the reason you modified the source. ([X] X는 대문자여야 합니다.) 4 | 5 | - [x] 버그수정 Bug fixes 6 | - [ ] 기능개선 Enhancements 7 | - [ ] 기능추가 Adding features 8 | - [ ] 기타 Others 9 | 10 | ## 수정된 소스 내용 Modified source 11 | 12 | 검토자를 위해 수정된 소스 내용을 설명해 주세요. Please describe the modified source for reviewers. 13 | 14 | ## JUnit 테스트 JUnit tests 15 | 16 | 테스트를 완료하셨으면 다음 항목에 [대문자X]로 표시해 주세요. When you're done testing, check the following items. 17 | 18 | - [x] JUnit 테스트 JUnit tests 19 | - [x] 수동 테스트 Manual testing 20 | 21 | ## 테스트 브라우저 Test Browser 22 | 23 | 테스트를 진행한 브라우저를 선택해 주세요. Please select the browser(s) you ran the test on. (다중 선택 가능 you can select multiple) [X] X는 대문자여야 합니다. 24 | 25 | - [ ] Chrome 26 | - [ ] Firefox 27 | - [ ] Edge 28 | - [ ] Safari 29 | - [ ] Opera 30 | - [ ] Internet Explorer 31 | - [ ] 기타 Others 32 | 33 | ## 테스트 스크린샷 또는 캡처 영상 Test screenshots or captured video 34 | 35 | 테스트 전과 후의 스크린샷 또는 캡처 영상을 이곳에 첨부해 주세요. Please attach screenshots or video captures of your before and after tests here. 36 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: ["main"] 9 | pull_request: 10 | branches: ["main"] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [18.x] 19 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | cache: "npm" 28 | - run: npm ci 29 | - run: npm run build --if-present 30 | - name: Run tests 31 | run: npm run test:run 32 | env: 33 | NODE_ENV: test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | /dist 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # code 27 | .history -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | egovframe-template-simple-react 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Docs/development-env-setting.md: -------------------------------------------------------------------------------- 1 | # 개발환경 초기화 Initialization 2 | 3 | 본 문서는 vite를 통해 처음 프로젝트를 생성하려고 할때 필요한 내용을 기술하였음. 4 | 5 | ## React 개발환경 초기화 6 | 7 | ### 1. 프로젝트 생성 8 | 9 | ```bash 10 | npm create vite@latest 11 | ``` 12 | 13 | ### 2. 생성 확인 14 | 15 | ```bash 16 | npm run dev 17 | ``` 18 | 19 | ### 3. 필요없는 파일 및 소스 삭제 20 | 21 | 구현에 필요 없는 파일 및 소스들을 삭제한다 22 | 23 | ## 개발 세팅 24 | 25 | ### 환경변수 설정 26 | 27 | - 최상위 디렉토리에 `.env.development` 파일을 만들어 준다. 28 | 29 | - `VITE_APP`으로 시작하는 key 값과 Value 값을 정해주고 30 | 31 | js 에서 `process.env.<키명> 으로 불러와 지는지 확인 한다. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 표준프레임워크 심플홈페이지 FrontEnd 2 | 3 | ![react](https://img.shields.io/badge/react-61DAFB?style=for-the-badge&logo=react&logoColor=black) 4 | ![javascript](https://img.shields.io/badge/javascript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black) 5 | ![nodejs](https://img.shields.io/badge/node.js-339933?style=for-the-badge&logo=Node.js&logoColor=white) 6 | ![npm](https://img.shields.io/badge/npm-CB3837?style=for-the-badge&logo=npm&logoColor=white) 7 | ![vite](https://img.shields.io/badge/vite-646CFF?style=for-the-badge&logo=vite&logoColor=white) 8 | ![workflow](https://github.com/eGovFramework/egovframe-template-simple-react/actions/workflows/node.js.yml/badge.svg) 9 | 10 | ※ 본 프로젝트는 기존 JSP 뷰 방식에서 벗어나 BackEnd와 FrontEnd를 분리하기 위한 예시 파일로 참고만 하시길 바랍니다. 11 | 12 | ## 프로젝트 소개 13 | 14 | ### 프로젝트 개요 15 | 16 | 단순 홈페이지 기능 구현 시 필수적인 부분만 사용 가능하도록 경량화 된 실행환경 제공 17 | 메인 페이지, 사용자 관리, 공지사항 관리, 게시판 관리, 안내 관리 기능을 제공 18 | 19 | ### 메뉴 구성 20 | 21 | ![menu_sht_v4](https://github.com/user-attachments/assets/4aad1e74-873a-4ed9-8df9-97958bcccbc8) 22 | 23 | ## 참고 화면 및 메뉴 설명 24 | 25 | ### 메인 화면 26 | 27 | ![sh1](https://github.com/user-attachments/assets/41757fa0-b976-435a-81ac-e163e2846998) 28 | 29 | 1. 최초 관리자 계정 설정은 **[ 로그인계정 : admin , 로그인암호 : 1 ]** 로 설정되어 있다. 30 | 2. 메인 화면 우측 상단의 **회원가입** 버튼을 통해 사용자 계정을 생성 가능하다. 31 | 3. 기본 기능이나 예시 메뉴를 실무적으로 추가 커스터마이징하여 활용할 수 있다. 32 | 33 | ### 로그인 화면 34 | 35 | ![login](https://github.com/user-attachments/assets/383f7e62-1b31-4726-8c65-785b00c9ec45) 36 | 37 | 1. 최초 관리자 계정을 통한 로그인이 가능하다. 38 | 2. **회원가입** 버튼을 통해 생성한 사용자 계정을 통한 로그인이 가능하다. (사용자 계정은 일부 메뉴 접근이 제한된다) 39 | 3. 로그인 창 하단의 소셜 로그인 버튼으로 네이버 및 카카오 계정으로 로그인이 가능하다. 이 경우의 권한은 사용자 계정과 동일하다. 40 | 4. 소셜 로그인 기능의 사용을 위해서는 사전에 **[네이버 개발자 센터](https://developers.naver.com/main/)** 및 **[카카오 개발자 센터](https://developers.kakao.com/)** 에서 Client ID와 Client Secret을 발급 받은 후 Callback URL을 프론트엔드와 백엔드 환경 설정 파일에 등록해야 한다. 41 | 5. 프론트엔드 환경 설정 파일은 본 애플리케이션의 `.env.development` (개발 환경) 및 `.env.production` (빌드 시 사용) 을 참고한다. 42 | 6. 백엔드 환경 설정 파일은 [심플 홈페이지 Backend](https://github.com/eGovFramework/egovframe-template-simple-backend.git) 의 `application.properties` 를 참고한다. 43 | 7. 네이버 소셜 로그인에 대한 상세 사항은 **[네이버 로그인 API 문서](https://developers.naver.com/docs/login/api/api.md)** 를 참조 가능하다. 44 | 8. 카카오 소셜 로그인에 대한 상세 사항은 **[카카오 로그인 API 문서](https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#kakaologin)** 를 참조 가능하다. 45 | 46 | ### 사이트 소개 화면 47 | 48 | ![sh2](https://github.com/user-attachments/assets/f7b8a9c7-e6a5-48e2-9cbc-4f590e19365b) 49 | 50 | - **해당 화면 및 세부 메뉴 화면은 구성을 위한 샘플페이지가 제공되며 기능은 구현되지 않은 상태입니다.** 51 | 52 | 1. 세부메뉴 : 사이트소개, 연혁, 조직소개, 찾아오시는 길 53 | 2. 기능설명 : 예시 메뉴에 해당하는 항목으로 샘플 페이지 형태로 존재한다. 54 | 3. 활용방법 : 각 샘플 페이지에 대한 콘텐츠를 새로 구성하여 활용할 수 있다. 55 | 56 | ### 정보마당 화면 57 | 58 | ![sh3](https://github.com/user-attachments/assets/ce639fea-4b3f-4dcb-b00d-39175a9fff91) 59 | 60 | - **해당 화면 및 세부 메뉴 화면은 구성을 위한 샘플페이지가 제공되며 기능은 구현되지 않은 상태입니다.** 61 | 62 | 1. 세부메뉴 : 주요사업 소개, 대표서비스 소개 63 | 2. 기능설명 : 예시 메뉴에 해당하는 항목으로 샘플 페이지 형태로 존재한다. 64 | 3. 활용방법 : 각 샘플 페이지에 대한 콘텐츠를 새로 구성하여 활용할 수 있다. 65 | 66 | ### 고객지원 화면 67 | 68 | ![sh4](https://github.com/user-attachments/assets/177a38d3-d94f-41f3-ac99-0fe0a7a3f806) 69 | 70 | - **해당 화면 및 세부 메뉴 화면은 구성을 위한 샘플페이지가 제공되며 기능은 구현되지 않은 상태입니다.** 71 | 72 | 1. 세부메뉴 : 자료실, 묻고답하기, 서비스신청 73 | 2. 기능설명 : 예시 메뉴에 해당하는 항목으로 샘플 페이지 형태로 존재한다. 74 | 3. 활용방법 : 각 샘플 페이지에 기능을 추가 개발 후 구성하여 활용할 수 있다. 75 | 76 | ### 알림마당 화면 77 | 78 | ![sh5](https://github.com/user-attachments/assets/d45ebbf2-3d0a-4450-a9ea-247495520bc7) 79 | 80 | 1. 세부메뉴 : 오늘의행사, 금주의행사, 공지사항, 사이트갤러리 81 | 2. 기능설명 : 공통컴포넌트 일정관리(부서일정)와 게시판 기능을 커스터마이징하여 사용한다. 82 | 3. 활용방법 : 관리자가 등록한 일정정보를 조회하거나 게시물을 조회할 수 있다. 83 | 84 | ### 사이트관리 화면 85 | 86 | ![sh6](https://github.com/user-attachments/assets/29c8e651-5d1b-4ad3-bc27-c16a511c5008) 87 | 88 | 1. 세부메뉴 : 일정관리, 게시판생성관리, 게시판사용관리, 공지사항관리, 사이트갤러리관리, 사이트관리자 암호변경, 회원관리 89 | 2. 기능설명 : 공통컴포넌트 일정관리(부서일정)과 게시판 기능을 커스터마이징하여 사용한다. 90 | 3. 활용방법 : 관리자로 로그인 한 후 일정정보를 등록하거나 게시물을 등록할 수 있다. (게시판 설정 가능) 91 | 92 | ## 환경 설정 93 | 94 | 프로젝트에서 사용된 환경 프로그램 정보는 다음과 같다. 95 | 96 | | 프로그램 명 | 버전 명 | 97 | | :---------- | :------- | 98 | | Node.js | v18.12.0 | 99 | | NPM | v8.19.2 | 100 | 101 | ## BackEnd 구동 102 | 103 | [심플 홈페이지 Backend](https://github.com/eGovFramework/egovframe-template-simple-backend.git) 소스를 받아 구동한다. 104 | 105 | ## FrontEnd 구동 106 | 107 | 아래 1 ~ 3의 과정을 따라서 진행한다. 108 | 109 | ### 1. 프로젝트의 생성 110 | 111 | Git에서 복제하여 설치 시 1-1. 을 참고한다. 112 | 113 | #### 1-1. Git에서 프로젝트 복제 및 모듈 설치 114 | 115 | Git에서 clone 한다. 116 | 117 | ```bash 118 | # 프로젝트 저장소를 로컬로 복제 119 | git clone https://github.com/[계정명]/egovframe-template-simple-react.git 120 | 121 | # 복제된 프로젝트 디렉토리로 이동 122 | cd egovframe-template-simple-react 123 | 124 | # node modules를 설치해 준다. 125 | npm install 126 | ``` 127 | 128 | ### 2. 백엔드 프로젝트 설정 129 | 130 | 구동된 BackEnd 서버의 URL을 본 어플리케이션의 .env.development 파일의 VITE_EGOV_CONTEXT_URL에 설정해 준다. 131 | (단, 개발환경에서는 사용하는 환경변수 정보는 .env.development, build 시 사용하는 환경변수는 .env.production 에 기입해 준다.) 132 | 133 | ```bash 134 | # .env.development 예시 135 | VITE_APP_EGOV_CONTEXT_URL=localhost:8080 136 | ``` 137 | 138 | ### 3. 프로젝트 실행 및 기타 명령어 139 | 140 | ```bash 141 | # 테스트용 리액트 서버를 실행할 때 아래 명령어를 사용한다. 142 | npm run dev 143 | ``` 144 | 145 | ```bash 146 | # 빌드할 때에는 아래 명령어를 사용한다. 147 | npm run build 148 | ``` 149 | 150 | ```bash 151 | # 로컬에서 미리보기할 때는 아래 명령어를 사용한다. 152 | npm run preview 153 | ``` 154 | 155 | ```bash 156 | # 테스트 대상 파일 경로는 vite.config.js에 명시되어 있으며 디폴트로 EgovMain.jsx의 테스트를 실행한다. 157 | # watch 모드로 테스트를 실행할 경우에는 아래 명령어를 사용한다. 158 | npm run test 159 | 160 | # 일회성 테스트를 실행할 경우에는 아래 명령어를 사용한다. 161 | npm run test:run 162 | ``` 163 | 164 | --- 165 | 166 | ### 참조 167 | 168 | 보다 상세한 설명은 아래의 문서를 확인한다. 169 | 170 | 1. [vite 공식 가이드 문서(한글)](https://vitejs-kr.github.io/guide/) 171 | 2. [개발환경 초기 설정](./Docs/development-env-setting.md) 172 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React App 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "src/" 4 | }, 5 | "include": [ 6 | "src" 7 | ] 8 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egovframe-template-simple-react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "dependencies": { 7 | "egovframe-template-simple-react": "file:", 8 | "qs": "^6.11.0", 9 | "react": "^18.3.1", 10 | "react-datepicker": "^4.8.0", 11 | "react-dom": "^18.3.1", 12 | "react-router-dom": "^6.4.0", 13 | "web-vitals": "^2.1.4" 14 | }, 15 | "devDependencies": { 16 | "@babel/plugin-proposal-private-property-in-object": "^7.0.0", 17 | "@testing-library/jest-dom": "^5.17.0", 18 | "@testing-library/react": "^13.4.0", 19 | "@testing-library/user-event": "^13.5.0", 20 | "@types/react": "^18.3.3", 21 | "@types/react-dom": "^18.3.0", 22 | "@vitejs/plugin-react": "4.3.1", 23 | "@vitejs/plugin-react-swc": "^3.5.0", 24 | "eslint": "^8.57.0", 25 | "eslint-plugin-react": "^7.34.3", 26 | "eslint-plugin-react-hooks": "^4.6.2", 27 | "eslint-plugin-react-refresh": "^0.4.7", 28 | "react-scripts": "5.0.1", 29 | "vite": "^5.3.4", 30 | "vitest": "2.0.4" 31 | }, 32 | "scripts": { 33 | "dev": "vite", 34 | "build": "vite build", 35 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 36 | "preview": "vite preview", 37 | "test": "vitest", 38 | "test:run": "vitest run" 39 | }, 40 | "proxy": "http://localhost:8080" 41 | } 42 | -------------------------------------------------------------------------------- /public/assets/images/banner_m_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/banner_m_01.png -------------------------------------------------------------------------------- /public/assets/images/banner_m_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/banner_m_02.png -------------------------------------------------------------------------------- /public/assets/images/banner_w_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/banner_w_01.png -------------------------------------------------------------------------------- /public/assets/images/banner_w_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/banner_w_02.png -------------------------------------------------------------------------------- /public/assets/images/img_business_intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/img_business_intro.png -------------------------------------------------------------------------------- /public/assets/images/img_business_intro_m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/img_business_intro_m.png -------------------------------------------------------------------------------- /public/assets/images/img_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/img_sample.png -------------------------------------------------------------------------------- /public/assets/images/img_sample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/img_sample2.png -------------------------------------------------------------------------------- /public/assets/images/img_simple_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/img_simple_main.png -------------------------------------------------------------------------------- /public/assets/images/img_template_intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/img_template_intro.png -------------------------------------------------------------------------------- /public/assets/images/logo_footer_m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/logo_footer_m.png -------------------------------------------------------------------------------- /public/assets/images/logo_footer_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/logo_footer_w.png -------------------------------------------------------------------------------- /public/assets/images/logo_m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/logo_m.png -------------------------------------------------------------------------------- /public/assets/images/logo_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/logo_w.png -------------------------------------------------------------------------------- /public/assets/images/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/map.png -------------------------------------------------------------------------------- /public/assets/images/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/qrcode.png -------------------------------------------------------------------------------- /public/assets/images/reply_arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/reply_arrow.gif -------------------------------------------------------------------------------- /public/assets/images/sample_pds_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/public/assets/images/sample_pds_list.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React App 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import RootRoutes from './routes'; 2 | import React from 'react'; 3 | 4 | import './css/base.css'; 5 | import './css/layout.css'; 6 | import './css/component.css'; 7 | import './css/page.css'; 8 | import './css/response.css'; 9 | 10 | function App() { 11 | 12 | return ( 13 |
14 | 15 | 16 | 17 |
18 | ) 19 | } 20 | 21 | console.log("process.env.NODE_ENV", process.env.NODE_ENV); 22 | console.log("process.env.REACT_APP_EGOV_CONTEXT_URL", process.env.REACT_APP_EGOV_CONTEXT_URL); 23 | 24 | export default App; 25 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import RootRoutes from "@/routes"; 2 | import React from "react"; 3 | import { BrowserRouter as Router } from "react-router-dom"; 4 | 5 | import "@/css/base.css"; 6 | import "@/css/layout.css"; 7 | import "@/css/component.css"; 8 | import "@/css/page.css"; 9 | import "@/css/response.css"; 10 | 11 | function App() { 12 | return ( 13 |
14 | 15 | 16 | 17 | 18 | 19 |
20 | ); 21 | } 22 | 23 | export default App; 24 | -------------------------------------------------------------------------------- /src/App.test.jsx: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('App', () => { 4 | it('passes a simple test', () => { 5 | expect(true).toBe(true); 6 | }); 7 | }); -------------------------------------------------------------------------------- /src/EgovMain.test.jsx: -------------------------------------------------------------------------------- 1 | import { render } from "@testing-library/react"; 2 | import { MemoryRouter } from "react-router-dom"; 3 | import { describe, it } from "vitest"; 4 | import EgovMain from "@/pages/main/EgovMain"; 5 | 6 | describe("EgovMain Component", () => { 7 | it("renders correctly", () => { 8 | render( 9 | 10 | 11 | 12 | ); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/api/egovFetch.js: -------------------------------------------------------------------------------- 1 | import { SERVER_URL } from "../config"; 2 | 3 | import URL from "@/constants/url"; 4 | import CODE from "@/constants/code"; 5 | import { getSessionItem, setSessionItem } from "@/utils/storage"; 6 | 7 | export function getQueryString(params) { 8 | return `?${Object.entries(params) 9 | .map((e) => e.join("=")) 10 | .join("&")}`; 11 | } 12 | 13 | export function requestFetch(url, requestOptions, handler, errorHandler) { 14 | console.groupCollapsed("requestFetch"); 15 | console.log("requestFetch [URL] : ", SERVER_URL + url); 16 | console.log("requestFetch [requestOption] : ", requestOptions); 17 | 18 | // Login 했을경우 JWT 설정 19 | const sessionUser = getSessionItem("loginUser"); 20 | const sessionUserId = sessionUser?.id || null; 21 | const jToken = getSessionItem("jToken"); 22 | if (sessionUserId != null && sessionUserId !== undefined) { 23 | if (!requestOptions["headers"]) requestOptions["headers"] = {}; 24 | if (!requestOptions["headers"]["Authorization"]) 25 | requestOptions["headers"]["Authorization"] = null; 26 | requestOptions["headers"]["Authorization"] = jToken; 27 | } 28 | 29 | //CORS ISSUE 로 인한 조치 - origin 및 credentials 추가 30 | // origin 추가 31 | if (!requestOptions["origin"]) { 32 | requestOptions = { ...requestOptions, origin: SERVER_URL }; 33 | } 34 | // credentials 추가 35 | if (!requestOptions["credentials"]) { 36 | requestOptions = { ...requestOptions, credentials: "include" }; 37 | } 38 | 39 | fetch(SERVER_URL + url, requestOptions) 40 | .then((response) => { 41 | // response Stream. Not completion object 42 | //console.log("requestFetch [Response Stream] ", response); 43 | return response.json(); 44 | }) 45 | .then((resp) => { 46 | if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) { 47 | alert("Login Alert"); //index.jsx라우터파일에 jwtAuthentication 함수로 공통 인증을 사용하는 코드 추가로 alert 원상복구 48 | setSessionItem("loginUser", { id: "" }); 49 | window.location.href = URL.LOGIN; 50 | return false; 51 | } else { 52 | return resp; 53 | } 54 | }) 55 | .then((resp) => { 56 | console.groupCollapsed("requestFetch.then()"); 57 | console.log("requestFetch [response] ", resp); 58 | if (typeof handler === "function") { 59 | handler(resp); 60 | } else { 61 | console.log("egov fetch handler not assigned!"); 62 | } 63 | console.groupEnd("requestFetch.then()"); 64 | }) 65 | .catch((error) => { 66 | console.error("There was an error!", error); 67 | if (error === "TypeError: Failed to fetch") { 68 | alert("서버와의 연결이 원활하지 않습니다. 서버를 확인하세요."); 69 | } 70 | 71 | if (typeof errorHandler === "function") { 72 | errorHandler(error); 73 | } else { 74 | console.error("egov error handler not assigned!"); 75 | alert("ERR : " + error.message); 76 | } 77 | }) 78 | .finally(() => { 79 | console.log("requestFetch finally end"); 80 | console.groupEnd("requestFetch"); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /src/api/egovFetch.jsx: -------------------------------------------------------------------------------- 1 | import { SERVER_URL } from "../config"; 2 | 3 | import URL from "@/constants/url"; 4 | import CODE from "@/constants/code"; 5 | 6 | export function requestFetch(url, requestOptions, handler, errorHandler) { 7 | console.groupCollapsed("requestFetch"); 8 | console.log("requestFetch [URL] : ", SERVER_URL + url); 9 | console.log("requestFetch [requestOption] : ", requestOptions); 10 | 11 | //CORS ISSUE 로 인한 조치 - origin 및 credentials 추가 12 | // origin 추가 13 | if (!requestOptions["origin"]) { 14 | requestOptions = { ...requestOptions, origin: SERVER_URL }; 15 | } 16 | // credentials 추가 17 | if (!requestOptions["credentials"]) { 18 | requestOptions = { ...requestOptions, credentials: "include" }; 19 | } 20 | 21 | fetch(SERVER_URL + url, requestOptions) 22 | .then((response) => { 23 | // response Stream. Not completion object 24 | //console.log("requestFetch [Response Stream] ", response); 25 | return response.json(); 26 | }) 27 | .then((resp) => { 28 | if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) { 29 | alert("Login Alert"); //index.jsx라우터파일에 jwtAuthentication 함수로 공통 인증을 사용하는 코드 추가로 alert 원상복구 30 | sessionStorage.setItem("loginUser", JSON.stringify({ id: "" })); 31 | window.location.href = URL.LOGIN; 32 | return false; 33 | } else { 34 | return resp; 35 | } 36 | }) 37 | .then((resp) => { 38 | console.groupCollapsed("requestFetch.then()"); 39 | console.log("requestFetch [response] ", resp); 40 | if (typeof handler === "function") { 41 | handler(resp); 42 | } else { 43 | console.log("egov fetch handler not assigned!"); 44 | } 45 | console.groupEnd("requestFetch.then()"); 46 | }) 47 | .catch((error) => { 48 | console.error("There was an error!", error); 49 | if (error === "TypeError: Failed to fetch") { 50 | alert("서버와의 연결이 원활하지 않습니다. 서버를 확인하세요."); 51 | } 52 | 53 | if (typeof errorHandler === "function") { 54 | errorHandler(error); 55 | } else { 56 | console.error("egov error handler not assigned!"); 57 | alert("ERR : " + error.message); 58 | } 59 | }) 60 | .finally(() => { 61 | console.log("requestFetch finally end"); 62 | console.groupEnd("requestFetch"); 63 | }); 64 | } 65 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/EgovAttachFile.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | 4 | import URL from "@/constants/url"; 5 | import * as EgovNet from "@/api/egovFetch"; 6 | import { SERVER_URL } from "@/config"; 7 | import CODE from "@/constants/code"; 8 | 9 | function EgovAttachFile({ 10 | boardFiles, 11 | mode, 12 | fnChangeFile, 13 | fnDeleteFile, 14 | posblAtchFileNumber, 15 | }) { 16 | console.groupCollapsed("EgovAttachFile"); 17 | 18 | // posblAtchFileNumber는 수정일 경우에만 값이 넘어오므로 방어 로직 19 | // 해당 컴포넌트는 스케줄 화면과 공유하며, 스케줄에서는 첨부파일을 1개 넣을 수 있으므로 디폴트 값을 1로 설정 20 | if ( 21 | typeof posblAtchFileNumber == "undefined" || 22 | posblAtchFileNumber == null 23 | ) { 24 | posblAtchFileNumber = 1; 25 | } 26 | 27 | const navigate = useNavigate(); 28 | 29 | function onClickDownFile(atchFileId, fileSn) { 30 | window.open( 31 | SERVER_URL + "/file?atchFileId=" + atchFileId + "&fileSn=" + fileSn + "" 32 | ); 33 | } 34 | 35 | function onClickDeleteFile(atchFileId, fileSn, fileIndex) { 36 | console.log("onClickDeleteFile Params : ", atchFileId, fileSn, fileIndex); 37 | 38 | const requestOptions = { 39 | method: "POST", 40 | headers: { 41 | "Content-type": "application/json", 42 | }, 43 | body: JSON.stringify({ 44 | atchFileId: atchFileId, 45 | fileSn: fileSn, 46 | }), 47 | }; 48 | EgovNet.requestFetch(`/file`, requestOptions, function (resp) { 49 | console.log("===>>> board file delete= ", resp); 50 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 51 | // 성공 52 | console.log("Deleted fileIndex = ", fileIndex); 53 | // eslint-disable-next-line no-unused-vars 54 | const _deleteFile = boardFiles.splice(fileIndex, 1); 55 | const _boardFiles = Object.assign([], boardFiles); 56 | fnDeleteFile(_boardFiles); 57 | alert("첨부파일이 삭제되었습니다."); 58 | fnChangeFile({}); 59 | } else { 60 | navigate( 61 | { pathname: URL.ERROR }, 62 | { state: { msg: resp.resultMessage } } 63 | ); 64 | } 65 | }); 66 | } 67 | 68 | function onChangeFileInput(e) { 69 | console.log("===>>> e = " + e.target.files[0]); 70 | if ( 71 | e.target.files.length + (boardFiles?.length || 0) > 72 | posblAtchFileNumber 73 | ) { 74 | alert("총 첨부파일 개수는 " + posblAtchFileNumber + " 까지 입니다."); 75 | e.target.value = null; // 파일 입력란 화면 초기화 76 | fnChangeFile({}); // 상위 컴포넌트의 저장된 값 초기화 77 | return false; 78 | } 79 | fnChangeFile(e.target.files); 80 | } 81 | 82 | let filesTag = []; 83 | 84 | if (boardFiles !== undefined) { 85 | boardFiles.forEach(function (item, index) { 86 | filesTag.push( 87 | 88 | 89 | 97 | {item.orignlFileNm} 98 | 99 | [{item.fileMg}byte] 100 | 101 | 102 | ); 103 | 104 | if (mode === CODE.MODE_MODIFY) { 105 | filesTag.push( 106 | 107 | 113 | 114 | ); 115 | } 116 | filesTag.push(
); 117 | }); 118 | } 119 | console.log("filesTag : ", filesTag); 120 | console.groupEnd("EgovAttachFile"); 121 | 122 | return ( 123 |
124 |
첨부파일
125 |
126 | 127 | {filesTag} 128 | {mode === CODE.MODE_CREATE && ( 129 | <> 130 | onChangeFileInput(e)} 136 | > 137 | 총 업로드 가능한 첨부파일 개수는 {posblAtchFileNumber} 개 입니다. 138 | 139 | )} 140 | {/* 첨부파일 1개 당 filesTag는 3개 요소(span, button, br)를 가진다 */} 141 | {mode === CODE.MODE_MODIFY && 142 | filesTag.length / 3 < posblAtchFileNumber && ( 143 | <> 144 | onChangeFileInput(e)} 150 | > 151 | 현재 업로드 가능한 첨부파일 개수는{" "} 152 | {posblAtchFileNumber - filesTag.length / 3} 개 입니다. 153 | 154 | )} 155 | 156 |
157 |
158 | ); 159 | } 160 | 161 | export default EgovAttachFile; 162 | -------------------------------------------------------------------------------- /src/components/EgovCondition.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | function EgovCondition() { 4 | return ( 5 |
6 | 47 |
48 | ); 49 | } 50 | 51 | export default EgovCondition; 52 | -------------------------------------------------------------------------------- /src/components/EgovContainer.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import EgovLeftNav from "@/components/EgovLeftNav"; 4 | 5 | function EgovContainer() { 6 | return ( 7 |
8 |
9 | {/* */} 10 |
11 |
    12 |
  • 13 | 14 | Home 15 | 16 |
  • 17 |
  • 18 | 알림마당 19 |
  • 20 |
  • 오늘의 행사
  • 21 |
22 |
23 | {/* */} 24 | 25 |
26 | {/* */} 27 | 28 | {/* */} 29 | 30 | {/* */} 31 |
32 |
33 |

알림마당

34 |
35 | 36 |

금주의 행사

37 | 38 | {/* */} 39 |
40 |
    41 |
  • 42 | 52 |
  • 53 |
  • 54 | 55 | 이전연도로이동 56 | 57 | 2021년 58 | 59 | 다음연도로이동 60 | 61 |
  • 62 |
  • 63 | 64 | 이전월로이동 65 | 66 | 8월 67 | 68 | 다음월로이동 69 | 70 |
  • 71 |
  • 72 | 73 | 이전주로이동 74 | 75 | 1주 76 | 77 | 다음주로이동 78 | 79 |
  • 80 |
81 |
82 | {/* */} 83 | 84 | {/* */} 85 |
86 |
87 | 날짜 88 | 시간 89 | 제목 90 | 담당자 91 |
92 |
93 | {/* */} 94 |

95 | 검색된 결과가 없습니다. 96 |

97 | 98 | {/* */} 99 | 100 |
2021년07월11일 일요일
101 |
11:00~12:30
102 |
103 | 전자정부표준프레임워크 금주의 행사안내입니다. 104 |
105 |
관리자
106 | 107 | 108 |
2021년07월11일 일요일
109 |
11:00~12:30
110 |
111 | 전자정부표준프레임워크 금주의 행사안내입니다. 112 |
113 |
관리자
114 | 115 | 116 |
2021년07월11일 일요일
117 |
11:00~12:30
118 |
119 | 전자정부표준프레임워크 금주의 행사안내입니다. 120 |
121 |
관리자
122 | 123 | 124 |
2021년07월11일 일요일
125 |
11:00~12:30
126 |
127 | 전자정부표준프레임워크 금주의 행사안내입니다. 128 |
129 |
관리자
130 | 131 | 132 |
2021년07월11일 일요일
133 |
11:00~12:30
134 |
135 | 전자정부표준프레임워크 금주의 행사안내입니다. 136 |
137 |
관리자
138 | 139 |
140 |
141 | {/* */} 142 | 143 |
144 | {/* */} 145 |
146 | 147 | 이전 148 | 149 |
    150 |
  • 151 | 152 | 1 153 | 154 |
  • 155 |
  • 156 | 2 157 |
  • 158 |
  • 159 | 3 160 |
  • 161 |
  • 162 | 4 163 |
  • 164 |
  • 165 | 5 166 |
  • 167 |
168 | 169 | 다음 170 | 171 |
172 | {/* */} 173 |
174 |
175 | {/* */} 176 |
177 |
178 |
179 | ); 180 | } 181 | 182 | export default EgovContainer; 183 | -------------------------------------------------------------------------------- /src/components/EgovError.jsx: -------------------------------------------------------------------------------- 1 | import { useNavigate, useLocation } from "react-router-dom"; 2 | 3 | function EgovError() { 4 | const navigate = useNavigate(); 5 | const location = useLocation(); 6 | 7 | let errormessage = location.state.msg || "알 수 없는 에러가 발생했습니다."; 8 | 9 | if (errormessage === "No message available") { 10 | errormessage = "알 수 없는 에러가 발생했습니다."; 11 | } 12 | 13 | const goBack = () => { 14 | navigate(-1, { replace: true }); // 이전 URL을 현재 페이지 인식하고 재 로딩하는 코드. 15 | }; 16 | 17 | return ( 18 |
19 |

Error

20 |
21 |

{errormessage}

22 |
23 | 26 |
27 |
28 |
29 | ); 30 | } 31 | 32 | export default EgovError; 33 | -------------------------------------------------------------------------------- /src/components/EgovFooter.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import logoFooterImg from "/assets/images/logo_footer_w.png"; 4 | import logoFooterImgMobile from "/assets/images/logo_footer_m.png"; 5 | import bannerImg_01 from "/assets/images/banner_w_01.png"; 6 | import bannerImgMobile_01 from "/assets/images/banner_m_01.png"; 7 | import bannerImg_02 from "/assets/images/banner_w_02.png"; 8 | import bannerImgMobile_02 from "/assets/images/banner_m_02.png"; 9 | 10 | function EgovFooter() { 11 | return ( 12 |
13 |
14 |

15 | 16 | 17 | 18 | 19 |

20 |
21 |

22 | 대표문의메일 : egovframeexample@gmail.com{" "} 23 | | 24 |
대표전화 : 0000-0000 (000-0000-0000) 25 |
26 | 호환성확인 : 000-0000-0000 | 교육문의 : 0000-0000-0000 27 |

28 |

29 | Copyright © 2021 Ministry Of The Interior And Safety. All Rights 30 | Reserved. 31 |

32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 |
44 |
45 | ); 46 | } 47 | 48 | export default EgovFooter; 49 | -------------------------------------------------------------------------------- /src/components/EgovImageGallery.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { SERVER_URL } from "@/config"; 3 | 4 | function EgovImageGallery({ boardFiles }) { 5 | let filesTag = []; 6 | 7 | if (boardFiles !== undefined) { 8 | boardFiles.forEach(function (item, index) { 9 | filesTag.push( 10 | 11 | 15 |
16 |
17 | ); 18 | }); 19 | } 20 | console.log("filesTag : ", filesTag); 21 | console.groupEnd("EgovAttachFile"); 22 | 23 | return
{filesTag}
; 24 | } 25 | 26 | export default EgovImageGallery; 27 | -------------------------------------------------------------------------------- /src/components/EgovInfoPopup.jsx: -------------------------------------------------------------------------------- 1 | import templateIntroImg from "/assets/images/img_template_intro.png"; 2 | 3 | function EgovInfoPopup() { 4 | return ( 5 |
6 |
7 |
8 |

홈페이지 템플릿 소개

9 | 12 |
13 | 14 |
15 |
    16 |
  • 17 | 경량환경 템플릿은 개발자가 프레임워크 쉽게 이해하고 활용할 수 18 | 있도록 지원합니다. 19 |
  • 20 |
  • 21 | 홈페이지 템플릿은 공통컴포넌트를 기반으로 아래 그림과 같이 메뉴가 22 | 구성됩니다. 23 |
  • 24 |
  • 25 | 관리자로 로그인하면 관리자용 메뉴를 추가로 사용할 수 있습니다. 26 |
  • 27 |
  • 28 | 사이트소개, 정보마당, 고객지원 메뉴는 구성을 위한 샘플페이지가 29 | 제공되며 기능은 구현되지 않은 상태입니다. 30 |
  • 31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 | ); 39 | } 40 | 41 | export default EgovInfoPopup; 42 | -------------------------------------------------------------------------------- /src/components/EgovLeftNav.jsx: -------------------------------------------------------------------------------- 1 | import { NavLink } from "react-router-dom"; 2 | import URL from "@/constants/url"; 3 | 4 | function EgovLeftNav() { 5 | return ( 6 |
7 |
8 |

알림마당

9 | 43 |
44 |
45 | ); 46 | } 47 | 48 | export default EgovLeftNav; 49 | -------------------------------------------------------------------------------- /src/components/EgovPaging.jsx: -------------------------------------------------------------------------------- 1 | function EgovPaging(props) { 2 | console.groupCollapsed("EgovPaging"); 3 | console.log("EgovPaging [props] : ", props); 4 | 5 | let paginationTag = []; 6 | 7 | if (props.pagination === undefined) { 8 | paginationTag = "-"; 9 | } else { 10 | const currentPageNo = props.pagination.currentPageNo; 11 | const pageSize = props.pagination.pageSize; 12 | const totalRecordCount = props.pagination.totalRecordCount; 13 | const recordCountPerPage = props.pagination.recordCountPerPage; 14 | 15 | const totalPageCount = Math.ceil(totalRecordCount / recordCountPerPage); 16 | const currentFirstPage = 17 | Math.floor((currentPageNo - 1) / pageSize) * pageSize + 1; 18 | let currentLastPage = currentFirstPage + pageSize - 1; 19 | currentLastPage = 20 | currentLastPage > totalPageCount ? totalPageCount : currentLastPage; 21 | 22 | if (totalPageCount > pageSize) { 23 | // 첫 페이지 이동 24 | const firstPageTag = ( 25 |
  • 26 | 34 |
  • 35 | ); 36 | paginationTag.push(firstPageTag); 37 | 38 | // 이전 페이지 이동 39 | const prevPageIndex = currentPageNo - 1 > 0 ? currentPageNo - 1 : 1; 40 | const previousPageTag = ( 41 |
  • 42 | 50 |
  • 51 | ); 52 | paginationTag.push(previousPageTag); 53 | } 54 | 55 | for (let i = currentFirstPage; i <= currentLastPage; i++) { 56 | if (i === currentPageNo) { 57 | // 현재 페이지 58 | const currentPage = ( 59 |
  • 60 | 61 |
  • 62 | ); 63 | paginationTag.push(currentPage); 64 | } else { 65 | // 다른 페이지 66 | const otherPage = ( 67 |
  • 68 | 75 |
  • 76 | ); 77 | paginationTag.push(otherPage); 78 | } 79 | } 80 | if (totalPageCount > pageSize) { 81 | // 다음 페이지 이동 82 | const nextPageIndex = 83 | currentLastPage + 1 < totalPageCount 84 | ? currentLastPage + 1 85 | : totalPageCount; 86 | const nextPageTag = ( 87 |
  • 88 | 96 |
  • 97 | ); 98 | paginationTag.push(nextPageTag); 99 | 100 | // 마지막 페이지 이동 101 | const lastPageTag = ( 102 |
  • 103 | 109 |
  • 110 | ); 111 | paginationTag.push(lastPageTag); 112 | } 113 | } 114 | console.log("paginationTag", paginationTag); 115 | console.groupEnd("EgovPaging"); 116 | 117 | return ( 118 |
    119 | 120 |
    121 | ); 122 | } 123 | 124 | export default EgovPaging; 125 | -------------------------------------------------------------------------------- /src/components/EgovRadioButton.jsx: -------------------------------------------------------------------------------- 1 | function EgovRadioButton({ name, label, value, checkedValue, setter }) { 2 | const checked = value === checkedValue; 3 | const toggledClassName = checked ? "f_rdo on" : "f_rdo"; 4 | return ( 5 | 16 | ); 17 | } 18 | 19 | export default EgovRadioButton; 20 | -------------------------------------------------------------------------------- /src/components/EgovRadioButtonGroup.jsx: -------------------------------------------------------------------------------- 1 | import EgovRadioButton from "@/components/EgovRadioButton"; 2 | 3 | function EgovRadioButtonGroup({ name, radioGroup, setValue, setter }) { 4 | return ( 5 | <> 6 | {radioGroup.map((radioOption, i) => { 7 | return ( 8 | 16 | ); 17 | })} 18 | 19 | ); 20 | } 21 | 22 | export default EgovRadioButtonGroup; 23 | -------------------------------------------------------------------------------- /src/components/EgovSelect.jsx: -------------------------------------------------------------------------------- 1 | function EgovSelect({ id, name, title, options, setValue, setter }) { 2 | console.log("egovSelect", id, name, title, options, setValue, setter); 3 | return ( 4 | 22 | ); 23 | } 24 | 25 | export default EgovSelect; 26 | -------------------------------------------------------------------------------- /src/components/EgovViewTemplate.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | function EgovViewTemplate(props) { 4 | console.group("EgovViewTemplate"); 5 | console.log("[Start] EgovViewTemplate ------------------------------"); 6 | console.log("EgovViewTemplate [props] : ", props); 7 | 8 | useEffect(() => { 9 | return () => {}; 10 | }, []); 11 | 12 | console.log("------------------------------EgovViewTemplate [End]"); 13 | console.groupEnd("EgovViewTemplate"); 14 | return ( 15 |
    16 |
    17 |
    18 | ); 19 | } 20 | 21 | export default EgovViewTemplate; 22 | -------------------------------------------------------------------------------- /src/components/leftmenu/EgovLeftNavAbout.jsx: -------------------------------------------------------------------------------- 1 | import { NavLink } from "react-router-dom"; 2 | import URL from "@/constants/url"; 3 | 4 | function EgovLeftNavAbout() { 5 | return ( 6 |
    7 |
    8 |

    사이트 소개

    9 |
      10 |
    • 11 | (isActive ? "cur" : "")} 14 | > 15 | 소개 16 | 17 |
    • 18 |
    • 19 | (isActive ? "cur" : "")} 22 | > 23 | 연혁 24 | 25 |
    • 26 |
    • 27 | (isActive ? "cur" : "")} 30 | > 31 | 조직소개 32 | 33 |
    • 34 |
    • 35 | (isActive ? "cur" : "")} 38 | > 39 | 찾아오시는 길 40 | 41 |
    • 42 |
    43 |
    44 |
    45 | ); 46 | } 47 | 48 | export default EgovLeftNavAbout; 49 | -------------------------------------------------------------------------------- /src/components/leftmenu/EgovLeftNavAdmin.jsx: -------------------------------------------------------------------------------- 1 | import { NavLink } from "react-router-dom"; 2 | import URL from "@/constants/url"; 3 | 4 | function EgovLeftNavAdmin() { 5 | return ( 6 |
    7 |
    8 |

    사이트관리

    9 |
      10 |
    • 11 | (isActive ? "cur" : "")} 14 | > 15 | 일정관리 16 | 17 |
    • 18 |
    • 19 | (isActive ? "cur" : "")} 22 | > 23 | 게시판생성관리 24 | 25 |
    • 26 |
    • 27 | (isActive ? "cur" : "")} 30 | > 31 | 게시판사용관리 32 | 33 |
    • 34 |
    • 35 | (isActive ? "cur" : "")} 38 | > 39 | 공지사항관리 40 | 41 |
    • 42 |
    • 43 | (isActive ? "cur" : "")} 46 | > 47 | 사이트갤러리관리 48 | 49 |
    • 50 |
    • 51 | (isActive ? "cur" : "")} 54 | > 55 | 사이트관리자 암호변경 56 | 57 |
    • 58 |
    • 59 | (isActive ? "cur" : "")} 62 | > 63 | 회원관리 64 | 65 |
    • 66 |
    67 |
    68 |
    69 | ); 70 | } 71 | 72 | export default EgovLeftNavAdmin; 73 | -------------------------------------------------------------------------------- /src/components/leftmenu/EgovLeftNavInform.jsx: -------------------------------------------------------------------------------- 1 | import { NavLink } from "react-router-dom"; 2 | import URL from "@/constants/url"; 3 | 4 | function EgovLeftNavInform() { 5 | console.groupCollapsed("EgovLeftNavInform"); 6 | console.log("[Start] EgovLeftNavInform ------------------------------"); 7 | console.log("------------------------------EgovLeftNavInform [End]"); 8 | console.groupEnd("EgovLeftNavInform"); 9 | return ( 10 |
    11 |
    12 |

    알림마당

    13 |
      14 |
    • 15 | (isActive ? "cur" : "")} 18 | > 19 | 오늘의행사 20 | 21 |
    • 22 |
    • 23 | (isActive ? "cur" : "")} 26 | > 27 | 금주의행사 28 | 29 |
    • 30 |
    • 31 | (isActive ? "cur" : "")} 34 | > 35 | 공지사항 36 | 37 |
    • 38 |
    • 39 | (isActive ? "cur" : "")} 42 | > 43 | 사이트갤러리 44 | 45 |
    • 46 |
    47 |
    48 |
    49 | ); 50 | } 51 | 52 | export default EgovLeftNavInform; 53 | -------------------------------------------------------------------------------- /src/components/leftmenu/EgovLeftNavIntro.jsx: -------------------------------------------------------------------------------- 1 | import { NavLink } from "react-router-dom"; 2 | import URL from "@/constants/url"; 3 | 4 | function EgovLeftNavIntro() { 5 | return ( 6 |
    7 |
    8 |

    정보마당

    9 |
      10 |
    • 11 | (isActive ? "cur" : "")} 14 | > 15 | 주요사업 소개 16 | 17 |
    • 18 |
    • 19 | (isActive ? "cur" : "")} 22 | > 23 | 대표서비스 소개 24 | 25 |
    • 26 |
    27 |
    28 |
    29 | ); 30 | } 31 | 32 | export default EgovLeftNavIntro; 33 | -------------------------------------------------------------------------------- /src/components/leftmenu/EgovLeftNavSupport.jsx: -------------------------------------------------------------------------------- 1 | import { NavLink } from "react-router-dom"; 2 | import URL from "@/constants/url"; 3 | 4 | function EgovLeftNavSupport() { 5 | return ( 6 |
    7 |
    8 |

    고객지원

    9 |
      10 |
    • 11 | (isActive ? "cur" : "")} 14 | > 15 | 자료실 16 | 17 |
    • 18 |
    • 19 | (isActive ? "cur" : "")} 22 | > 23 | 묻고답하기 24 | 25 |
    • 26 |
    • 27 | (isActive ? "cur" : "")} 30 | > 31 | 서비스신청 32 | 33 |
    • 34 |
    35 |
    36 |
    37 | ); 38 | } 39 | 40 | export default EgovLeftNavSupport; 41 | -------------------------------------------------------------------------------- /src/components/sns/SnsKakaoBt.jsx: -------------------------------------------------------------------------------- 1 | const SnsKakaoBt = () => { 2 | const KAKAO_CLIENT_ID = import.meta.env.VITE_APP_KAKAO_CLIENTID; // 발급받은 클라이언트 아이디 3 | const REDIRECT_URI = import.meta.env.VITE_APP_KAKAO_CALLBACKURL; // Callback URL 4 | const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${KAKAO_CLIENT_ID}&redirect_uri=${REDIRECT_URI}`; 5 | 6 | const KakaoLogin = () => { 7 | window.location.href = KAKAO_AUTH_URL; 8 | }; 9 | 10 | return ( 11 | 12 | 13 | 14 | ); 15 | }; 16 | 17 | export default SnsKakaoBt; 18 | -------------------------------------------------------------------------------- /src/components/sns/SnsKakaoCallback.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import * as EgovNet from "@/api/egovFetch"; 3 | import CODE from "@/constants/code"; 4 | import { setSessionItem } from "@/utils/storage"; 5 | 6 | const SnsKakaoCallback = () => { 7 | //백엔드 호출 8 | const callBackEnd = () => { 9 | // 백엔드로 코드값을 넘겨주는 로직 10 | let code = new URL(window.location.href).searchParams.get("code"); 11 | let state = new URL(window.location.href).searchParams.get("state"); 12 | console.log("code, state=====>", code, state); 13 | // 요청이 성공하면 14 | if (code) { 15 | const kakaoLoginUrl = `/login/kakao/callback?code=${code}&state=${state}`; 16 | const requestOptions = { 17 | method: "GET", 18 | headers: { 19 | "Content-type": "application/json", 20 | }, 21 | }; 22 | EgovNet.requestFetch(kakaoLoginUrl, requestOptions, (resp) => { 23 | let resultVO = resp.resultVO; 24 | let jToken = resp?.jToken || null; 25 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 26 | setSessionItem("jToken", jToken); 27 | //setLoginVO(resultVO); 28 | setSessionItem("loginUser", resultVO); 29 | //props.onChangeLogin(resultVO); 30 | // PC와 Mobile 열린메뉴 닫기 31 | document.querySelector(".all_menu.WEB").classList.add("closed"); 32 | document.querySelector(".btnAllMenu").classList.remove("active"); 33 | document.querySelector(".btnAllMenu").title = "전체메뉴 닫힘"; 34 | document.querySelector(".all_menu.Mobile").classList.add("closed"); 35 | alert("Sns 간편 로그인 중..."); //공통 alert 사용대신해서 36 | } else { 37 | //React.StrictMode 에서 fetch가 자동으로 2번 실행할 때 아래 메인화면으로 이동된다. 38 | window.location.replace("/"); 39 | } 40 | }); 41 | } 42 | }; 43 | useEffect(callBackEnd, []); 44 | 45 | return ( 46 | <> 47 | {/* 로그인중이라는 것을 표시할 수 있는 로딩중 화면 */} 48 |

    로그인 중...

    49 | 50 | ); 51 | }; 52 | 53 | export default SnsKakaoCallback; 54 | -------------------------------------------------------------------------------- /src/components/sns/SnsNaverBt.jsx: -------------------------------------------------------------------------------- 1 | const SnsNaverBt = () => { 2 | const NAVER_CLIENT_ID = import.meta.env.VITE_APP_NAVER_CLIENTID; // 발급받은 클라이언트 아이디 3 | const REDIRECT_URI = import.meta.env.VITE_APP_NAVER_CALLBACKURL; // Callback URL 4 | const STATE = import.meta.env.VITE_APP_STATE; //다른 서버와 통신 시 암호화문자 5 | const NAVER_AUTH_URL = `https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=${NAVER_CLIENT_ID}&state=${STATE}&redirect_uri=${REDIRECT_URI}`; 6 | 7 | const NaverLogin = () => { 8 | window.location.href = NAVER_AUTH_URL; 9 | }; 10 | 11 | return ( 12 | 13 | 14 | 15 | ); 16 | }; 17 | 18 | export default SnsNaverBt; 19 | -------------------------------------------------------------------------------- /src/components/sns/SnsNaverCallback.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import * as EgovNet from "@/api/egovFetch"; 3 | import CODE from "@/constants/code"; 4 | import { setSessionItem } from "@/utils/storage"; 5 | 6 | const SnsNaverCallback = () => { 7 | //백엔드 호출 8 | const callBackEnd = () => { 9 | // 백엔드로 코드값을 넘겨주는 로직 10 | let code = new URL(window.location.href).searchParams.get("code"); 11 | let state = new URL(window.location.href).searchParams.get("state"); 12 | console.log("code, state=====>", code, state); 13 | // 요청이 성공하면 14 | if (code) { 15 | const naverLoginUrl = `/login/naver/callback?code=${code}&state=${state}`; 16 | const requestOptions = { 17 | method: "GET", 18 | headers: { 19 | "Content-type": "application/json", 20 | }, 21 | }; 22 | EgovNet.requestFetch(naverLoginUrl, requestOptions, (resp) => { 23 | let resultVO = resp.resultVO; 24 | let jToken = resp?.jToken || null; 25 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 26 | setSessionItem("jToken", jToken); 27 | //setLoginVO(resultVO); 28 | setSessionItem("loginUser", resultVO); 29 | //props.onChangeLogin(resultVO); 30 | // PC와 Mobile 열린메뉴 닫기 31 | document.querySelector(".all_menu.WEB").classList.add("closed"); 32 | document.querySelector(".btnAllMenu").classList.remove("active"); 33 | document.querySelector(".btnAllMenu").title = "전체메뉴 닫힘"; 34 | document.querySelector(".all_menu.Mobile").classList.add("closed"); 35 | alert("Sns 간편 로그인 중..."); //공통 alert 사용대신해서 36 | } else { 37 | //React.StrictMode 에서 fetch가 자동으로 2번 실행할 때 아래 메인화면으로 이동된다. 38 | window.location.replace("/"); 39 | } 40 | }); 41 | } 42 | }; 43 | useEffect(callBackEnd, []); 44 | 45 | return ( 46 | <> 47 | {/* 로그인중이라는 것을 표시할 수 있는 로딩중 화면 */} 48 |

    로그인 중...

    49 | 50 | ); 51 | }; 52 | 53 | export default SnsNaverCallback; 54 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | // Configuration for different environments 2 | export const SERVER_URL = process.env.NODE_ENV === 'test' ? 'http://localhost:8080' : 'http://localhost:8080'; 3 | 4 | export const DEFAULT_BBS_ID = "BBSMSTR_AAAAAAAAAAAA"; // default = 공지사항 게시판 아이디 5 | export const NOTICE_BBS_ID = "BBSMSTR_AAAAAAAAAAAA"; // 공지사항 게시판 아이디 6 | export const GALLERY_BBS_ID = "BBSMSTR_BBBBBBBBBBBB"; // 갤러리 게시판 아이디 7 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | export const SERVER_URL = "http://" + import.meta.env.VITE_APP_EGOV_CONTEXT_URL; // REST API 서버 Domain URL 2 | export const DEFAULT_BBS_ID = "BBSMSTR_AAAAAAAAAAAA"; // default = 공지사항 게시판 아이디 3 | export const NOTICE_BBS_ID = "BBSMSTR_AAAAAAAAAAAA"; // 공지사항 게시판 아이디 4 | export const GALLERY_BBS_ID = "BBSMSTR_BBBBBBBBBBBB"; // 갤러리 게시판 아이디 5 | -------------------------------------------------------------------------------- /src/config/index.jsx: -------------------------------------------------------------------------------- 1 | export const SERVER_URL = "http://"+import.meta.env.VITE_EGOV_CONTEXT_URL; // REST API 서버 Domain URL 2 | export const DEFAULT_BBS_ID = "BBSMSTR_AAAAAAAAAAAA"; // default = 공지사항 게시판 아이디 3 | export const NOTICE_BBS_ID = "BBSMSTR_AAAAAAAAAAAA"; // 공지사항 게시판 아이디 4 | export const GALLERY_BBS_ID = "BBSMSTR_BBBBBBBBBBBB"; // 갤러리 게시판 아이디 5 | -------------------------------------------------------------------------------- /src/constants/code.js: -------------------------------------------------------------------------------- 1 | const CODE = { 2 | RCV_SUCCESS : "200", // 성공 3 | 4 | RCV_ERROR_AUTH : "403", // 인증 오류 5 | RCV_ERROR_DELETE : "700", // 삭제 오류 6 | RCV_ERROR_SAVE : "800", // 저장 오류 7 | RCV_ERROR_VALIDATION : "900", // 입력 오류 8 | 9 | MODE_CREATE : "create", // 등록 모드 10 | MODE_MODIFY : "modify", // 수정 모드 11 | MODE_READ : "read", // 읽기 모드 12 | MODE_REPLY : "reply", // 답글 모드 13 | 14 | DATE_YEAR : "year", 15 | DATE_MONTH : "month", 16 | DATE_DATE : "date", 17 | DATE_WEEK : "week", 18 | DATE_DAY : "day", 19 | } 20 | 21 | export default CODE; -------------------------------------------------------------------------------- /src/constants/code.jsx: -------------------------------------------------------------------------------- 1 | const CODE = { 2 | RCV_SUCCESS : "200", // 성공 3 | 4 | RCV_ERROR_AUTH : "403", // 인증 오류 5 | RCV_ERROR_DELETE : "700", // 삭제 오류 6 | RCV_ERROR_SAVE : "800", // 저장 오류 7 | RCV_ERROR_VALIDATION : "900", // 입력 오류 8 | 9 | MODE_CREATE : "create", // 등록 모드 10 | MODE_MODIFY : "modify", // 수정 모드 11 | MODE_READ : "read", // 읽기 모드 12 | MODE_REPLY : "reply", // 답글 모드 13 | 14 | DATE_YEAR : "year", 15 | DATE_MONTH : "month", 16 | DATE_DATE : "date", 17 | DATE_WEEK : "week", 18 | DATE_DAY : "day", 19 | } 20 | 21 | // eslint-disable-next-line react-refresh/only-export-components 22 | export default CODE; -------------------------------------------------------------------------------- /src/constants/url.js: -------------------------------------------------------------------------------- 1 | const URL = { 2 | //COMMON 3 | MAIN: "/", //메인페이지 4 | 5 | LOGIN: "/login", //로그인 6 | SNS_NAVER_CB: "/login/naver/callback", //Sns Naver Callback 7 | SNS_KAKAO_CB: "/login/kakao/callback", //Sns Kakao Callback 8 | ERROR: "/error", //로그인 9 | 10 | //ABOUT 11 | ABOUT: "/about", //사이트소개 12 | ABOUT_SITE: "/about/site", // 사이트소개/소개 13 | ABOUT_HISTORY: "/about/history", // 사이트소개/연혁 14 | ABOUT_ORGANIZATION: "/about/organization", // 사이트소개/조직소개 15 | ABOUT_LOCATION: "/about/location", // 사이트소개/찾아오시는길 16 | 17 | //INTRO 18 | INTRO: "/intro", //정보마당 19 | INTRO_WORKS: "/intro/works", // 정보마당/주요사업소개 20 | INTRO_SERVICE: "/intro/service", // 정보마당/주요서비스소개 21 | 22 | //SUPPORT 23 | SUPPORT: "/support", // 고객지원 24 | SUPPORT_DOWNLOAD: "/support/download", // 고객지원/자료실 25 | SUPPORT_DOWNLOAD_DETAIL: "/support/download/detail", // 고객지원/자료실/상세 26 | SUPPORT_DOWNLOAD_CREATE: "/support/download/create", // 고객지원/자료실/등록 27 | SUPPORT_QNA: "/support/qna", // 고객지원/묻고답하기 28 | SUPPORT_QNA_DETAIL: "/support/qna/detail", // 고객지원/묻고답하기/상세 29 | SUPPORT_APPLY: "/support/apply", // 고객지원/서비스신청 30 | 31 | //INFORM 32 | INFORM: "/inform", // 알림마당 33 | INFORM_DAILY: "/inform/daily", // 알림마당/오늘의행사 34 | INFORM_DAILY_DETAIL: "/inform/daily/detail", // 알림마당/오늘의행사상세 35 | INFORM_WEEKLY: "/inform/weekly", // 알림마당/금주의행사 36 | INFORM_WEEKLY_DETAIL: "/inform/weekly/detail", // 알림마당/금주의행사상세 37 | INFORM_NOTICE: "/inform/notice", // 알림마당/공지사항 38 | INFORM_NOTICE_DETAIL: "/inform/notice/detail", // 알림마당/공지사항상세 39 | INFORM_NOTICE_CREATE: "/inform/notice/create", // 알림마당/공지사항등록 40 | INFORM_NOTICE_MODIFY: "/inform/notice/modify", // 알림마당/공지사항수정 41 | INFORM_NOTICE_REPLY: "/inform/notice/reply", // 알림마당/공지사항답글 42 | INFORM_GALLERY: "/inform/gallery", // 알림마당/사이트갤러리 43 | INFORM_GALLERY_DETAIL: "/inform/gallery/detail", // 알림마당/사이트갤러리상세 44 | INFORM_GALLERY_CREATE: "/inform/gallery/create", // 알림마당/사이트갤러리등록 45 | INFORM_GALLERY_MODIFY: "/inform/gallery/modify", // 알림마당/사이트갤러리수정 46 | INFORM_GALLERY_REPLY: "/inform/gallery/reply", // 알림마당/사이트갤러리답글 47 | 48 | //ADMIN 49 | ADMIN: "/admin", // 사이트관리 50 | ADMIN_SCHEDULE: "/admin/schedule", // 사이트관리/일정관리 51 | ADMIN_SCHEDULE_DETAIL: "/admin/schedule/detail", // 사이트관리/일정관리상세 52 | ADMIN_SCHEDULE_CREATE: "/admin/schedule/create", // 사이트관리/일정관리생성 53 | ADMIN_SCHEDULE_MODIFY: "/admin/schedule/modify", // 사이트관리/일정관리수정 54 | 55 | ADMIN_BOARD: "/admin/board", // 사이트관리/게시판생성관리 목록 56 | ADMIN_BOARD_DETAIL: "/admin/board/detail", // 사이트관리/게시판생성관리 상세 57 | ADMIN_BOARD_CREATE: "/admin/board/create", // 사이트관리/게시판생성관리 등록 58 | ADMIN_BOARD_MODIFY: "/admin/board/modify", // 사이트관리/게시판생성관리 상세/수정 59 | 60 | ADMIN_USAGE: "/admin/usage", // 사이트관리/게시판사용관리 목록 61 | ADMIN_USAGE_DETAIL: "/admin/usage/detail", // 사이트관리/게시판사용관리 상세 62 | ADMIN_USAGE_CREATE: "/admin/usage/create", // 사이트관리/게시판사용관리 등록 63 | ADMIN_USAGE_MODIFY: "/admin/usage/modify", // 사이트관리/게시판사용관리 상세/수정 64 | 65 | ADMIN_NOTICE: "/admin/notice", // 사이트관리/공지사항관리 목록 66 | ADMIN_NOTICE_DETAIL: "/admin/notice/detail", // 사이트관리/공지사항관리 상세 67 | ADMIN_NOTICE_CREATE: "/admin/notice/create", // 사이트관리/공지사항관리 등록 68 | ADMIN_NOTICE_MODIFY: "/admin/notice/modify", // 사이트관리/공지사항관리 수정 69 | ADMIN_NOTICE_REPLY: "/admin/notice/reply", // 사이트관리/공지사항관리 답글 등록 70 | 71 | ADMIN_GALLERY: "/admin/gallery", // 사이트관리/사이트갤러리관리 72 | ADMIN_GALLERY_DETAIL: "/admin/gallery/detail", // 사이트관리/사이트갤러리관리 상세 73 | ADMIN_GALLERY_CREATE: "/admin/gallery/create", // 사이트관리/사이트갤러리관리 등록 74 | ADMIN_GALLERY_MODIFY: "/admin/gallery/modify", // 사이트관리/사이트갤러리관리 수정 75 | ADMIN_GALLERY_REPLY: "/admin/gallery/reply", // 사이트관리/사이트갤러리관리 답글 등록 76 | 77 | ADMIN_MANAGER: "/admin/manager", // 사이트관리/사이트관리자 암호변경 기능 78 | ADMIN_MEMBERS: "/admin/members", // 사이트관리/회원관리 목록기능 79 | ADMIN_MEMBERS_DETAIL: "/admin/members/detail", // 사이트관리/회원관리 상세 80 | ADMIN_MEMBERS_CREATE: "/admin/members/create", // 사이트관리/회원관리 등록 81 | ADMIN_MEMBERS_MODIFY: "/admin/members/modify", // 사이트관리/회원관리 상세/수정 82 | 83 | //MYPAGE 84 | MYPAGE_MODIFY: "/mypage/modify", // 고객지원/마이페이지/회원 수정 85 | MYPAGE_CREATE: "/mypage/create", // 고객지원/마이페이지/회원 등록 86 | }; 87 | 88 | // eslint-disable-next-line react-refresh/only-export-components 89 | export default URL; 90 | -------------------------------------------------------------------------------- /src/constants/url.jsx: -------------------------------------------------------------------------------- 1 | const URL = { 2 | //COMMON 3 | MAIN: "/egovframe-template-simple-react", //메인페이지 4 | 5 | LOGIN: "/egovframe-template-simple-react/login", //로그인 6 | ERROR: "/egovframe-template-simple-react/error", //로그인 7 | 8 | //ABOUT 9 | ABOUT: "/egovframe-template-simple-react/about", //사이트소개 10 | ABOUT_SITE: "/egovframe-template-simple-react/about/site", // 사이트소개/소개 11 | ABOUT_HISTORY: "/egovframe-template-simple-react/about/history", // 사이트소개/연혁 12 | ABOUT_ORGANIZATION: "/egovframe-template-simple-react/about/organization", // 사이트소개/조직소개 13 | ABOUT_LOCATION: "/egovframe-template-simple-react/about/location", // 사이트소개/찾아오시는길 14 | 15 | //INTRO 16 | INTRO: "/egovframe-template-simple-react/intro", //정보마당 17 | INTRO_WORKS: "/egovframe-template-simple-react/intro/works", // 정보마당/주요사업소개 18 | INTRO_SERVICE: "/egovframe-template-simple-react/intro/service", // 정보마당/주요서비스소개 19 | 20 | //SUPPORT 21 | SUPPORT: "/egovframe-template-simple-react/support", // 고객지원 22 | SUPPORT_DOWNLOAD: "/egovframe-template-simple-react/support/download", // 고객지원/자료실 23 | SUPPORT_DOWNLOAD_DETAIL: 24 | "/egovframe-template-simple-react/support/download/detail", // 고객지원/자료실/상세 25 | SUPPORT_DOWNLOAD_CREATE: 26 | "/egovframe-template-simple-react/support/download/create", // 고객지원/자료실/등록 27 | SUPPORT_QNA: "/egovframe-template-simple-react/support/qna", // 고객지원/묻고답하기 28 | SUPPORT_QNA_DETAIL: "/egovframe-template-simple-react/support/qna/detail", // 고객지원/묻고답하기/상세 29 | SUPPORT_APPLY: "/egovframe-template-simple-react/support/apply", // 고객지원/서비스신청 30 | 31 | //INFORM 32 | INFORM: "/egovframe-template-simple-react/inform", // 알림마당 33 | INFORM_DAILY: "/egovframe-template-simple-react/inform/daily", // 알림마당/오늘의행사 34 | INFORM_DAILY_DETAIL: "/egovframe-template-simple-react/inform/daily/detail", // 알림마당/오늘의행사상세 35 | INFORM_WEEKLY: "/egovframe-template-simple-react/inform/weekly", // 알림마당/금주의행사 36 | INFORM_WEEKLY_DETAIL: "/egovframe-template-simple-react/inform/weekly/detail", // 알림마당/금주의행사상세 37 | INFORM_NOTICE: "/egovframe-template-simple-react/inform/notice", // 알림마당/공지사항 38 | INFORM_NOTICE_DETAIL: "/egovframe-template-simple-react/inform/notice/detail", // 알림마당/공지사항상세 39 | INFORM_NOTICE_CREATE: "/egovframe-template-simple-react/inform/notice/create", // 알림마당/공지사항등록 40 | INFORM_NOTICE_MODIFY: "/egovframe-template-simple-react/inform/notice/modify", // 알림마당/공지사항수정 41 | INFORM_NOTICE_REPLY: "/egovframe-template-simple-react/inform/notice/reply", // 알림마당/공지사항답글 42 | INFORM_GALLERY: "/egovframe-template-simple-react/inform/gallery", // 알림마당/사이트갤러리 43 | INFORM_GALLERY_DETAIL: 44 | "/egovframe-template-simple-react/inform/gallery/detail", // 알림마당/사이트갤러리상세 45 | INFORM_GALLERY_CREATE: 46 | "/egovframe-template-simple-react/inform/gallery/create", // 알림마당/사이트갤러리등록 47 | INFORM_GALLERY_MODIFY: 48 | "/egovframe-template-simple-react/inform/gallery/modify", // 알림마당/사이트갤러리수정 49 | INFORM_GALLERY_REPLY: "/egovframe-template-simple-react/inform/gallery/reply", // 알림마당/사이트갤러리답글 50 | 51 | //ADMIN 52 | ADMIN: "/egovframe-template-simple-react/admin", // 사이트관리 53 | ADMIN_SCHEDULE: "/egovframe-template-simple-react/admin/schedule", // 사이트관리/일정관리 54 | ADMIN_SCHEDULE_DETAIL: 55 | "/egovframe-template-simple-react/admin/schedule/detail", // 사이트관리/일정관리상세 56 | ADMIN_SCHEDULE_CREATE: 57 | "/egovframe-template-simple-react/admin/schedule/create", // 사이트관리/일정관리생성 58 | ADMIN_SCHEDULE_MODIFY: 59 | "/egovframe-template-simple-react/admin/schedule/modify", // 사이트관리/일정관리수정 60 | 61 | ADMIN_BOARD: "/egovframe-template-simple-react/admin/board", // 사이트관리/게시판생성관리 목록 62 | ADMIN_BOARD_DETAIL: "/egovframe-template-simple-react/admin/board/detail", // 사이트관리/게시판생성관리 상세 63 | ADMIN_BOARD_CREATE: "/egovframe-template-simple-react/admin/board/create", // 사이트관리/게시판생성관리 등록 64 | ADMIN_BOARD_MODIFY: "/egovframe-template-simple-react/admin/board/modify", // 사이트관리/게시판생성관리 상세/수정 65 | 66 | ADMIN_USAGE: "/egovframe-template-simple-react/admin/usage", // 사이트관리/게시판사용관리 목록 67 | ADMIN_USAGE_DETAIL: "/egovframe-template-simple-react/admin/usage/detail", // 사이트관리/게시판사용관리 상세 68 | ADMIN_USAGE_CREATE: "/egovframe-template-simple-react/admin/usage/create", // 사이트관리/게시판사용관리 등록 69 | ADMIN_USAGE_MODIFY: "/egovframe-template-simple-react/admin/usage/modify", // 사이트관리/게시판사용관리 상세/수정 70 | 71 | ADMIN_NOTICE: "/egovframe-template-simple-react/admin/notice/", // 사이트관리/공지사항관리 목록 72 | ADMIN_NOTICE_DETAIL: "/egovframe-template-simple-react/admin/notice/detail", // 사이트관리/공지사항관리 상세 73 | ADMIN_NOTICE_CREATE: "/egovframe-template-simple-react/admin/notice/create", // 사이트관리/공지사항관리 등록 74 | ADMIN_NOTICE_MODIFY: "/egovframe-template-simple-react/admin/notice/modify", // 사이트관리/공지사항관리 수정 75 | ADMIN_NOTICE_REPLY: "/egovframe-template-simple-react/admin/notice/reply", // 사이트관리/공지사항관리 답글 등록 76 | 77 | ADMIN_GALLERY: "/egovframe-template-simple-react/admin/gallery", // 사이트관리/사이트갤러리관리 78 | ADMIN_GALLERY_DETAIL: "/egovframe-template-simple-react/admin/gallery/detail", // 사이트관리/사이트갤러리관리 상세 79 | ADMIN_GALLERY_CREATE: "/egovframe-template-simple-react/admin/gallery/create", // 사이트관리/사이트갤러리관리 등록 80 | ADMIN_GALLERY_MODIFY: "/egovframe-template-simple-react/admin/gallery/modify", // 사이트관리/사이트갤러리관리 수정 81 | ADMIN_GALLERY_REPLY: "/egovframe-template-simple-react/admin/gallery/reply", // 사이트관리/사이트갤러리관리 답글 등록 82 | 83 | ADMIN_MANAGER: "/egovframe-template-simple-react/admin/manager/", // 사이트관리/사이트관리자 암호변경 기능 84 | 85 | ADMIN_MEMBERS: "/admin/members/", // 사이트관리/회원관리 목록기능 86 | ADMIN_MEMBERS_DETAIL: "/admin/members/detail", // 사이트관리/회원관리 상세 87 | ADMIN_MEMBERS_CREATE: "/admin/members/create", // 사이트관리/회원관리 등록 88 | ADMIN_MEMBERS_MODIFY: "/admin/members/modify", // 사이트관리/회원관리 상세/수정 89 | 90 | //MYPAGE 91 | MYPAGE_MODIFY: "/mypage/modify", // 고객지원/마이페이지/회원 수정 92 | MYPAGE_CREATE: "/mypage/create", // 고객지원/마이페이지/회원 등록 93 | }; 94 | 95 | // eslint-disable-next-line react-refresh/only-export-components 96 | export default URL; 97 | -------------------------------------------------------------------------------- /src/css/base.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | /* Web Font */ 4 | @font-face {font-family: 'Noto Sans KR';font-style: normal;font-weight: 300; 5 | src: url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Light.woff2) format('woff2'), 6 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Light.woff) format('woff'), 7 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Light.otf) format('opentype');} 8 | 9 | @font-face {font-family: 'Noto Sans KR';font-style: normal;font-weight: 400;src: 10 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.woff2) format('woff2'), 11 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.woff) format('woff'), 12 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.otf) format('opentype');} 13 | 14 | @font-face {font-family: 'Noto Sans KR';font-style: normal;font-weight: 500; 15 | src: url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Medium.woff2) format('woff2'), 16 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Medium.woff) format('woff'), 17 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Medium.otf) format('opentype');} 18 | 19 | @font-face {font-family: 'Noto Sans KR';font-style: normal;font-weight: 700; 20 | src: url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Bold.woff2) format('woff2'), 21 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Bold.woff) format('woff'), 22 | url(https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Bold.otf) format('opentype');} 23 | 24 | /* Reset style */ 25 | * {word-break: keep-all; word-wrap: break-word; box-sizing: border-box; -webkit-box-sizing: border-box;} 26 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, 27 | blockquote, pre, a, abbr, acronym, address, big, cite, code, del, em, font, img, ins, q, s, small, strike, strong, sub, sup, 28 | dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, thead, tbody, tfoot, tr, th, td, input { 29 | margin: 0; padding: 0; 30 | } 31 | 32 | blockquote, button, fieldset, iframe {border: 0;} 33 | cite, em, u, address, i {font-style: normal;} 34 | img {border: 0; vertical-align: top;} 35 | hr, legend {position: absolute; left: -9999px; top: -9999px;} 36 | caption {text-indent: -9999px; font-size: 0;} 37 | li {list-style: none;} 38 | table {width: 100%; table-layout: fixed; border-collapse: collapse;} 39 | a:link, a:visited, a:hover, a:active {text-decoration: none;} 40 | 41 | /* Blind 숨김처리 */ 42 | .blind {position: absolute; left: -9999px; top: -9999px;} 43 | .skip {position: absolute; left: -9999px; top: -9999px;} 44 | 45 | body {font-family: 'Noto Sans KR', sans-serif; font-size: 16px;} 46 | button, textarea {font-family: 'Noto Sans KR', sans-serif;} 47 | button {cursor: pointer;} 48 | 49 | 50 | /* 정렬 */ 51 | .al_c {text-align: center;} 52 | .al_r {text-align: right;} 53 | 54 | 55 | /* 가로길이 */ 56 | .w_full {width: 100%;} 57 | .w_half {width: 50%;} 58 | .w_quarter {width: 25%;} 59 | .w_50 {width: 50px;} 60 | .w_70 {width: 70px;} 61 | .w_80 {width: 80px;} 62 | .w_100 {width: 100px;} 63 | .w_120 {width: 120px;} 64 | .w_130 {width: 130px;} 65 | .w_150 {width: 150px;} 66 | .w_200 {width: 200px;} 67 | .w_250 {width: 250px;} 68 | .w_300 {width: 300px;} 69 | .w_350 {width: 350px;} 70 | .w_400 {width: 400px;} 71 | .w_500 {width: 500px;} 72 | 73 | .h_30 {height: 30px;} 74 | .h_100 {height: 100px;} 75 | 76 | 77 | /* 여백 */ 78 | .mt0 {margin-top: 0 !important;} 79 | .mt10 {margin-top: 10px !important;} 80 | .mt40 {margin-top: 40px !important;} 81 | .ml10 {margin-left: 10px !important;} 82 | .pb10 {padding-bottom: 10px !important;} -------------------------------------------------------------------------------- /src/css/images/bg_btn_calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/bg_btn_calendar.png -------------------------------------------------------------------------------- /src/css/images/bg_ds_t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/bg_ds_t2.png -------------------------------------------------------------------------------- /src/css/images/bg_form_chk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/bg_form_chk.png -------------------------------------------------------------------------------- /src/css/images/bg_form_chk_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/bg_form_chk_on.png -------------------------------------------------------------------------------- /src/css/images/bg_form_rdo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/bg_form_rdo.png -------------------------------------------------------------------------------- /src/css/images/bg_form_rdo_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/bg_form_rdo_on.png -------------------------------------------------------------------------------- /src/css/images/ico_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_address.png -------------------------------------------------------------------------------- /src/css/images/ico_allmenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_allmenu.png -------------------------------------------------------------------------------- /src/css/images/ico_allmenu_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_allmenu_close.png -------------------------------------------------------------------------------- /src/css/images/ico_arrow_black_36x20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_arrow_black_36x20.png -------------------------------------------------------------------------------- /src/css/images/ico_arrow_gray_15x9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_arrow_gray_15x9.png -------------------------------------------------------------------------------- /src/css/images/ico_arrow_r_gray_4x7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_arrow_r_gray_4x7.png -------------------------------------------------------------------------------- /src/css/images/ico_arrow_r_gray_9x15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_arrow_r_gray_9x15.png -------------------------------------------------------------------------------- /src/css/images/ico_arrow_up_gray_16x9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_arrow_up_gray_16x9.png -------------------------------------------------------------------------------- /src/css/images/ico_bn01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_bn01.png -------------------------------------------------------------------------------- /src/css/images/ico_bn02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_bn02.png -------------------------------------------------------------------------------- /src/css/images/ico_bn03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_bn03.png -------------------------------------------------------------------------------- /src/css/images/ico_bn04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_bn04.png -------------------------------------------------------------------------------- /src/css/images/ico_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_call.png -------------------------------------------------------------------------------- /src/css/images/ico_close_black44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_close_black44.png -------------------------------------------------------------------------------- /src/css/images/ico_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_delete.png -------------------------------------------------------------------------------- /src/css/images/ico_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_down.png -------------------------------------------------------------------------------- /src/css/images/ico_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_error.png -------------------------------------------------------------------------------- /src/css/images/ico_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_file.png -------------------------------------------------------------------------------- /src/css/images/ico_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_home.png -------------------------------------------------------------------------------- /src/css/images/ico_mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_mail.png -------------------------------------------------------------------------------- /src/css/images/ico_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_more.png -------------------------------------------------------------------------------- /src/css/images/ico_person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_person.png -------------------------------------------------------------------------------- /src/css/images/ico_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_plus.png -------------------------------------------------------------------------------- /src/css/images/ico_prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_prev.png -------------------------------------------------------------------------------- /src/css/images/ico_question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_question.png -------------------------------------------------------------------------------- /src/css/images/ico_reply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_reply.png -------------------------------------------------------------------------------- /src/css/images/ico_req.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_req.png -------------------------------------------------------------------------------- /src/css/images/ico_search_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_search_b.png -------------------------------------------------------------------------------- /src/css/images/ico_service_intro1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_service_intro1.png -------------------------------------------------------------------------------- /src/css/images/ico_service_intro2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_service_intro2.png -------------------------------------------------------------------------------- /src/css/images/ico_subway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_subway.png -------------------------------------------------------------------------------- /src/css/images/ico_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/ico_v.png -------------------------------------------------------------------------------- /src/css/images/icon_google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/icon_google.png -------------------------------------------------------------------------------- /src/css/images/icon_kakao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/icon_kakao.png -------------------------------------------------------------------------------- /src/css/images/icon_naver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/icon_naver.png -------------------------------------------------------------------------------- /src/css/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/src/css/images/logo.jpg -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter } from 'react-router-dom'; 3 | import App from './App'; 4 | import reportWebVitals from './reportWebVitals'; 5 | import { createRoot } from 'react-dom/client'; 6 | 7 | const root = createRoot(document.getElementById("root")); 8 | root.render( 9 | 10 | 11 | 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /src/js/ui.js: -------------------------------------------------------------------------------- 1 | let init = false; 2 | 3 | export default function initPage() { 4 | const sessionUser = sessionStorage.getItem("loginUser"); 5 | const sessionUserId = JSON.parse(sessionUser)?.id; 6 | 7 | if (sessionUserId === "admin") { 8 | // Mobile 서브메뉴 항목 클릭시 메뉴 닫기 9 | document.querySelectorAll(".all_menu.Mobile .submenu a").forEach((el) => { 10 | el.removeEventListener("click", handleSubmenuClick); 11 | el.addEventListener("click", handleSubmenuClick); 12 | }); 13 | 14 | // 모바일 관리자 하위 메뉴 열고 닫기 15 | const nodes = document.querySelectorAll(".all_menu.Mobile h3 a"); 16 | const last_submenu = nodes[nodes.length - 1]; 17 | last_submenu.removeEventListener("click", handleLastSubmenuClick); 18 | last_submenu.addEventListener("click", handleLastSubmenuClick); 19 | } 20 | 21 | if (init) return; 22 | init = true; 23 | 24 | /* 전체메뉴 */ 25 | // 웹 26 | const webMenuButton = document.querySelector(".btnAllMenu"); 27 | if (webMenuButton) { 28 | webMenuButton.addEventListener("click", handleWebMenuToggle); 29 | } 30 | 31 | // 모바일 전체메뉴 열기 32 | const mobileMenuButton = document.querySelector(".btnAllMenuM"); 33 | if (mobileMenuButton) { 34 | mobileMenuButton.addEventListener("click", handleMobileMenuOpen); 35 | } 36 | 37 | // 닫기 38 | const mobileUserInfoClose = document.querySelector(".user_info_m .close"); 39 | if (mobileUserInfoClose) { 40 | mobileUserInfoClose.addEventListener("click", handleMobileMenuClose); 41 | } 42 | 43 | // PC 메뉴 항목 클릭시 메뉴 닫기 44 | const webAllMenu = document.querySelector(".all_menu.WEB"); 45 | if (webAllMenu) { 46 | webAllMenu.addEventListener("click", handleWebMenuClose); 47 | } 48 | 49 | // 회원가입, 마이페이지 항목 클릭시 메뉴 닫기 50 | const webUserInfo = document.querySelector(".user_info"); 51 | if (webUserInfo) { 52 | webUserInfo.addEventListener("click", handleWebMenuClose); 53 | } 54 | 55 | // 회원가입, 마이페이지 항목 클릭시 모바일 전체메뉴 열기 56 | const mobileUserInfo = document.querySelector(".user_info_m"); 57 | if (mobileUserInfo) { 58 | mobileUserInfo.addEventListener("click", handleMobileMenuClose); 59 | } 60 | 61 | // Mobile 서브메뉴 항목 클릭시 메뉴 닫기 62 | document.querySelectorAll(".all_menu.Mobile .submenu a").forEach((el) => { 63 | el.removeEventListener("click", handleSubmenuClick); 64 | el.addEventListener("click", handleSubmenuClick); 65 | }); 66 | 67 | // 모바일 하위 메뉴 열고 닫기 68 | document.querySelectorAll(".all_menu.Mobile h3 a").forEach((el) => { 69 | el.removeEventListener("click", handleMobileSubmenuToggle); 70 | el.addEventListener("click", handleMobileSubmenuToggle); 71 | }); 72 | 73 | document.addEventListener("click", handleGlobalClick); 74 | 75 | // 홈페이지 템플릿 소개팝업 76 | const template = { 77 | init: function () { 78 | this.$tg = document.querySelector(".TEMPLATE_INTRO"); 79 | this.$btn = document.querySelector(".lnk_go_template"); 80 | this.$btnClose = this.$tg.querySelector(".pop_header .close"); 81 | this.addEvent(); 82 | }, 83 | addEvent: function () { 84 | this.$btn.addEventListener("click", this.handleOpenPopup.bind(this)); 85 | this.$btnClose.addEventListener( 86 | "click", 87 | this.handleClosePopup.bind(this) 88 | ); 89 | }, 90 | handleOpenPopup: function (e) { 91 | e.preventDefault(); 92 | this.$tg.style.display = "block"; 93 | }, 94 | handleClosePopup: function (e) { 95 | e.preventDefault(); 96 | this.$tg.style.display = "none"; 97 | }, 98 | }; 99 | document.querySelector(".lnk_go_template") && template.init(); 100 | } 101 | 102 | // Event Handlers 103 | function handleSubmenuClick() { 104 | document.querySelector(".all_menu.Mobile").classList.add("closed"); 105 | } 106 | 107 | function handleLastSubmenuClick(e) { 108 | e.preventDefault(); 109 | const el = e.currentTarget; 110 | el.classList.toggle("active"); 111 | 112 | const submenu = el.parentElement.nextElementSibling; 113 | if (submenu && submenu.matches(".submenu")) { 114 | if (submenu.classList.contains("closed")) { 115 | submenu.style.height = submenu.scrollHeight + "px"; 116 | submenu.classList.remove("closed"); 117 | } else { 118 | submenu.classList.add("closed"); 119 | submenu.style.height = ""; 120 | } 121 | } 122 | } 123 | 124 | function handleWebMenuToggle(e) { 125 | const el = e.target; 126 | 127 | el.classList.toggle("active"); 128 | 129 | const menu = document.querySelector(".all_menu.WEB"); 130 | if (menu.matches(".closed")) { 131 | menu.classList.remove("closed"); 132 | el.title = "전체메뉴 닫힘"; 133 | } else { 134 | menu.classList.add("closed"); 135 | el.title = "전체메뉴 열림"; 136 | } 137 | } 138 | 139 | function handleMobileMenuOpen(e) { 140 | document.querySelector(".all_menu.Mobile").classList.remove("closed"); 141 | e.target.title = "전체메뉴 열림"; 142 | } 143 | 144 | function handleMobileMenuClose() { 145 | document.querySelector(".all_menu.Mobile").classList.add("closed"); 146 | document.querySelector(".btnAllMenuM").title = "전체메뉴 닫힘"; 147 | } 148 | 149 | function handleWebMenuClose(e) { 150 | if (e.target.matches("a")) { 151 | document.querySelector(".all_menu.WEB").classList.add("closed"); 152 | document.querySelector(".btnAllMenu").classList.remove("active"); 153 | document.querySelector(".btnAllMenu").title = "전체메뉴 닫힘"; 154 | } 155 | } 156 | 157 | function handleMobileSubmenuToggle(e) { 158 | e.preventDefault(); 159 | const el = e.target; 160 | el.classList.toggle("active"); 161 | 162 | const submenu = el.parentElement.nextElementSibling; 163 | if (submenu.matches(".closed")) { 164 | submenu.style.height = submenu.scrollHeight + "px"; 165 | submenu.classList.remove("closed"); 166 | } else { 167 | submenu.classList.add("closed"); 168 | submenu.style.height = ""; 169 | } 170 | } 171 | 172 | function handleGlobalClick(e) { 173 | const el = e.target; 174 | 175 | if (el.matches(".mini_board .tab li a")) { 176 | e.preventDefault(); 177 | const tabs = el.closest(".tab"); 178 | 179 | tabs.querySelectorAll("a").forEach((a) => a.classList.remove("on")); 180 | el.classList.add("on"); 181 | 182 | const divs = document.querySelectorAll(".mini_board .list > div"); 183 | divs.forEach((div) => (div.style.display = "none")); 184 | 185 | const idx = Array.prototype.indexOf.call(tabs.querySelectorAll("a"), el); 186 | divs[idx].style.display = "block"; 187 | } else if (el.matches(".f_chk input")) { 188 | el.parentElement.classList[el.checked ? "add" : "remove"]("on"); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | 5 | ReactDOM.createRoot(document.getElementById("root")).render( 6 | 7 | 8 | 9 | ); 10 | -------------------------------------------------------------------------------- /src/pages/about/EgovAboutHistory.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import URL from "@/constants/url"; 4 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAbout"; 5 | 6 | function EgovAboutHistory() { 7 | return ( 8 |
    9 |
    10 | {/* */} 11 |
    12 |
      13 |
    • 14 | 15 | Home 16 | 17 |
    • 18 |
    • 19 | 사이트 소개 20 |
    • 21 |
    • 연혁
    • 22 |
    23 |
    24 | {/* */} 25 | 26 |
    27 | {/* */} 28 | 29 | {/* */} 30 | 31 |
    32 | {/* */} 33 | 34 |

    사이트 소개

    35 | 36 |

    37 | 표준프레임워크 경량환경 포털사이트를 소개합니다. 38 |

    39 | 40 |

    전자정부표준프레임워크 연혁

    41 | 42 |

    연혁

    43 | 44 |

    45 | 표준프레임워크 활성화 전담조직으로 한국정보화진흥원(NIA)에 2010년 46 | 11월 4일 「표준프레임워크센터」가
    47 | 설립되었으며 정책지원, 글로벌 확산 등을 담당할 NIA 인력과 R&D, 48 | 기술지원 등을 담당할 외부 민간 전문가로
    49 | 구성되었습니다. 50 |

    51 | 52 | {/* */} 53 |
    54 |
    55 |
    56 |
    57 | ); 58 | } 59 | 60 | export default EgovAboutHistory; 61 | -------------------------------------------------------------------------------- /src/pages/about/EgovAboutLocation.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import URL from "@/constants/url"; 4 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAbout"; 5 | 6 | import mapImg from "/assets/images/map.png"; 7 | import qrImg from "/assets/images/qrcode.png"; 8 | 9 | function EgovAboutLocation() { 10 | return ( 11 |
    12 |
    13 | {/* */} 14 |
    15 |
      16 |
    • 17 | 18 | Home 19 | 20 |
    • 21 |
    • 22 | 사이트 소개 23 |
    • 24 |
    • 찾아오시는길
    • 25 |
    26 |
    27 | {/* */} 28 | 29 |
    30 | {/* */} 31 | 32 | {/* */} 33 | 34 |
    35 | {/* */} 36 | 37 |

    사이트 소개

    38 | 39 |

    40 | 표준프레임워크 경량환경 포털사이트를 소개합니다. 41 |

    42 | 43 |

    찾아오시는길

    44 | 45 |
    46 | 51 | 52 | 53 |
    54 | 55 |
    56 |
    57 |

    표준프레임워크센터 주소

    58 |
    59 |
    도로명주소
    60 |
    61 | 04513 서울특별시 중구 세종대로 39 대한서울상공회의소 7층 62 |
    63 |
    64 |
    65 |
    지번주소
    66 |
    67 | 04513 서울특별시 중구 남대문로4가 45 대한서울상공회의소 7층 68 |
    69 |
    70 |
    71 |
    72 |

    QR코드로 위치알아보기

    73 |

    74 | 스마트폰에서 QR코드 75 |
    76 | 리더를 이용해 사진· 77 |
    78 | 지도 등 다양한 정보를 79 |
    80 | 확인하세요. 81 |

    82 | qr code 83 |
    84 |
    85 | 86 |
    87 |
    88 |

    찾아오시는 길

    89 |
    90 |
    지하철 2호선
    91 |
    시청역 9번 출구 5분거리
    92 |
    93 |
    94 |
    지하철 1호선
    95 |
    서울역 3번 출구 5분거리
    96 |
    97 |
    98 |
    99 |

    연락처

    100 |
    101 |
    전화
    102 |
    0000-0000
    103 |
    104 |
    105 |
    이메일
    106 |
    egovframeexample@gmail.com
    107 |
    108 |
    109 |
    110 | 111 | {/* */} 112 |
    113 |
    114 |
    115 |
    116 | ); 117 | } 118 | 119 | export default EgovAboutLocation; 120 | -------------------------------------------------------------------------------- /src/pages/about/EgovAboutOrganization.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import URL from "@/constants/url"; 4 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAbout"; 5 | 6 | function EgovAboutOrganization() { 7 | return ( 8 |
    9 |
    10 | {/* */} 11 |
    12 |
      13 |
    • 14 | 15 | Home 16 | 17 |
    • 18 |
    • 19 | 사이트 소개 20 |
    • 21 |
    • 조직소개
    • 22 |
    23 |
    24 | {/* */} 25 | 26 |
    27 | {/* */} 28 | 29 | {/* */} 30 | 31 |
    32 | {/* */} 33 | 34 |

    사이트 소개

    35 | 36 |

    37 | 표준프레임워크 경량환경 포털사이트를 소개합니다. 38 |

    39 | 40 |

    조직소개

    41 | 42 |

    조직

    43 | 44 |

    45 | 오픈커뮤니티의 초기 정착을 위해 표준프레임워크 개발 참여자와 국내 46 | 주요 오픈커뮤니티의 운영자·전문가를 리딩 47 |
    48 | 그룹(PMC, 커미터)으로 구성 오픈커뮤니티의 지속적인 확대·발전을 49 | 위해 프로젝트 활동에 적극적으로 참여하는
    50 | 커뮤니티 회원이 리딩그룹의 역할을 획득할 수 있도록 투명하고 공정한 51 | 의사결정 체계를 수립 52 |

    53 | 54 | {/* */} 55 |
    56 |
    57 |
    58 |
    59 | ); 60 | } 61 | 62 | export default EgovAboutOrganization; 63 | -------------------------------------------------------------------------------- /src/pages/about/EgovAboutSite.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAbout"; 4 | 5 | function EgovAboutSite() { 6 | return ( 7 |
    8 |
    9 | {/* */} 10 |
    11 |
      12 |
    • 13 | 14 | Home 15 | 16 |
    • 17 |
    • 18 | 사이트 소개 19 |
    • 20 |
    • 소개
    • 21 |
    22 |
    23 | {/* */} 24 | 25 |
    26 | {/* */} 27 | 28 | {/* */} 29 | 30 |
    31 | {/* */} 32 | 33 |

    사이트 소개

    34 | 35 |

    36 | 표준프레임워크 경량환경의 개요와 연혁, 조직소개, 37 |
    38 | 표준프레임워크센터의 약도 등의 정보를 제공하고 있습니다. 39 |

    40 | 41 |

    전자정부표준프레임워크 소개

    42 | 43 |

    개요

    44 | 45 |

    46 | 전자정부 표준 프레임워크는 응용SW의 구성기반이 되며 응용SW실행 시 47 | 필요한 기본 기능을 제공하는 환경이다. 48 |
    49 | 전자정부 표준 프레임워크는 ‘전자정부 서비스의 품질향상 및 정보화 50 | 투자 효율성 향상’을 위해 개발 프레임워크 51 |
    52 | 표준을 정립하고, 개발 프레임워크 표준 적용을 통한 응용 SW의 표준화 53 | 및 품질과 재사용성 향상을 목표로 한다. 54 |

    55 | 56 |
    57 |

    58 | 전자정부 서비스 품질향상 및 정보화투자 효율성 향상 59 |

    60 | 61 |
      62 |
    • 63 | 국가 정보화 64 |
      65 | 투자효율성 제고 66 |
    • 67 |
    • 68 | 중소SI업체 69 |
      70 | 경쟁력 확보 71 |
    • 72 |
    • 73 | 선진 국가정보화 74 |
      75 | 기반환경 제공 76 |
    • 77 |
    78 | 79 |

    80 | 전자정부표준프레임워크 81 |
    82 | 활용 83 |

    84 | 85 |
    86 |

    87 | 전자정부표준프레임워크 구축 및 적용 요구 88 |

    89 |
      90 |
    • 91 | 92 | 특정업체 종속성 발생으로 93 |
      94 | 인한 공정경쟁 저하 및 사업자 95 |
      96 | 변경 시 예산낭비 97 |
      98 |
    • 99 |
    • 100 | 101 | 기관별/사업별 개별적인 102 |
      103 | 정보화 사업추진으로 중복개발 104 |
      105 |
    • 106 |
    • 107 | 108 | 표준화된 공통 개발기반 부재로 109 |
      110 | 시스템간 상호 운용성 및
      111 | 재사용성 저하 112 |
      113 |
    • 114 |
    115 |

    116 | 전자정부표준프레임워크는 응용SW의 구성기반이 되며 응용SW실행 117 | 시 필요한 기본 기능을 제공하는 환경으로 정보시스템 구축 시 118 | 특정 대기업의 프레임워크로 구축·운영되어, 사업자 종속-비용증가 119 | 및 중소기업의 입찰제한 등의 폐단이 발생하는 것을 방지하기 위한 120 | 목적과 ‘전자정부 서비스의 품질향상 및 정보화 투자 효율성 121 | 향상’을 위해 개발 프레임워크 표준을 정립하고, 개발 프레임워크 122 | 표준 적용을 통한 응용 SW의 표준화 및 품질과 재사용성 향상을 123 | 목표로 한다. 124 |

    125 |
    126 | 127 |

    배경

    128 |

    129 | 현재 전자정부는 유사한 기능을 가지는 다양한 종류 및 버전의 130 | 프레임워크를 개별 시스템 단위로 적용/관리하고 있으며, 이에 따라 131 | 다양한 문제점들이 발생하고 있다. 전자정부에 적용된 132 | 개발프레임워크는 Black Box 형태로 제공되어 사업자의 기술지원 133 | 없이는 응용 SW를 유지보수하기 어렵기 때문에 사업자에 대한 134 | 의존성이 발생한다. 복수개의 개발프레임워크가 적용된 사업의 경우, 135 | 프레임워크에 따라 개발표준 정의, 개발자수급, 교육시행 등 별도의 136 | 유지보수 체계를 갖추는 중복 투자가 발생하며, 개발프레임워크의 137 | 체계적인 관리절차의 미비로 동일 개발프레임워크라 하더라도 버전 138 | 관리에 어려움이 있다.전자정부의 프레임워크의 표준화는 사업자 139 | 고유 개발 프레임워크에 대한 기술 종속성을 배제하고 표준화를 통해 140 | 응용 SW의 표준화와 품질, 재사용성을 향상시키며, 개발 141 | 프레임워크의 유지 보수 단일화를 통한 투자 효율성을 높인다. 142 |

    143 | 144 |

    특징

    145 |

    146 | 현재 전자정부는 유사한 기능을 가지는 다양한 종류 및 버전의 147 | 프레임워크를 개별 시스템 단위로 적용/관리하고 있으며, 이에 따라 148 | 다양한 문제점들이 발생하고 있다. 전자정부에 적용된 149 | 개발프레임워크는 Black Box 형태로 제공되어 사업자의 기술지원 150 | 없이는 응용 SW를 유지보수하기 어렵기 때문에 사업자에 대한 151 | 의존성이 발생한다. 복수개의 개발프레임워크가 적용된 사업의 경우, 152 | 프레임워크에 따라 개발표준 정의, 개발자수급, 교육시행 등 별도의 153 | 유지보수 체계를 갖추는 중복 투자가 발생하며, 개발프레임워크의 154 | 체계적인 관리절차의 미비로 동일 개발프레임워크라 하더라도 버전 155 | 관리에 어려움이 있다.전자정부의 프레임워크의 표준화는 사업자 156 | 고유 개발 프레임워크에 대한 기술 종속성을 배제하고 표준화를 통해 157 | 응용 SW의 표준화와 품질, 재사용성을 향상시키며, 개발 158 | 프레임워크의 유지 보수 단일화를 통한 투자 효율성을 높인다. 159 |

    160 |
    161 | 162 | {/* */} 163 |
    164 |
    165 |
    166 |
    167 | ); 168 | } 169 | 170 | export default EgovAboutSite; 171 | -------------------------------------------------------------------------------- /src/pages/admin/gallery/EgovAdminGalleryDetail.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | import { Link, useLocation, useNavigate } from "react-router-dom"; 4 | 5 | import * as EgovNet from "@/api/egovFetch"; 6 | import URL from "@/constants/url"; 7 | import CODE from "@/constants/code"; 8 | import { GALLERY_BBS_ID } from "@/config"; 9 | 10 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAdmin"; 11 | import EgovAttachFile from "@/components/EgovAttachFile"; 12 | import EgovImageGallery from "@/components/EgovImageGallery"; 13 | 14 | function EgovAdminGalleryDetail(props) { 15 | console.group("EgovAdminGalleryDetail"); 16 | console.log("------------------------------"); 17 | console.log("EgovAdminGalleryDetail [props] : ", props); 18 | 19 | const navigate = useNavigate(); 20 | const location = useLocation(); 21 | console.log("EgovAdminGalleryDetail [location] : ", location); 22 | 23 | const bbsId = location.state.bbsId || GALLERY_BBS_ID; 24 | const nttId = location.state.nttId; 25 | const searchCondition = location.state.searchCondition; 26 | 27 | const [masterBoard, setMasterBoard] = useState({}); 28 | const [boardDetail, setBoardDetail] = useState({}); 29 | const [boardAttachFiles, setBoardAttachFiles] = useState(); 30 | 31 | const retrieveDetail = () => { 32 | const retrieveDetailURL = `/board/${bbsId}/${nttId}`; 33 | const requestOptions = { 34 | method: "GET", 35 | headers: { 36 | "Content-type": "application/json", 37 | }, 38 | }; 39 | EgovNet.requestFetch(retrieveDetailURL, requestOptions, function (resp) { 40 | setMasterBoard(resp.result.brdMstrVO); 41 | setBoardDetail(resp.result.boardVO); 42 | setBoardAttachFiles(resp.result.resultFiles); 43 | }); 44 | }; 45 | 46 | const onClickDeleteBoardArticle = (bbsId, nttId) => { 47 | const deleteBoardURL = `/board/${bbsId}/${nttId}`; 48 | 49 | const requestOptions = { 50 | method: "PATCH", 51 | headers: { 52 | "Content-type": "application/json", 53 | }, 54 | }; 55 | 56 | EgovNet.requestFetch(deleteBoardURL, requestOptions, (resp) => { 57 | console.log("====>>> board delete= ", resp); 58 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 59 | alert("게시글이 삭제되었습니다."); 60 | navigate(URL.ADMIN_GALLERY, { replace: true }); 61 | } else { 62 | // alert("ERR : " + resp.message); 63 | navigate( 64 | { pathname: URL.ERROR }, 65 | { state: { msg: resp.resultMessage } } 66 | ); 67 | } 68 | }); 69 | }; 70 | 71 | useEffect(function () { 72 | retrieveDetail(); 73 | // eslint-disable-next-line react-hooks/exhaustive-deps 74 | }, []); 75 | 76 | console.groupEnd("EgovAdminGalleryDetail"); 77 | 78 | return ( 79 |
    80 |
    81 | {/* */} 82 |
    83 |
      84 |
    • 85 | 86 | Home 87 | 88 |
    • 89 |
    • 90 | 사이트관리 91 |
    • 92 |
    • {masterBoard && masterBoard.bbsNm}
    • 93 |
    94 |
    95 | {/* */} 96 | 97 |
    98 | {/* */} 99 | 100 | {/* */} 101 | 102 |
    103 | {/* */} 104 | 105 |
    106 |

    사이트관리

    107 |
    108 | 109 |

    {masterBoard && masterBoard.bbsNm}

    110 | 111 | {/* */} 112 |
    113 |
    114 |
    {boardDetail && boardDetail.nttSj}
    115 |
    116 |
    117 |
    작성자
    118 |
    {boardDetail && boardDetail.frstRegisterNm}
    119 |
    120 |
    121 |
    작성일
    122 |
    {boardDetail && boardDetail.frstRegisterPnttm}
    123 |
    124 |
    125 |
    조회수
    126 |
    {boardDetail && boardDetail.inqireCo}
    127 |
    128 |
    129 |
    130 | 131 |
    132 | 139 |
    140 | 141 | 142 | 143 |
    144 | {/* 답글이 아니고 게시판 파일 첨부 가능 상태에서만 첨부파일 컴포넌트 노출 */} 145 | {boardDetail.parnts === "0" && 146 | masterBoard.fileAtchPosblAt === "Y" && ( 147 | 148 | )} 149 |
    150 | 151 |
    152 | {masterBoard.bbsUseFlag === "Y" && ( 153 |
    154 | 162 | 수정 163 | 164 | { 168 | e.preventDefault(); 169 | onClickDeleteBoardArticle( 170 | boardDetail.bbsId, 171 | boardDetail.nttId 172 | ); 173 | }} 174 | > 175 | 삭제 176 | 177 | {masterBoard.replyPosblAt === "Y" && ( 178 | 186 | 답글작성 187 | 188 | )} 189 |
    190 | )} 191 |
    192 | 201 | 목록 202 | 203 |
    204 |
    205 |
    206 | {/* */} 207 | 208 | {/* */} 209 |
    210 |
    211 |
    212 |
    213 | ); 214 | } 215 | 216 | export default EgovAdminGalleryDetail; 217 | -------------------------------------------------------------------------------- /src/pages/admin/manager/EgovAdminPasswordUpdate.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { Link, useNavigate } from "react-router-dom"; 3 | import * as EgovNet from "@/api/egovFetch"; 4 | import URL from "@/constants/url"; 5 | import CODE from "@/constants/code"; 6 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAdmin"; 7 | 8 | function EgovAdminPasswordUpdate(props) { 9 | console.group("EgovAdminPasswordUpdate"); 10 | console.log("[Start] EgovAdminPasswordUpdate ------------------------------"); 11 | console.log("EgovAdminPasswordUpdate [props] : ", props); 12 | 13 | const navigate = useNavigate(); 14 | const [oldPassword, setOldPassword] = useState(""); 15 | const [newPassword, setNewPassword] = useState(""); 16 | const [confirmPassword, setConfirmPassword] = useState(""); 17 | const formValidator = (formData) => { 18 | if ( 19 | formData.get("old_password") === null || 20 | formData.get("old_password") === "" 21 | ) { 22 | alert("기존 암호는 필수 값입니다."); 23 | return false; 24 | } 25 | if ( 26 | formData.get("new_password") === null || 27 | formData.get("new_password") === "" 28 | ) { 29 | alert("신규 암호는 필수 값입니다."); 30 | return false; 31 | } 32 | if (formData.get("new_password") === formData.get("old_password")) { 33 | alert("신규 암호는 기존 암호와 동일하게 사용할 수 없습니다."); 34 | return false; 35 | } 36 | return true; 37 | }; 38 | 39 | const updateAdminPassword = () => { 40 | if (newPassword !== confirmPassword) { 41 | return alert("신규 암호와 입력 확인값이 일치하지 않습니다"); 42 | } 43 | 44 | const editURL = "/admin/password"; 45 | 46 | let requestOptions = {}; 47 | const formData = new FormData(); 48 | formData.append("old_password", oldPassword); 49 | formData.append("new_password", newPassword); 50 | if (formValidator(formData)) { 51 | requestOptions = { 52 | method: "PATCH", 53 | headers: { 54 | "Content-type": "application/json", 55 | }, 56 | body: JSON.stringify({ 57 | old_password: oldPassword, 58 | new_password: newPassword, 59 | }), 60 | }; 61 | EgovNet.requestFetch(editURL, requestOptions, (resp) => { 62 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 63 | alert("OK 다음 로그인 시 신규 암호를 사용하세요."); 64 | navigate({ pathname: URL.MAIN }, { replace: true }); 65 | } else { 66 | alert("Fail 변경되지 않았습니다. 다시 시도해 주세요."); 67 | navigate( 68 | { pathname: URL.ERROR }, 69 | { state: { msg: resp.resultMessage } } 70 | ); //에러메세지 변수명 변경 71 | } 72 | }); 73 | } 74 | }; 75 | 76 | useEffect(() => { 77 | // eslint-disable-next-line react-hooks/exhaustive-deps 78 | }, []); 79 | 80 | console.log("------------------------------EgovAdminPasswordUpdate [End]"); 81 | console.groupEnd("EgovAdminPasswordUpdate"); 82 | 83 | return ( 84 |
    85 |
    86 | {/* */} 87 |
    88 |
      89 |
    • 90 | 91 | Home 92 | 93 |
    • 94 |
    • 95 | 사이트관리 96 |
    • 97 |
    • 사이트관리자 암호변경
    • 98 |
    99 |
    100 | {/* */} 101 | 102 |
    103 | {/* */} 104 | 105 | {/* */} 106 | 107 |
    108 | {/* */} 109 | 110 |
    111 |

    사이트관리

    112 |
    113 |

    사이트관리자 암호변경

    114 |
    115 |
    116 |
    117 | 118 | 필수 119 |
    120 |
    121 | setOldPassword(e.target.value)} 130 | /> 131 |
    132 |
    133 |
    134 |
    135 | 136 | 필수 137 |
    138 |
    139 | setNewPassword(e.target.value)} 148 | /> 149 |
    150 |
    151 |
    152 |
    153 | 154 | 필수 155 |
    156 |
    157 | setConfirmPassword(e.target.value)} 166 | /> 167 |
    168 |
    169 | {/* */} 170 |
    171 |
    172 | 178 |
    179 |
    180 | {/* */} 181 |
    182 | {/* */} 183 |
    184 |
    185 |
    186 |
    187 | ); 188 | } 189 | 190 | export default EgovAdminPasswordUpdate; 191 | -------------------------------------------------------------------------------- /src/pages/admin/notice/EgovAdminNoticeDetail.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | import { Link, useLocation, useNavigate } from "react-router-dom"; 4 | 5 | import * as EgovNet from "@/api/egovFetch"; 6 | import URL from "@/constants/url"; 7 | import CODE from "@/constants/code"; 8 | import { NOTICE_BBS_ID } from "@/config"; 9 | 10 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAdmin"; 11 | import EgovAttachFile from "@/components/EgovAttachFile"; 12 | 13 | function EgovAdminNoticeDetail(props) { 14 | console.group("EgovAdminNoticeDetail"); 15 | console.log("------------------------------"); 16 | console.log("EgovAdminNoticeDetail [props] : ", props); 17 | 18 | const navigate = useNavigate(); 19 | const location = useLocation(); 20 | console.log("EgovAdminNoticeDetail [location] : ", location); 21 | 22 | const bbsId = location.state.bbsId || NOTICE_BBS_ID; 23 | const nttId = location.state.nttId; 24 | const searchCondition = location.state.searchCondition; 25 | 26 | const [masterBoard, setMasterBoard] = useState({}); 27 | const [boardDetail, setBoardDetail] = useState({}); 28 | const [boardAttachFiles, setBoardAttachFiles] = useState(); 29 | 30 | const retrieveDetail = () => { 31 | const retrieveDetailURL = `/board/${bbsId}/${nttId}`; 32 | const requestOptions = { 33 | method: "GET", 34 | headers: { 35 | "Content-type": "application/json", 36 | }, 37 | }; 38 | EgovNet.requestFetch(retrieveDetailURL, requestOptions, function (resp) { 39 | setMasterBoard(resp.result.brdMstrVO); 40 | setBoardDetail(resp.result.boardVO); 41 | setBoardAttachFiles(resp.result.resultFiles); 42 | }); 43 | }; 44 | 45 | const onClickDeleteBoardArticle = (bbsId, nttId) => { 46 | const deleteBoardURL = `/board/${bbsId}/${nttId}`; 47 | 48 | const requestOptions = { 49 | method: "PATCH", 50 | headers: { 51 | "Content-type": "application/json", 52 | }, 53 | }; 54 | 55 | EgovNet.requestFetch(deleteBoardURL, requestOptions, (resp) => { 56 | console.log("====>>> board delete= ", resp); 57 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 58 | alert("게시글이 삭제되었습니다."); 59 | navigate(URL.ADMIN_NOTICE, { replace: true }); 60 | } else { 61 | navigate( 62 | { pathname: URL.ERROR }, 63 | { state: { msg: resp.resultMessage } } 64 | ); 65 | } 66 | }); 67 | }; 68 | 69 | useEffect(function () { 70 | retrieveDetail(); 71 | // eslint-disable-next-line react-hooks/exhaustive-deps 72 | }, []); 73 | 74 | console.groupEnd("EgovAdminNoticeDetail"); 75 | 76 | return ( 77 |
    78 |
    79 | {/* */} 80 |
    81 |
      82 |
    • 83 | 84 | Home 85 | 86 |
    • 87 |
    • 88 | 사이트관리 89 |
    • 90 |
    • {masterBoard && masterBoard.bbsNm}
    • 91 |
    92 |
    93 | {/* */} 94 | 95 |
    96 | {/* */} 97 | 98 | {/* */} 99 | 100 |
    101 | {/* */} 102 | 103 |
    104 |

    사이트관리

    105 |
    106 | 107 |

    {masterBoard && masterBoard.bbsNm}

    108 | 109 | {/* */} 110 |
    111 |
    112 |
    {boardDetail && boardDetail.nttSj}
    113 |
    114 |
    115 |
    작성자
    116 |
    {boardDetail && boardDetail.frstRegisterNm}
    117 |
    118 |
    119 |
    작성일
    120 |
    {boardDetail && boardDetail.frstRegisterPnttm}
    121 |
    122 |
    123 |
    조회수
    124 |
    {boardDetail && boardDetail.inqireCo}
    125 |
    126 |
    127 |
    128 | 129 |
    130 | 137 |
    138 |
    139 | {/* 답글이 아니고 게시판 파일 첨부 가능 상태에서만 첨부파일 컴포넌트 노출 */} 140 | {boardDetail.parnts === "0" && 141 | masterBoard.fileAtchPosblAt === "Y" && ( 142 | 143 | )} 144 |
    145 | 146 |
    147 | {masterBoard.bbsUseFlag === "Y" && ( 148 |
    149 | 157 | 수정 158 | 159 | { 163 | e.preventDefault(); 164 | onClickDeleteBoardArticle( 165 | boardDetail.bbsId, 166 | boardDetail.nttId 167 | ); 168 | }} 169 | > 170 | 삭제 171 | 172 | {masterBoard.replyPosblAt === "Y" && ( 173 | 181 | 답글작성 182 | 183 | )} 184 |
    185 | )} 186 |
    187 | 196 | 목록 197 | 198 |
    199 |
    200 |
    201 | {/* */} 202 | 203 | {/* */} 204 |
    205 |
    206 |
    207 |
    208 | ); 209 | } 210 | 211 | export default EgovAdminNoticeDetail; 212 | -------------------------------------------------------------------------------- /src/pages/admin/schedule/EgovAdminScheduleDetail.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { Link, useLocation, useNavigate } from "react-router-dom"; 3 | 4 | import * as EgovNet from "@/api/egovFetch"; 5 | import URL from "@/constants/url"; 6 | import CODE from "@/constants/code"; 7 | 8 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavAdmin"; 9 | import EgovAttachFile from "@/components/EgovAttachFile"; 10 | 11 | function EgovAdminScheduleDetail(props) { 12 | console.group("EgovAdminScheduleDetail"); 13 | console.log("[Start] EgovAdminScheduleDetail ------------------------------"); 14 | console.log("EgovAdminScheduleDetail [props] : ", props); 15 | 16 | const navigate = useNavigate(); 17 | const location = useLocation(); 18 | console.log("EgovAdminScheduleDetail [location] : ", location); 19 | 20 | const [scheduleDetail, setScheduleDetail] = useState({}); 21 | const [boardAttachFiles, setBoardAttachFiles] = useState(); 22 | const [user, setUser] = useState({}); 23 | 24 | const retrieveDetail = () => { 25 | const retrieveDetailURL = `/schedule/${location.state?.schdulId}`; 26 | 27 | const requestOptions = { 28 | method: "GET", 29 | headers: { 30 | "Content-type": "application/json", 31 | }, 32 | }; 33 | EgovNet.requestFetch(retrieveDetailURL, requestOptions, function (resp) { 34 | let rawScheduleDetail = resp.result.scheduleDetail; 35 | rawScheduleDetail.startDateTime = convertDate( 36 | rawScheduleDetail.schdulBgnde 37 | ); 38 | rawScheduleDetail.endDateTime = convertDate( 39 | rawScheduleDetail.schdulEndde 40 | ); 41 | rawScheduleDetail.reptitSeCodeNm = getCodeName( 42 | resp.result.reptitSeCode, 43 | resp.result.scheduleDetail.reptitSeCode 44 | ); 45 | rawScheduleDetail.schdulIpcrCodeNm = getCodeName( 46 | resp.result.schdulIpcrCode, 47 | resp.result.scheduleDetail.schdulIpcrCode 48 | ); 49 | rawScheduleDetail.schdulSeNm = getCodeName( 50 | resp.result.schdulSe, 51 | resp.result.scheduleDetail.schdulSe 52 | ); 53 | setScheduleDetail(rawScheduleDetail); 54 | setUser(resp.result.user); 55 | setBoardAttachFiles(resp.result.resultFiles); 56 | }); 57 | }; 58 | const convertDate = (str) => { 59 | let year = str.substring(0, 4); 60 | let month = str.substring(4, 6); 61 | let date = str.substring(6, 8); 62 | let hour = str.substring(8, 10); 63 | let minute = str.substring(10, 12); 64 | return { 65 | year: year, 66 | month: month, 67 | date: date, 68 | hour: hour, 69 | minute: minute, 70 | dateForm: 71 | year + 72 | "년 " + 73 | month + 74 | "월 " + 75 | date + 76 | "일 " + 77 | hour + 78 | "시 " + 79 | minute + 80 | "분 ", 81 | }; 82 | }; 83 | 84 | const getCodeName = (codeArr, code) => { 85 | return codeArr.map((codeObj) => { 86 | if (codeObj.code === code?.trim()) return codeObj.codeNm; 87 | else return ""; 88 | }); 89 | }; 90 | 91 | const onClickDeleteSchedule = (schdulId) => { 92 | const deleteBoardURL = `/schedule/${schdulId}`; 93 | 94 | const requestOptions = { 95 | method: "DELETE", 96 | headers: { 97 | "Content-type": "application/json", 98 | }, 99 | }; 100 | 101 | EgovNet.requestFetch(deleteBoardURL, requestOptions, (resp) => { 102 | console.log("====>>> Schdule delete= ", resp); 103 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 104 | alert("게시글이 삭제되었습니다."); 105 | navigate(URL.ADMIN_SCHEDULE, { replace: true }); 106 | } else { 107 | // alert("ERR : " + resp.message); 108 | navigate( 109 | { pathname: URL.ERROR }, 110 | { state: { msg: resp.resultMessage } } 111 | ); 112 | } 113 | }); 114 | }; 115 | 116 | useEffect(function () { 117 | retrieveDetail(); 118 | // eslint-disable-next-line react-hooks/exhaustive-deps 119 | }, []); 120 | 121 | console.log("------------------------------EgovAdminScheduleDetail [End]"); 122 | console.groupEnd("EgovAdminScheduleDetail"); 123 | return ( 124 |
    125 |
    126 | {/* */} 127 |
    128 |
      129 |
    • 130 | 131 | Home 132 | 133 |
    • 134 |
    • 135 | 사이트관리 136 |
    • 137 |
    • 일정관리
    • 138 |
    139 |
    140 | {/* */} 141 | 142 |
    143 | {/* */} 144 | 145 | {/* */} 146 | 147 |
    148 | {/* */} 149 | 150 |
    151 |

    사이트관리

    152 |
    153 | 154 |

    일정관리 상세보기

    155 | 156 | {/* */} 157 |
    158 |
    159 |
    일정구분
    160 |
    {scheduleDetail.schdulSeNm}
    161 |
    162 |
    163 |
    중요도
    164 |
    {scheduleDetail.schdulIpcrCodeNm}
    165 |
    166 |
    167 |
    부서
    168 |
    {scheduleDetail.schdulDeptName}
    169 |
    170 |
    171 |
    일정명
    172 |
    {scheduleDetail.schdulNm}
    173 |
    174 |
    175 |
    일정내용
    176 |
    {scheduleDetail.schdulCn}
    177 |
    178 |
    179 |
    반복구분
    180 |
    {scheduleDetail.reptitSeCodeNm}
    181 |
    182 |
    183 |
    날짜/시간
    184 |
    185 | {" "} 186 | {scheduleDetail.startDateTime?.dateForm} ~{" "} 187 | {scheduleDetail.endDateTime?.dateForm} 188 |
    189 |
    190 |
    191 |
    담당자
    192 |
    {scheduleDetail.schdulChargerName}
    193 |
    194 | 195 | 196 | 197 | {/* */} 198 |
    199 | {user.id && ( 200 |
    201 | 208 | 수정 209 | 210 | 218 |
    219 | )} 220 |
    221 | 225 | 목록 226 | 227 |
    228 |
    229 | {/* */} 230 |
    231 | {/* */} 232 | 233 | {/* */} 234 |
    235 |
    236 |
    237 |
    238 | ); 239 | } 240 | 241 | export default EgovAdminScheduleDetail; 242 | -------------------------------------------------------------------------------- /src/pages/inform/daily/EgovDailyDetail.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { Link, useLocation } from "react-router-dom"; 3 | 4 | import * as EgovNet from "@/api/egovFetch"; 5 | import URL from "@/constants/url"; 6 | 7 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavInform"; 8 | import EgovAttachFile from "@/components/EgovAttachFile"; 9 | 10 | function EgovDailyDetail(props) { 11 | console.group("EgovDailyDetail"); 12 | console.log("[Start] EgovDailyDetail ------------------------------"); 13 | console.log("EgovDailyDetail [props] : ", props); 14 | 15 | const location = useLocation(); 16 | console.log("EgovDailyDetail [location] : ", location); 17 | 18 | const [scheduleDetail, setScheduleDetail] = useState({}); 19 | const [boardAttachFiles, setBoardAttachFiles] = useState(); 20 | 21 | const retrieveDetail = () => { 22 | const retrieveDetailURL = `/schedule/${location.state?.schdulId}`; 23 | const requestOptions = { 24 | method: "GET", 25 | headers: { 26 | "Content-type": "application/json", 27 | }, 28 | }; 29 | EgovNet.requestFetch(retrieveDetailURL, requestOptions, function (resp) { 30 | let rawScheduleDetail = resp.result.scheduleDetail; 31 | rawScheduleDetail.startDateTime = convertDate( 32 | rawScheduleDetail.schdulBgnde 33 | ); 34 | rawScheduleDetail.endDateTime = convertDate( 35 | rawScheduleDetail.schdulEndde 36 | ); 37 | rawScheduleDetail.reptitSeCodeNm = getCodeName( 38 | resp.result.reptitSeCode, 39 | resp.result.scheduleDetail.reptitSeCode 40 | ); 41 | rawScheduleDetail.schdulIpcrCodeNm = getCodeName( 42 | resp.result.schdulIpcrCode, 43 | resp.result.scheduleDetail.schdulIpcrCode 44 | ); 45 | rawScheduleDetail.schdulSeNm = getCodeName( 46 | resp.result.schdulSe, 47 | resp.result.scheduleDetail.schdulSe 48 | ); 49 | setScheduleDetail(rawScheduleDetail); 50 | setBoardAttachFiles(resp.result.resultFiles); 51 | }); 52 | }; 53 | const convertDate = (str) => { 54 | let year = str.substring(0, 4); 55 | let month = str.substring(4, 6); 56 | let date = str.substring(6, 8); 57 | let hour = str.substring(8, 10); 58 | let minute = str.substring(10, 12); 59 | return { 60 | year: year, 61 | month: month, 62 | date: date, 63 | hour: hour, 64 | minute: minute, 65 | dateForm: 66 | year + 67 | "년 " + 68 | month + 69 | "월 " + 70 | date + 71 | "일 " + 72 | hour + 73 | "시 " + 74 | minute + 75 | "분 ", 76 | }; 77 | }; 78 | 79 | const getCodeName = (codeArr, code) => { 80 | return codeArr.map((codeObj) => { 81 | if (codeObj.code === code?.trim()) return codeObj.codeNm; 82 | else return ""; 83 | }); 84 | }; 85 | 86 | useEffect(function () { 87 | retrieveDetail(); 88 | // eslint-disable-next-line react-hooks/exhaustive-deps 89 | }, []); 90 | 91 | console.log("------------------------------EgovDailyDetail [End]"); 92 | console.groupEnd("EgovDailyDetail"); 93 | return ( 94 |
    95 |
    96 | {/* */} 97 |
    98 |
      99 |
    • 100 | 101 | Home 102 | 103 |
    • 104 |
    • 105 | 알림마당 106 |
    • 107 |
    • 일정관리
    • 108 |
    109 |
    110 | {/* */} 111 | 112 |
    113 | {/* */} 114 | 115 | {/* */} 116 | 117 |
    118 | {/* */} 119 | 120 |
    121 |

    알림마당

    122 |
    123 | 124 |

    일정관리 상세보기

    125 | 126 | {/* */} 127 |
    128 |
    129 |
    일정구분
    130 |
    {scheduleDetail.schdulSeNm}
    131 |
    132 |
    133 |
    중요도
    134 |
    {scheduleDetail.schdulIpcrCodeNm}
    135 |
    136 |
    137 |
    부서
    138 |
    {scheduleDetail.schdulDeptName}
    139 |
    140 |
    141 |
    일정명
    142 |
    {scheduleDetail.schdulNm}
    143 |
    144 |
    145 |
    일정내용
    146 |
    {scheduleDetail.schdulCn}
    147 |
    148 |
    149 |
    반복구분
    150 |
    {scheduleDetail.reptitSeCodeNm}
    151 |
    152 |
    153 |
    날짜/시간
    154 |
    155 | {" "} 156 | {scheduleDetail.startDateTime?.dateForm} ~{" "} 157 | {scheduleDetail.endDateTime?.dateForm} 158 |
    159 |
    160 |
    161 |
    담당자
    162 |
    {scheduleDetail.schdulChargerName}
    163 |
    164 | 165 | 166 | {/* */} 167 |
    168 |
    169 | 173 | 목록 174 | 175 |
    176 |
    177 | {/* */} 178 |
    179 | {/* */} 180 | 181 | {/* */} 182 |
    183 |
    184 |
    185 |
    186 | ); 187 | } 188 | 189 | export default EgovDailyDetail; 190 | -------------------------------------------------------------------------------- /src/pages/inform/notice/EgovNoticeDetail.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | import { Link, useLocation, useNavigate } from "react-router-dom"; 4 | 5 | import * as EgovNet from "@/api/egovFetch"; 6 | import URL from "@/constants/url"; 7 | import CODE from "@/constants/code"; 8 | import { NOTICE_BBS_ID } from "@/config"; 9 | 10 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavInform"; 11 | import EgovAttachFile from "@/components/EgovAttachFile"; 12 | import { getSessionItem } from "@/utils/storage"; 13 | 14 | function EgovNoticeDetail(props) { 15 | console.group("EgovNoticeDetail"); 16 | console.log("------------------------------"); 17 | console.log("EgovNoticeDetail [props] : ", props); 18 | 19 | const navigate = useNavigate(); 20 | const location = useLocation(); 21 | console.log("EgovNoticeDetail [location] : ", location); 22 | //관리자 권한 체크때문에 추가(아래) 23 | const sessionUser = getSessionItem("loginUser"); 24 | const sessionUserSe = sessionUser?.userSe; 25 | 26 | const bbsId = location.state.bbsId || NOTICE_BBS_ID; 27 | const nttId = location.state.nttId; 28 | const searchCondition = location.state.searchCondition; 29 | 30 | const [masterBoard, setMasterBoard] = useState({}); 31 | const [user, setUser] = useState({}); 32 | const [boardDetail, setBoardDetail] = useState({}); 33 | const [boardAttachFiles, setBoardAttachFiles] = useState(); 34 | 35 | const retrieveDetail = () => { 36 | const retrieveDetailURL = `/board/${bbsId}/${nttId}`; 37 | const requestOptions = { 38 | method: "GET", 39 | headers: { 40 | "Content-type": "application/json", 41 | }, 42 | }; 43 | EgovNet.requestFetch(retrieveDetailURL, requestOptions, function (resp) { 44 | setMasterBoard(resp.result.brdMstrVO); 45 | setBoardDetail(resp.result.boardVO); 46 | setUser(resp.result.user); 47 | setBoardAttachFiles(resp.result.resultFiles); 48 | }); 49 | }; 50 | 51 | const onClickDeleteBoardArticle = (bbsId, nttId) => { 52 | const deleteBoardURL = `/board/${bbsId}/${nttId}`; 53 | 54 | const requestOptions = { 55 | method: "PATCH", 56 | headers: { 57 | "Content-type": "application/json", 58 | }, 59 | }; 60 | 61 | EgovNet.requestFetch(deleteBoardURL, requestOptions, (resp) => { 62 | console.log("====>>> board delete= ", resp); 63 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 64 | alert("게시글이 삭제되었습니다."); 65 | navigate(URL.INFORM_NOTICE, { replace: true }); 66 | } else { 67 | navigate( 68 | { pathname: URL.ERROR }, 69 | { state: { msg: resp.resultMessage } } 70 | ); 71 | } 72 | }); 73 | }; 74 | 75 | useEffect(function () { 76 | retrieveDetail(); 77 | // eslint-disable-next-line react-hooks/exhaustive-deps 78 | }, []); 79 | 80 | console.groupEnd("EgovNoticeDetail"); 81 | 82 | return ( 83 |
    84 |
    85 | {/* */} 86 |
    87 |
      88 |
    • 89 | 90 | Home 91 | 92 |
    • 93 |
    • 94 | 알림마당 95 |
    • 96 |
    • {masterBoard && masterBoard.bbsNm}
    • 97 |
    98 |
    99 | {/* */} 100 | 101 |
    102 | {/* */} 103 | 104 | {/* */} 105 | 106 |
    107 | {/* */} 108 | 109 |
    110 |

    알림마당

    111 |
    112 | 113 |

    {masterBoard && masterBoard.bbsNm}

    114 | 115 | {/* */} 116 |
    117 |
    118 |
    {boardDetail && boardDetail.nttSj}
    119 |
    120 |
    121 |
    작성자
    122 |
    {boardDetail && boardDetail.frstRegisterNm}
    123 |
    124 |
    125 |
    작성일
    126 |
    {boardDetail && boardDetail.frstRegisterPnttm}
    127 |
    128 |
    129 |
    조회수
    130 |
    {boardDetail && boardDetail.inqireCo}
    131 |
    132 |
    133 |
    134 | 135 |
    136 | 143 |
    144 |
    145 | {/* 답글이 아니고 게시판 파일 첨부 가능 상태에서만 첨부파일 컴포넌트 노출 */} 146 | {boardDetail.parnts === "0" && 147 | masterBoard.fileAtchPosblAt === "Y" && ( 148 | 149 | )} 150 |
    151 | 152 |
    153 | {user && 154 | sessionUserSe === "ADM" && 155 | masterBoard.bbsUseFlag === "Y" && ( 156 |
    157 | 165 | 수정 166 | 167 | 179 | {masterBoard.replyPosblAt === "Y" && ( 180 | 188 | 답글작성 189 | 190 | )} 191 |
    192 | )} 193 | 194 |
    195 | 204 | 목록 205 | 206 |
    207 |
    208 |
    209 | {/* */} 210 | 211 | {/* */} 212 |
    213 |
    214 |
    215 |
    216 | ); 217 | } 218 | 219 | export default EgovNoticeDetail; 220 | -------------------------------------------------------------------------------- /src/pages/intro/EgovIntroService.jsx: -------------------------------------------------------------------------------- 1 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavIntro"; 2 | 3 | function EgovIntroService() { 4 | return ( 5 |
    6 |
    7 | {/* */} 8 |
    9 | 20 |
    21 | {/* */} 22 | 23 |
    24 | {/* */} 25 | 26 | {/* */} 27 | 28 |
    29 | {/* */} 30 | 31 |

    정보마당

    32 | 33 |

    34 | 대표제품의 소개와 대표서비스의 소개를 보실 수 있는 페이지입니다. 35 |

    36 | 37 |

    대표서비스 소개

    38 | 39 |

    40 | 전자정부 표준 프레임워크 실행환경은 5개 서비스 그룹으로 구성되며 41 | 34개 서비스를 제공한다. 42 |
    43 | 실행환경 서비스 구조는 아래 그림과 같다. 44 |

    45 | 46 |

    화면처리

    47 | 48 |
    49 |

    50 | 화면처리 서비스그룹은 업무처리 서비스와 사용자간의 인터페이스를 51 | 담당하는 서비스로 사용자 화면 구성 및
    52 | 사용자 입력 정보 검증 등의 기능을 지원한다. 53 |

    54 |
      55 |
    • 56 | Ajax Support: Ajax는 대화식 웹 애플리케이션의 제작을 위해 57 | HTML과 CSS, DOM, 자바 스크립트, XML, XSLT 등과 같은 조합을 58 | 이용하는 웹 개발 기법으로 Ajax 기능 지원을 위한 Custom Tag 59 | Library를 제공한다. 60 |
    • 61 |
    • 62 | Internationalization: Internationalization은 다양한 지역과 63 | 언어 환경을 지원할 수 있는 서비스로, 서버 설정 및 클라이언트 64 | 브라우저 환경에 따라 자동화된 다국어 기능을 제공한다. 65 |
    • 66 |
    • 67 | MVC : MVC 디자인 패턴을 적용하여 사용자 화면을 개발할 수 68 | 있도록 MVC 기반 구조를 제공한다. 69 |
    • 70 |
    • 71 | Security : 웹 응용프로그램 작성 시 발생될 수 있는 웹 보안상의 72 | 취약점(XSS, SQL Injection 등)에 대응하기 위한 기능을 제공한다. 73 |
    • 74 |
    • 75 | UI Adaptor : 화면 레이어의 구현 방식에 따라 업무로직 레이어가 76 | 변경되는 것을 막기 위해서, 업무처리 Layer에서 사용할 데이터 77 | 타입을 정의하고, 화면 레이어에서 사용하는 in/out parameter를 78 | 해당 구현 방식에 맞게 변환해주는 기능 제공한다. 79 |
    • 80 |
    81 |
    82 | 83 |

    업무처리

    84 | 85 |
    86 |

    87 | 업무처리 서비스는 업무 프로그램의 업무 로직을 담당하는 서비스로 88 | 업무 흐름제어, 트랜잭션 관리, 에러 처리 등의 89 |
    90 | 기능을 제공한다. 91 |

    92 |
      93 |
    • 94 | Process Control : 비지니스 로직과 업무 흐름의 분리를 지원하며, 95 | XML 등의 외부 설정으로 업무흐름 구성을 제공하고, 미리 정의된 96 | 프로세스를 실행하는 기능을 제공한다. 97 |
    • 98 |
    • 99 | Exception Handling : 응용 프로그래밍의 수행 과정에서 발생하는 100 | 예외사항(Exception)을 처리하기 위해 표준화된 방법을 제공한다. 101 |
    • 102 |
    103 |
    104 | 105 | {/* */} 106 |
    107 |
    108 |
    109 |
    110 | ); 111 | } 112 | 113 | export default EgovIntroService; 114 | -------------------------------------------------------------------------------- /src/pages/intro/EgovIntroWork.jsx: -------------------------------------------------------------------------------- 1 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavIntro"; 2 | 3 | import businessIntroImg from "/assets/images/img_business_intro.png"; 4 | import businessIntroImgMobile from "/assets/images/img_business_intro_m.png"; 5 | 6 | function EgovIntroWork() { 7 | return ( 8 |
    9 |
    10 | {/* */} 11 |
    12 | 23 |
    24 | {/* */} 25 | 26 |
    27 | {/* */} 28 | 29 | {/* */} 30 | 31 |
    32 | {/* */} 33 | 34 |

    정보마당

    35 | 36 |

    37 | 대표제품의 소개와 대표서비스의 소개를 보실 수 있는 페이지입니다. 38 |

    39 | 40 |

    주요사업 소개

    41 | 42 |

    개요

    43 | 44 |

    45 | 전자정부 표준프레임워크는 실행환경, 개발환경, 관리환경, 운영환경 46 | 등 4개의 표준프레임워크 환경과 공통 47 |
    48 | 컴포넌트로 구성된다. 전자정부 및 공공사업에서 웹 어플리케이션 49 | 시스템 구축 시 어플리케이션 아키텍처와 기본
    50 | 기능 및 공통컴포넌트를 표준으로 제공하는 개발프레임워크로서 다음과 51 | 같이 실행, 개발, 운영, 관리환경과 공통 52 |
    53 | 컴포넌트로 구성됨 54 |

    55 | 56 |

    실행 환경

    57 | 58 |

    59 | 전자정부 사업에서 개발하는 업무 프로그램의 실행에 필요한 공통모듈 60 | 등 업무 프로그램 개발 시 화면,서버 프로 61 |
    62 | 그램, 데이터 개발을 표준화가 용이하도록 지원하는 응용프로그램 환경 63 |

    64 | 65 |

    66 | 67 | 68 |

    69 | 70 | {/* */} 71 |
    72 |
    73 |
    74 |
    75 | ); 76 | } 77 | 78 | export default EgovIntroWork; 79 | -------------------------------------------------------------------------------- /src/pages/login/EgovLogin.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import EgovLoginContent from "@/pages/login/EgovLoginContent"; 4 | 5 | import URL from "@/constants/url"; 6 | 7 | function EgovLogin(props) { 8 | console.group("EgovLogin"); 9 | console.log("[Start] EgovLogin ------------------------------"); 10 | console.log("EgovLogin [props] : ", props); 11 | 12 | const onChangeLogin = (user) => { 13 | props.onChangeLogin(user); 14 | }; 15 | 16 | console.log("------------------------------EgovLogin [End]"); 17 | console.groupEnd("EgovLogin"); 18 | 19 | return ( 20 |
    21 |
    22 | {/* */} 23 |
    24 |
      25 |
    • 26 | 27 | Home 28 | 29 |
    • 30 |
    • 로그인
    • 31 |
    32 |
    33 | {/* */} 34 | 35 |
    36 | 37 |
    38 |
    39 |
    40 | ); 41 | } 42 | 43 | export default EgovLogin; 44 | -------------------------------------------------------------------------------- /src/pages/login/EgovLoginContent.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useRef } from "react"; 2 | import { useLocation, useNavigate } from "react-router-dom"; 3 | import * as EgovNet from "@/api/egovFetch"; 4 | 5 | import URL from "@/constants/url"; 6 | import CODE from "@/constants/code"; 7 | import { getLocalItem, setLocalItem, setSessionItem } from "@/utils/storage"; 8 | import SnsNaverBt from "@/components/sns/SnsNaverBt"; 9 | import SnsKakaoBt from "@/components/sns/SnsKakaoBt"; 10 | 11 | function EgovLoginContent(props) { 12 | console.group("EgovLoginContent"); 13 | console.log("[Start] EgovLoginContent ------------------------------"); 14 | console.log("EgovLoginContent [props] : ", props); 15 | 16 | const navigate = useNavigate(); 17 | const location = useLocation(); 18 | console.log("EgovLoginContent [location] : ", location); 19 | 20 | const [userInfo, setUserInfo] = useState({ 21 | id: "", 22 | password: "default", 23 | userSe: "USR", 24 | }); 25 | // eslint-disable-next-line no-unused-vars 26 | const [loginVO, setLoginVO] = useState({}); 27 | 28 | const [saveIDFlag, setSaveIDFlag] = useState(false); 29 | 30 | const checkRef = useRef(); 31 | const idRef = useRef(null); //id입력 부분에서 엔터키 이벤트 발생 확인 32 | const passwordRef = useRef(null); //비밀번호 입력 부분 33 | 34 | const KEY_ID = "KEY_ID"; 35 | const KEY_SAVE_ID_FLAG = "KEY_SAVE_ID_FLAG"; 36 | 37 | const handleSaveIDFlag = () => { 38 | setLocalItem(KEY_SAVE_ID_FLAG, !saveIDFlag); 39 | setSaveIDFlag(!saveIDFlag); 40 | }; 41 | 42 | useEffect(() => { 43 | let idFlag = getLocalItem(KEY_SAVE_ID_FLAG); 44 | if (idFlag === null) { 45 | setSaveIDFlag(false); 46 | // eslint-disable-next-line react-hooks/exhaustive-deps 47 | idFlag = false; 48 | } else { 49 | setSaveIDFlag(idFlag); 50 | } 51 | if (idFlag === false) { 52 | setLocalItem(KEY_ID, ""); 53 | checkRef.current.className = "f_chk"; 54 | } else { 55 | checkRef.current.className = "f_chk on"; 56 | } 57 | }, []); 58 | 59 | useEffect(() => { 60 | let data = getLocalItem(KEY_ID); 61 | if (data !== null) { 62 | setUserInfo({ id: data, password: "default", userSe: "USR" }); 63 | } 64 | }, []); 65 | 66 | const activeEnter = (e) => { 67 | if (e.key === "Enter") { 68 | e.preventDefault(); 69 | if (e.target === idRef.current && passwordRef.current.value === "") { 70 | //엔터 키 이벤트 발생한 입력 필드가 아이디인지 확인하기 71 | alert("비밀번호 입력 여부를 확인하여 주세요"); 72 | passwordRef.current.focus(); 73 | } else { 74 | submitFormHandler(e); 75 | } 76 | } 77 | }; 78 | const submitFormHandler = () => { 79 | console.log("EgovLoginContent submitFormHandler()"); 80 | 81 | const loginUrl = "/auth/login-jwt"; 82 | 83 | const requestOptions = { 84 | method: "POST", 85 | headers: { 86 | "Content-type": "application/json", 87 | }, 88 | body: JSON.stringify(userInfo), 89 | }; 90 | 91 | EgovNet.requestFetch(loginUrl, requestOptions, (resp) => { 92 | let resultVO = resp.resultVO; 93 | let jToken = resp?.jToken || null; 94 | 95 | setSessionItem("jToken", jToken); 96 | 97 | if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { 98 | //setLoginVO(resultVO); 99 | setSessionItem("loginUser", resultVO); 100 | props.onChangeLogin(resultVO); 101 | if (saveIDFlag) setLocalItem(KEY_ID, resultVO?.id); 102 | navigate(URL.MAIN); 103 | // PC와 Mobile 열린메뉴 닫기 104 | document.querySelector(".all_menu.WEB").classList.add("closed"); 105 | document.querySelector(".btnAllMenu").classList.remove("active"); 106 | document.querySelector(".btnAllMenu").title = "전체메뉴 닫힘"; 107 | document.querySelector(".all_menu.Mobile").classList.add("closed"); 108 | } else { 109 | alert(resp.resultMessage); 110 | } 111 | }); 112 | }; 113 | 114 | console.log("------------------------------EgovLoginContent [End]"); 115 | console.groupEnd("EgovLoginContent"); 116 | 117 | return ( 118 |
    119 | {/* */} 120 |
    121 |

    로그인

    122 |

    123 | 전자정부표준프레임워크 경량환경 홈페이지 로그인 페이지입니다. 124 |
    125 | 로그인을 하시면 모든 서비스를 제한없이 이용하실 수 있습니다. 126 |

    127 | 128 |
    129 |
    130 |
    131 | 로그인 132 | 133 | 140 | setUserInfo({ ...userInfo, id: e.target.value }) 141 | } 142 | ref={idRef} 143 | onKeyDown={activeEnter} 144 | /> 145 | 151 | setUserInfo({ ...userInfo, password: e.target.value }) 152 | } 153 | ref={passwordRef} 154 | onKeyDown={activeEnter} 155 | /> 156 | 157 |
    158 | 168 |
    169 | 172 |
    173 |
    174 |
    175 | 176 |
      177 |
    • 178 | 비밀번호는 6~12자의 영문 대/소문자, 숫자, 특수문자를 혼합해서 179 | 사용하실 수 있습니다. 180 |
    • 181 |
    • 182 | 쉬운 비밀번호나 자주 쓰는 사이트의 비밀번호가 같을 경우, 도용되기 183 | 쉬우므로 주기적으로 변경하셔서 사용하는 것이 좋습니다. 184 |
    • 185 |
    186 |
    187 | 188 | 189 |
    190 |
    191 | {/* */} 192 |
    193 | ); 194 | } 195 | 196 | export default EgovLoginContent; 197 | -------------------------------------------------------------------------------- /src/pages/main/EgovMain.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { Link, useLocation } from "react-router-dom"; 3 | 4 | import * as EgovNet from "@/api/egovFetch"; 5 | import URL from "@/constants/url"; 6 | 7 | import simpleMainIng from "/assets/images/img_simple_main.png"; 8 | import initPage from "@/js/ui"; 9 | 10 | function EgovMain(props) { 11 | console.group("EgovMain"); 12 | console.log("[Start] EgovMain ------------------------------"); 13 | console.log("EgovMain [props] : ", props); 14 | 15 | const location = useLocation(); 16 | console.log("EgovMain [location] : ", location); 17 | 18 | // eslint-disable-next-line no-unused-vars 19 | const [noticeBoard, setNoticeBoard] = useState(); 20 | // eslint-disable-next-line no-unused-vars 21 | const [gallaryBoard, setGallaryBoard] = useState(); 22 | const [noticeListTag, setNoticeListTag] = useState(); 23 | const [gallaryListTag, setGallaryListTag] = useState(); 24 | 25 | useEffect(() => { 26 | initPage(); 27 | }); 28 | 29 | const retrieveList = useCallback(() => { 30 | console.groupCollapsed("EgovMain.retrieveList()"); 31 | 32 | const retrieveListURL = "/mainPage"; 33 | const requestOptions = { 34 | method: "GET", 35 | headers: { 36 | "Content-type": "application/json", 37 | }, 38 | }; 39 | 40 | EgovNet.requestFetch( 41 | retrieveListURL, 42 | requestOptions, 43 | (resp) => { 44 | setNoticeBoard(resp.result.notiList); 45 | setGallaryBoard(resp.result.galList); 46 | 47 | let mutNotiListTag = []; 48 | mutNotiListTag.push(
  • 검색된 결과가 없습니다.
  • ); // 게시판 목록 초기값 49 | 50 | // 리스트 항목 구성 51 | resp.result.notiList.forEach(function (item, index) { 52 | if (index === 0) mutNotiListTag = []; // 목록 초기화 53 | mutNotiListTag.push( 54 |
  • 55 | 62 | {item.nttSj} 63 | {item.frstRegisterPnttm} 64 | 65 |
  • 66 | ); 67 | }); 68 | setNoticeListTag(mutNotiListTag); 69 | 70 | let mutGallaryListTag = []; 71 | mutGallaryListTag.push(
  • 검색된 결과가 없습니다.
  • ); // 게시판 목록 초기값 72 | 73 | // 리스트 항목 구성 74 | resp.result.galList.forEach(function (item, index) { 75 | if (index === 0) mutGallaryListTag = []; // 목록 초기화 76 | mutGallaryListTag.push( 77 |
  • 78 | 85 | {item.nttSj} 86 | {item.frstRegisterPnttm} 87 | 88 |
  • 89 | ); 90 | }); 91 | setGallaryListTag(mutGallaryListTag); 92 | }, 93 | function (resp) { 94 | console.log("err response : ", resp); 95 | } 96 | ); 97 | console.groupEnd("EgovMain.retrieveList()"); 98 | }, []); 99 | 100 | useEffect(() => { 101 | retrieveList(); 102 | }, [retrieveList]); 103 | 104 | console.log("------------------------------EgovMain [End]"); 105 | console.groupEnd("EgovMain"); 106 | 107 | return ( 108 |
    109 |
    110 |
    111 |
    112 | 단순 홈페이지 전자정부 표준프레임워크의 경량환경 내부업무에 대한 최신 정보와 기술을 제공하고 있습니다. 116 |
    117 | 118 |
    119 |
    120 | 130 |
    131 |
    132 |

    공지사항

    133 |
      {noticeListTag}
    134 | 135 | 더보기 136 | 137 |
    138 | 139 |
    140 |

    갤러리

    141 |
      {gallaryListTag}
    142 | 143 | 더보기 144 | 145 |
    146 |
    147 |
    148 | 149 |
    150 | 151 | 자료실 152 | 153 | 다양한 자료를 154 |
    155 | 다운로드 받으실 수 있습니다. 156 |
    157 | 158 | 159 | 표준프레임워크센터 160 | 161 | 표준프레임워크센터의 162 |
    163 | 약도 등의 정보를 제공합니다. 164 |
    165 | 166 |
    167 |
    168 |
    169 | 170 |
    171 |
    172 |
    173 |

    주요사업 소개

    174 |

    175 | 표준프레임워크가 제공하는 176 |
    177 | 주요 사업을 소개합니다. 178 |

    179 |
    180 | 자세히 보기 181 |
    182 |
    183 |
    184 |

    대표서비스 소개

    185 |

    186 | 표준프레임워크 실행환경의 187 |
    188 | 서비스 그룹에서 제공하는 189 |
    190 | 대표서비스입니다. 191 |

    192 |
    193 | 자세히 보기 194 |
    195 |
    196 |
    197 |

    서비스 신청

    198 |

    199 | 표준프레임워크 경량환경 200 |
    201 | 홈페이지의 다양한 서비스를 202 |
    203 | 신청 하실 수 있습니다. 204 |

    205 |
    206 | 자세히 보기 207 |
    208 |
    209 |
    210 |

    일정 현황

    211 |

    212 | 표준프레임워크 경량환경 213 |
    214 | 홈페이지의 전체적인 일정 215 |
    216 | 현황을 조회하실 수 있습니다. 217 |

    218 |
    219 | 자세히 보기 220 |
    221 |
    222 |
    223 |
    224 | ); 225 | } 226 | 227 | export default EgovMain; 228 | -------------------------------------------------------------------------------- /src/pages/support/apply/EgovSupportApply.jsx: -------------------------------------------------------------------------------- 1 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavSupport"; 2 | 3 | function EgovSupportApply() { 4 | return ( 5 |
    6 |
    7 | {/* */} 8 |
    9 | 20 |
    21 | {/* */} 22 | 23 |
    24 | {/* */} 25 | 26 | {/* */} 27 | 28 |
    29 | {/* */} 30 | 31 |

    고객지원

    32 | 33 |

    34 | 프레임워크 경량환경의 원하시는 서비스를 신청하실 수 있습니다. 35 |

    36 | 37 |

    서비스 신청

    38 | 39 |

    주요 서비스 안내

    40 | 41 |

    42 | 서비스필요시 다음과 같은 절차로 신청하시면 됩니다. 43 |
    44 |
    45 | 1. 필요한 서비스 확인 46 |
    47 |
    48 | 2. 자료실에서 필요한 서비스 존재여부 확인 49 |
    50 |
    51 | 3. 서비스요청을 통해 필요한 서비스 신청 52 |
    53 |
    54 | 대표 서비스 자세히 보기 55 |

    56 | 57 | {/* */} 58 |
    59 |
    60 |
    61 |
    62 | ); 63 | } 64 | 65 | export default EgovSupportApply; 66 | -------------------------------------------------------------------------------- /src/pages/support/download/EgovDownloadCreate.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavSupport"; 4 | import URL from "@/constants/url"; 5 | 6 | import samplePdsListImg from "/assets/images/sample_pds_list.png"; 7 | 8 | function EgovDownloadCreate() { 9 | return ( 10 |
    11 |
    12 | {/* */} 13 |
    14 |
      15 |
    • 16 | 17 | Home 18 | 19 |
    • 20 |
    • 21 | 고객지원 22 |
    • 23 |
    • 소개
    • 24 |
    25 |
    26 | {/* */} 27 | 28 |
    29 | {/* */} 30 | 31 | {/* */} 32 | 33 |
    34 | {/* */} 35 | 36 |
    37 |

    고객지원

    38 |
    39 | 40 |

    자료실

    41 |

    본 화면은 디자인 예시임

    42 | 43 | {/* */} 44 |
    45 |
    46 |
    47 |
    48 | 49 |
    50 |
    51 | 57 |
    58 |
    59 |
    60 | 61 |
    62 |
    63 |
    작성자
    64 |
    innovate
    65 |
    66 |
    67 |
    작성일
    68 |
    2011-08-01 23:22:11
    69 |
    70 |
    71 | 72 |
    73 |
    74 | 75 |

    76 | 썸네일 이미지는 77 |
    78 | width : 160px, height : 109px 79 |
    80 | 크기의 이미지를 올려주세요 81 |

    82 |
    83 |
    84 |
    85 |
    86 | 87 |
    88 |
    89 | 95 |
    96 |
    97 |
    98 |
    99 | 100 |
    101 |
    102 | 108 |
    109 |
    110 |
    111 |
    112 | 113 |
    114 |
    115 | 116 |
    117 |
    118 |
    119 |
    120 | 121 |
    122 |
    123 | 129 |
    130 |
    131 |
    132 |
    133 | 134 |
    135 |
    136 | 142 |
    143 |
    144 |
    145 |
    146 |
    147 | {/* */} 148 | 149 |

    150 | 151 |

    152 | 153 |
    154 | 161 |
    162 | 163 | {/* */} 164 |
    165 |
    166 | 167 |
    168 | 172 | 등록 173 | 174 |
    175 |
    176 | {/* */} 177 | 178 | {/* */} 179 |
    180 |
    181 |
    182 |
    183 | ); 184 | } 185 | 186 | export default EgovDownloadCreate; 187 | -------------------------------------------------------------------------------- /src/pages/support/download/EgovDownloadDetail.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavSupport"; 4 | import URL from "@/constants/url"; 5 | 6 | import samplePdsList from "/assets/images/sample_pds_list.png"; 7 | 8 | function EgovDownloadDetail() { 9 | return ( 10 |
    11 |
    12 | {/* */} 13 |
    14 |
      15 |
    • 16 | 17 | Home 18 | 19 |
    • 20 |
    • 21 | 고객지원 22 |
    • 23 |
    • 소개
    • 24 |
    25 |
    26 | {/* */} 27 | 28 |
    29 | {/* */} 30 | 31 | {/* */} 32 | 33 |
    34 | {/* */} 35 | 36 |
    37 |

    고객지원

    38 |
    39 | 40 |

    자료실

    41 |

    본 화면은 디자인 예시임

    42 | 43 | {/* */} 44 |
    45 |

    egovframe installer v1.03

    46 | 47 |
    48 |
    49 |
    작성자
    50 |
    innovate
    51 |
    52 |
    53 |
    작성일
    54 |
    2011-08-01 23:22:11
    55 |
    56 |
    57 | 58 |
    59 | 65 |
    66 |
    67 |
    운영체제
    68 |
    69 | Win95/Win98/WinME/WinNT/Win2000/WinXP/WinVISTA/Win7/ 70 |
    71 |
    72 |
    73 |
    권장사양
    74 |
    펜티엄3
    75 |
    76 |
    77 |
    파일정보
    78 |
    79 | 7MB (총 1 개)/ egovframework-common-all.zip [15,083,713 80 | byte] 81 |
    82 |
    83 |
    84 |
    등록일자
    85 |
    2011-08-08 11:11:11
    86 |
    87 |
    88 |
    언어
    89 |
    영어
    90 |
    91 |
    92 |
    93 |
    94 | {/* */} 95 | 96 |

    자료 상세설명

    97 | 98 |

    99 | 안녕하세요.. 공통컴포넌트 전체 소스입니다. 관련된 내용은 다음 100 | 가이드를 참조하십시오. 101 | http://www.egovframe.go.kr/wiki/doku.php?id= 102 | egovframework:com:v3:init_guide 감사합니다. 103 |

    104 | 105 | {/* */} 106 |
    107 |
    108 | 109 |
    110 | 114 | 목록 115 | 116 |
    117 |
    118 | {/* */} 119 | 120 |
    121 |
    122 |
    이전글
    123 |
    124 | egovframe installer v1.03 125 |
    126 |
    127 |
    128 |
    다음글
    129 |
    130 | egovframe installer v1.03 131 |
    132 |
    133 |
    134 | 135 | {/* */} 136 |
    137 |
    138 |
    139 |
    140 | ); 141 | } 142 | 143 | export default EgovDownloadDetail; 144 | -------------------------------------------------------------------------------- /src/pages/support/qna/EgovQnaDetail.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavSupport"; 4 | 5 | function EgovQnaDetail() { 6 | return ( 7 |
    8 |
    9 | {/* */} 10 |
    11 |
      12 |
    • 13 | 14 | Home 15 | 16 |
    • 17 |
    • 18 | 고객지원 19 |
    • 20 |
    • 소개
    • 21 |
    22 |
    23 | {/* */} 24 | 25 |
    26 | {/* */} 27 | 28 | {/* */} 29 | 30 |
    31 | {/* */} 32 | 33 |
    34 |

    고객지원

    35 |
    36 | 37 |

    Q&A 상세조회

    38 |

    본 화면은 디자인 예시임

    39 | 40 |
    41 |
    42 |
    제목
    43 |
    jsp파일을 못찼습니다.
    44 |
    45 |
    46 |
    이메일
    47 |
    abc@nate.com
    48 |
    49 |
    50 |
    이메일답변여부
    51 |
    답변요청
    52 |
    53 |
    54 |
    등록일자
    55 |
    2011-08-08 11:11:11
    56 |
    57 |
    58 |
    작성자
    59 |
    박성환
    60 |
    61 |
    62 |
    전화
    63 |
    000-000-0000
    64 |
    65 |
    66 |
    작성일
    67 |
    2011-08-08
    68 |
    69 |
    70 |
    조회
    71 |
    100
    72 |
    73 |
    74 |
    처리상태
    75 |
    접수대기
    76 |
    77 |
    78 |
    첨부파일
    79 |
    80 | 81 | file_name.hwp [3626] byte 82 | 83 |
    84 |
    85 |
    86 |
    87 | Q 88 | 안녕하세요 웹호스팅에 올렸더니 jsp파일에서 이런에러로그가 89 | 남았는데요 jsp파일을 못찾는것같습니다? xml을 수정해야하나요? 90 |
    91 | 심각: Servlet.service() for servlet action threw exception 92 |
    93 | javax.servlet.ServletException: Could not get RequestDispatcher 94 | for [/WEB-INF/jsp/egovframework//main/main.jsp]: check that this 95 | file exists within your WAR 96 |
    97 | at 98 | org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:217) 99 |
    100 |
    101 | A 102 |
      103 |
    • 104 | chanjin님의 답변 2011-08-08 12:33:33 105 | 심각: Servlet.service() for servlet action threw exception은 106 | jsp파일을 열어서 보셔야합니다. javax.servlet.ServletException: 107 | Could not get RequestDispatcher for 108 | [/WEB-INF/jsp/egovframework//main/main.jsp]: check that this 109 | file exists within your WAR 110 | 111 | Delete 112 | 113 |
    • 114 |
    • 115 | sunrise님의 답변 2011-08-07 11:11:11 116 | tomcat서버를 재시동해보세요. 전 그렇게 하니깐 되던데요. 117 | 118 | Delete 119 | 120 |
    • 121 |
    • 122 | auto님의 답변 2011-08-07 11:11:11 123 | 제가 살펴볼께요 메일로 주세요. test@naver.com 124 | 125 | Delete 126 | 127 |
    • 128 |
    129 |
    130 | 131 | {/* */} 132 |
    133 |
    134 | 135 |
    136 | 143 |
    144 |
    145 | 150 |
    151 | {/* */} 152 | 153 | {/* */} 154 |
    155 |
    156 |
    157 |
    158 | ); 159 | } 160 | 161 | export default EgovQnaDetail; 162 | -------------------------------------------------------------------------------- /src/pages/support/qna/EgovQnaList.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | import { default as EgovLeftNav } from "@/components/leftmenu/EgovLeftNavSupport"; 4 | import URL from "@/constants/url"; 5 | 6 | function EgovQnaList() { 7 | return ( 8 |
    9 |
    10 | {/* */} 11 |
    12 |
      13 |
    • 14 | 15 | Home 16 | 17 |
    • 18 |
    • 19 | 고객지원 20 |
    • 21 |
    • 소개
    • 22 |
    23 |
    24 | {/* */} 25 | 26 |
    27 | {/* */} 28 | 29 | {/* */} 30 | 31 |
    32 | {/* */} 33 | 34 |
    35 |

    고객지원

    36 |
    37 | 38 |

    묻고답하기(Q&A)

    39 |

    본 화면은 디자인 예시임

    40 | 41 | {/* */} 42 |
    43 |
      44 |
    • 45 | 57 |
    • 58 |
    • 59 | {/* */} 60 | 61 | 62 | 63 | 64 |
    • 65 |
    66 |
    67 | {/* */} 68 | 69 | {/* */} 70 |
    71 |
    72 | 번호 73 | 제목 74 | 작성자 75 | 조회수 76 | 등록일 77 |
    78 |
    79 | {/* */} 80 | {/*

    검색된 결과가 없습니다.

    */} 81 | 82 | {/* */} 83 | 84 |
    3
    85 |
    86 | 공통컴포넌트 중 모니터링 관련 서비스 실행시 오류가 87 | 발생합니다(15) 88 |
    89 |
    홍길동
    90 |
    3
    91 |
    2021-7-24
    92 | 93 | 94 |
    2
    95 |
    96 | validation 처리 시.패스워드에 대한 메소드를 찾지 못합니다. 97 |
    98 |
    홍길동
    99 |
    3
    100 |
    2021-7-24
    101 | 102 | 103 |
    1
    104 |
    105 | 공통컴포넌트 중 모니터링 관련 서비스 실행시 오류가 106 | 발생합니다. 107 |
    108 |
    홍길동
    109 |
    3
    110 |
    2021-7-24
    111 | 112 |
    113 |
    114 | {/* */} 115 | 116 |
    117 | {/* */} 118 |
    119 |
      120 |
    • 121 | 124 |
    • 125 |
    • 126 | 129 |
    • 130 |
    • 131 | 134 |
    • 135 |
    • 136 | 137 |
    • 138 |
    • 139 | 140 |
    • 141 |
    • 142 | 143 |
    • 144 |
    • 145 | 146 |
    • 147 |
    • 148 | 151 |
    • 152 |
    • 153 | 156 |
    • 157 |
    158 |
    159 | {/* */} 160 |
    161 | 162 | {/* */} 163 |
    164 |
    165 |
    166 |
    167 | ); 168 | } 169 | 170 | export default EgovQnaList; 171 | -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /src/utils/bbsFormVaildator.js: -------------------------------------------------------------------------------- 1 | const bbsFormVaildator = (formData) => { 2 | if (formData.get('nttSj') === null || formData.get('nttSj') === "") { 3 | alert("제목은 필수 값입니다."); 4 | return false; 5 | } 6 | if (formData.get('nttCn') === null || formData.get('nttCn') === "") { 7 | alert("내용은 필수 값입니다."); 8 | return false; 9 | } 10 | return true; 11 | }; 12 | 13 | export default bbsFormVaildator; -------------------------------------------------------------------------------- /src/utils/bbsFormVaildator.jsx: -------------------------------------------------------------------------------- 1 | const bbsFormVaildator = (formData) => { 2 | if (formData.get("nttSj") === null || formData.get("nttSj") === "") { 3 | alert("제목은 필수 값입니다."); 4 | return false; 5 | } 6 | if (formData.get("nttCn") === null || formData.get("nttCn") === "") { 7 | alert("내용은 필수 값입니다."); 8 | return false; 9 | } 10 | return true; 11 | }; 12 | 13 | export default bbsFormVaildator; 14 | -------------------------------------------------------------------------------- /src/utils/calc.js: -------------------------------------------------------------------------------- 1 | export const itemIdxByPage = (resultCnt, currentPageNo, pageSize, index) => resultCnt + 1 - ((currentPageNo - 1) * pageSize + index + 1); -------------------------------------------------------------------------------- /src/utils/calc.jsx: -------------------------------------------------------------------------------- 1 | export const itemIdxByPage = (resultCnt, currentPageNo, pageSize, index) => resultCnt + 1 - ((currentPageNo - 1) * pageSize + index + 1); -------------------------------------------------------------------------------- /src/utils/storage.js: -------------------------------------------------------------------------------- 1 | function getItem(storage, key) { 2 | const jsonStr = storage.getItem(key); 3 | if (!jsonStr) return null; 4 | return JSON.parse(jsonStr); 5 | } 6 | 7 | function setItem(storage, key, value) { 8 | const str = (value === undefined) ? null : value; 9 | storage.setItem(key, JSON.stringify(str)); 10 | } 11 | 12 | function removeItem(storage, key) { 13 | storage.removeItem(key); 14 | } 15 | 16 | export function getLocalItem(key) { 17 | return getItem(localStorage, key); 18 | } 19 | 20 | export function setLocalItem(key, value) { 21 | setItem(localStorage, key, value); 22 | } 23 | 24 | export function removeLocalItem(key) { 25 | removeItem(localStorage, key); 26 | } 27 | 28 | export function getSessionItem(key) { 29 | return getItem(sessionStorage, key); 30 | } 31 | 32 | export function setSessionItem(key, value) { 33 | setItem(sessionStorage, key, value); 34 | } 35 | 36 | export function removeSessionItem(key) { 37 | removeItem(sessionStorage, key); 38 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eGovFramework/egovframe-template-simple-react/e6e9ef0391cea902b99141c20fafbc08d121425c/vite.config.js -------------------------------------------------------------------------------- /vitest.setup.js: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom"; // 테스트에서 커스텀 매처 사용 2 | import { vi } from 'vitest'; 3 | 4 | // Mock fetch API for tests 5 | global.fetch = vi.fn(() => 6 | Promise.resolve({ 7 | json: () => 8 | Promise.resolve({ 9 | resultCode: 0, 10 | result: { 11 | notiList: [], 12 | galList: [] 13 | } 14 | }) 15 | }) 16 | ); 17 | --------------------------------------------------------------------------------