diff --git a/README.md b/README.md
index 2659b05..15e3767 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,21 @@
-# PLM 솔루션 (ILSHIN)
+# RPS 업무관리 시스템
## 프로젝트 개요
-본 프로젝트는 제품 수명 주기 관리(PLM - Product Lifecycle Management) 솔루션입니다. 제품 개발 초기 단계부터 설계, 생산, 유통, 유지보수 및 폐기에 이르기까지 제품과 관련된 모든 데이터와 프로세스를 통합적으로 관리하는 것을 목표로 합니다.
+본 프로젝트는 RPS(Resource Planning System) 업무관리 시스템입니다. 기업의 자원 계획 및 업무 프로세스를 통합적으로 관리하여 효율적인 업무 처리와 자원 최적화를 목표로 합니다.
-## 주요 기능 (예상)
+## 주요 기능
-소스 코드 분석 및 일반적인 PLM 솔루션의 기능을 바탕으로 다음과 같은 메뉴/기능을 포함할 것으로 예상됩니다. 실제 메뉴는 애플리케이션 실행 후 확인해야 합니다.
+RPS 업무관리 시스템의 주요 기능은 다음과 같습니다:
-- **제품 정보 관리:** 제품 분류, 속성, 사양 등 관리
-- **BOM (Bill of Materials) 관리:** 부품 목록, 계층 구조 관리 (eBOM, mBOM 등)
-- **설계 변경 관리 (ECO/ECR):** 설계 변경 요청, 검토, 승인 프로세스 관리
-- **문서 관리:** CAD 데이터, 도면, 기술 문서 등의 버전 관리 및 접근 제어
-- **프로젝트/일정 관리:** 개발 프로젝트 일정, 리소스, 산출물 관리
-- **사용자 및 권한 관리:** 역할 기반 접근 제어
-- **워크플로우 관리:** 표준 프로세스 자동화 및 추적
-- **데이터 시각화/리포트:** 다양한 형식의 보고서 생성 (데이터 표시는 `jqGrid` 등을 활용할 것으로 보입니다.)
+- **자원 관리:** 인적 자원, 물적 자원, 시설 등의 통합 관리
+- **업무 프로세스 관리:** 업무 흐름 정의, 승인 프로세스, 워크플로우 관리
+- **프로젝트 관리:** 프로젝트 계획, 일정 관리, 진행 상황 추적
+- **문서 관리:** 업무 문서의 생성, 수정, 승인, 보관 및 검색
+- **보고서 및 분석:** 업무 현황 분석, KPI 관리, 대시보드 제공
+- **사용자 및 권한 관리:** 역할 기반 접근 제어 및 권한 관리
+- **알림 및 메시징:** 업무 관련 알림, 메시지 전송 기능
+- **데이터 시각화:** 차트, 그래프를 통한 데이터 시각화 (jqGrid, Tabulator 등 활용)
## 기술 스택
@@ -25,8 +25,8 @@
- MyBatis (v3.2.3) - 데이터베이스 연동
- **Frontend:**
- JSP (JavaServer Pages)
- - JavaScript (jQuery v1.11.3 / v2.1.4, jqGrid v4.7.1 확인)
- - CSS
+ - JavaScript (jQuery v1.11.3 / v2.1.4, jqGrid v4.7.1, Tabulator 확인)
+ - CSS (basic.css - 메인 스타일시트, 드롭다운 메뉴 및 반응형 디자인 포함)
- Apache Tiles (v3.0.5) - 페이지 레이아웃/템플릿
- **Database:**
- PostgreSQL (연결 정보 및 드라이버 확인)
@@ -44,6 +44,99 @@
- `pdfbox` (PDF 처리)
- 기타 다수 (`WebContent/WEB-INF/lib` 디렉토리 참조)
+## UI 구조 및 메뉴 시스템
+
+### 메뉴 구조
+- **상단 네비게이션:** 메인 메뉴가 상단 헤더에 위치
+- **드롭다운 메뉴:** 상단 메뉴 클릭 시 하위 메뉴가 드롭다운으로 표시
+- **전체 화면 활용:** 왼쪽 프레임을 제거하고 컨텐츠 영역을 전체 화면으로 확대
+- **반응형 디자인:** 다양한 화면 크기에 대응하는 반응형 레이아웃
+
+### 주요 파일
+- **header.jsp:** 상단 메뉴 및 네비게이션 구조 정의
+- **basic.css:** 메인 스타일시트, 드롭다운 메뉴 스타일 포함
+- **메뉴 관련 JavaScript:** jQuery 기반 메뉴 인터랙션 처리
+
+## Materialize CSS 드롭다운 시스템
+
+본 시스템은 [Materialize CSS](https://materializecss.com/dropdown.html) 프레임워크의 드롭다운 컴포넌트를 활용하여 현대적이고 사용자 친화적인 메뉴 시스템을 구현합니다.
+
+### Materialize CSS 드롭다운 특징
+
+#### 기본 구조
+```html
+
+Drop Me!
+
+
+
+```
+
+#### JavaScript 초기화
+```javascript
+// DOM 로드 완료 후 초기화
+document.addEventListener('DOMContentLoaded', function() {
+ var elems = document.querySelectorAll('.dropdown-trigger');
+ var instances = M.Dropdown.init(elems, options);
+});
+
+// jQuery 방식
+$('.dropdown-trigger').dropdown();
+```
+
+#### 주요 옵션
+| 옵션명 | 타입 | 기본값 | 설명 |
+|--------|------|--------|------|
+| alignment | String | 'left' | 메뉴 정렬 방향 정의 |
+| autoTrigger | Boolean | true | 키보드 포커스 자동 설정 |
+| constrainWidth | Boolean | true | 드롭다운 너비를 트리거 크기에 맞춤 |
+| container | Element | null | 드롭다운의 경계 컨테이너 지정 |
+| coverTrigger | Boolean | true | false시 트리거 아래에 드롭다운 표시 |
+| closeOnClick | Boolean | true | 항목 클릭시 드롭다운 닫기 |
+| hover | Boolean | false | 호버시 드롭다운 열기 |
+| inDuration | Number | 150 | 열림 애니메이션 지속시간 (ms) |
+| outDuration | Number | 250 | 닫힘 애니메이션 지속시간 (ms) |
+
+#### 주요 메서드
+- **`.open()`**: 드롭다운 열기
+- **`.close()`**: 드롭다운 닫기
+- **`.recalculateDimensions()`**: 내용 변경시 크기 재계산
+- **`.destroy()`**: 인스턴스 제거
+
+#### 인스턴스 속성
+- **`el`**: 초기화된 DOM 엘리먼트
+- **`options`**: 초기화 옵션 객체
+- **`id`**: 드롭다운 엘리먼트 ID
+- **`dropdownEl`**: 드롭다운 DOM 엘리먼트
+- **`isOpen`**: 드롭다운 열림 상태
+- **`isScrollable`**: 드롭다운 스크롤 가능 여부
+- **`focusedIndex`**: 포커스된 항목 인덱스
+
+### 시스템 적용 방식
+
+본 RPS 시스템에서는 Materialize CSS 드롭다운을 다음과 같이 활용합니다:
+
+1. **CDN 라이브러리 로드**
+ ```html
+
+
+
+
+
+
+ ```
+
+2. **동적 메뉴 로딩**: AJAX를 통해 서버에서 메뉴 데이터를 가져와 동적으로 드롭다운 생성
+3. **Material Design 아이콘**: 메뉴 항목에 Material Icons 적용으로 시각적 향상
+4. **커스텀 스타일링**: basic.css를 통해 기존 시스템 디자인과 조화로운 스타일 적용
+
## 프로젝트 구조 (폴더별 역할)
- **`.git/`**: Git 버전 관리 시스템 메타데이터 저장소.
diff --git a/WebContent/WEB-INF/view/main/contentsFS.jsp b/WebContent/WEB-INF/view/main/contentsFS.jsp
index f279e73..6f65a82 100644
--- a/WebContent/WEB-INF/view/main/contentsFS.jsp
+++ b/WebContent/WEB-INF/view/main/contentsFS.jsp
@@ -1,20 +1,5 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/WebContent/WEB-INF/view/main/header.jsp b/WebContent/WEB-INF/view/main/header.jsp
index 3a8971f..e0f7922 100644
--- a/WebContent/WEB-INF/view/main/header.jsp
+++ b/WebContent/WEB-INF/view/main/header.jsp
@@ -11,7 +11,7 @@ ArrayList userMenuList = new ArrayList();
userMenuList = (ArrayList)request.getAttribute("userMenuList");
%>
-
+
<%=Constants.SYSTEM_NAME %>
@@ -26,17 +26,25 @@ userMenuList = (ArrayList)request.getAttribute("userMenuList");
}
*/
.menu_off{
- color:#000;
- font-size:14px;
- font-weight:normal;
+ color:#fff !important; padding: 2px 3px; font-size:9px; background-color:#0011ff; border-radius:2px;
+ display: inline-block; min-width: 40px; text-align: center; margin: 0px;
+ transition: all 0.3s ease; text-decoration: none !important; border: none;
+ cursor: pointer;
}
.menu_on{
- color:#B3A7A7;
- font-size:15px;
- font-weight:bold;
+ color:#fff !important; padding: 2px 3px; font-size:9px; background-color:#c4c4f4; border-radius:2px;
+ display: inline-block; min-width: 40px; text-align: center; margin: 0px;
+ transition: all 0.3s ease; text-decoration: none !important; border: none;
+ cursor: pointer;
+ }
+ .menu_off:hover {
+ background-color: #c4c4f4 !important;
+ text-decoration: none !important;
+ color: #fff !important;
}
+
@@ -83,16 +91,51 @@ $(function(){
fn_registDetailPopup(userId);
});
- $(".menu").click(function(){
- var menuObjid = $(this).attr("menuObjid");
-
- $(".menu_on").removeClass('menu_on').addClass('menu_off'); //이전 클릭한 메뉴 원복
- $(this).removeClass('menu_off');
- $(this).addClass('menu_on');
+ $(".menu").click(function(){
+ // 모든 메뉴를 off 스타일로 변경
+ $(".menu").css({
+ 'background-color': '#0011ff',
+ 'color': '#fff'
+ }).removeClass('menu_on').addClass('menu_off');
+
+ // 클릭된 메뉴를 on 스타일로 변경
+ $(this).css({
+ 'background-color': '#c4c4f4',
+ 'color': '#fff'
+ }).removeClass('menu_off').addClass('menu_on');
+
+ var menuObjid = $(this).attr("menuObjId");
+
+ // 안전하게 메뉴 처리
+ try {
+ if(parent.frames["contentsFS"] && parent.frames["contentsFS"].frames["menu_page"]) {
+ var menuFrame = parent.frames["contentsFS"].frames["menu_page"];
+ if(menuFrame.fn_initMenuArea && menuFrame.add_menu) {
+ menuFrame.fn_initMenuArea();
+ menuFrame.add_menu(menuObjid);
+ }
+ }
+ } catch(e) {
+ console.log("Menu frame not ready:", e);
+ }
+
+
+ });
- parent.frames["contentsFS"].frames["menu_page"].fn_initMenuArea();
- parent.frames["contentsFS"].frames["menu_page"].add_menu(menuObjid);
- });
+ // 메뉴 hover 효과
+ $(".menu").hover(
+ function() {
+ if (!$(this).hasClass('menu_on')) {
+ $(this).css('background-color', '#E08550');
+ }
+ },
+ function() {
+ if (!$(this).hasClass('menu_on')) {
+ $(this).css('background-color', '#F29661');
+ }
+ }
+ );
+
$(".btnApprovalList").click(function(){
fn_goMyTaskMyApproval();
@@ -162,7 +205,31 @@ function fn_goFirstMenu(){
if($(".menu") && $(".menu").eq(0)){
var menuObjId = $(".menu").eq(0).attr("menuObjId");
//alert(menuObjId); -84984128(scm)
- fn_goMenu(menuObjId);
+
+ // 모든 메뉴를 off 스타일로 변경
+ $(".menu").css({
+ 'background-color': '#0011ff',
+ 'color': '#fff'
+ }).removeClass('menu_on').addClass('menu_off');
+
+ // 첫 번째 메뉴를 on 스타일로 변경
+ $(".menu").eq(0).css({
+ 'background-color': '#c4c4f4',
+ 'color': '#fff'
+ }).removeClass('menu_off').addClass('menu_on');
+
+ // 안전하게 메뉴 처리
+ try {
+ if(parent.frames["contentsFS"] && parent.frames["contentsFS"].frames["menu_page"]) {
+ var menuFrame = parent.frames["contentsFS"].frames["menu_page"];
+ if(menuFrame.fn_initMenuArea && menuFrame.add_menu) {
+ menuFrame.fn_initMenuArea();
+ menuFrame.add_menu(menuObjId);
+ }
+ }
+ } catch(e) {
+ console.log("Menu frame not ready:", e);
+ }
}
}
function fn_goMyTask(subMenuObjid, onlyViewMenu){
@@ -175,37 +242,43 @@ function fn_goDashboard(subMenuObjid, onlyViewMenu){
fn_goMenu(menuobjid, subMenuObjid, onlyViewMenu);
}
function sel_menu(menuobjid, subMenuObjid, onlyViewMenu){
- parent.frames["contentsFS"].frames["menu_page"].sel_menu(menuobjid, subMenuObjid, onlyViewMenu);
+ // 왼쪽 프레임 제거로 인해 더 이상 사용하지 않음
+ // parent.frames["contentsFS"].frames["menu_page"].sel_menu(menuobjid, subMenuObjid, onlyViewMenu);
+ console.log("sel_menu 호출됨 - 드롭다운 메뉴 방식으로 변경됨");
}
function fn_goMenu(menuobjid, subMenuObjid, onlyViewMenu){
if(fnc_isEmpty(menuobjid)){
return;
}
- //$(".menu[menuobjid="+menuobjid+"]").trigger("click");
+
fn_selTopMenu(menuobjid);
- /*
- if(parent && parent.parent && parent.parent.frames["headerFS"] && typeof(parent.parent.frames["headerFS"].fn_goMyTask) == "function" ){
- parent.parent.frames["headerFS"].fn_goMyTask();
- }
- */
+ // 드롭다운 메뉴 방식으로 변경 - 왼쪽 프레임 제거됨
+ // 메뉴 클릭시 해당 메뉴의 첫 번째 하위 메뉴로 이동하거나 기본 페이지로 이동
+ $(".menu[menuObjId='" + menuobjid + "']").trigger("click");
+
+ /* 기존 왼쪽 프레임 방식 제거
parent.frames["contentsFS"].frames["menu_page"].fn_initMenuArea();
parent.frames["contentsFS"].frames["menu_page"].add_menu(menuobjid, subMenuObjid, onlyViewMenu);
-
- //top.frames["contentsFS"].frames["menu_page"].fn_initMenuArea();
- //top.frames["contentsFS"].frames["menu_page"].add_menu(menuobjid, subMenuObjid, onlyViewMenu);
+ */
}
+var menuLoaded = false;
+
function fn_firstCallMenu(){
- if( parent
- && parent.frames["contentsFS"]
- && parent.frames["contentsFS"].frames["menu_page"]
- && parent.frames["contentsFS"].frames["menu_page"].fn_initMenuArea ){
- //fn_goMyTask();
- //alert('1');
- fn_goFirstMenu();
- clearInterval(_intervalId);
+ // 이미 로드되었으면 중복 실행 방지
+ if(menuLoaded) return;
+
+ // 왼쪽 프레임이 복구되었으므로 기존 방식으로 첫 번째 메뉴 호출
+ if(parent && parent.frames["contentsFS"] && parent.frames["contentsFS"].frames["menu_page"]){
+ // 메뉴 프레임이 완전히 로드될 때까지 기다림
+ var menuFrame = parent.frames["contentsFS"].frames["menu_page"];
+ if(menuFrame.fn_initMenuArea && menuFrame.add_menu) {
+ fn_goFirstMenu();
+ clearInterval(_intervalId);
+ menuLoaded = true;
+ }
}
}
@@ -259,6 +332,7 @@ function openAdminMngPop(){
window.open("/admin/adminMainFS.do","<%=Constants.SYSTEM_NAME %>","width=1630,height=950,menuBar=no,status=no");
}
+
//결재건수조회
function fn_setApprovalCnt(){
$.ajax({
@@ -285,72 +359,63 @@ function fn_setApprovalCnt(){
-
+