20210831 - 캘린더 일정 관리, 그룹별 색상 표현

1. 페이지 구조

Parent 리전 : Static Contents

Sub 리전1 : 일정구분에 따른 색상 그룹 정보

Sub 리전2 : 캘린더


2. Sub 리전1 - Type : Classic Report


select listagg(type_nm, '  ') within group (order by orderby) event_types
  from (
         select '<span class="a-luminance-color t-Badge t-Badge--basic t-Badge--small '
||apex_escape.html(lower(css_cal))||'">'||apex_escape.html(cal_type_nm)
||'</span>' type_nm
              , orderby
           from x0822_calendar_css
          where use_yn = 'Y'
       )

Appearance - Template : Standard

Template Options : Use Template Defaults, Remove Body Padding, Hidden, Remove Borders, Scroll Default

Column - Security - Escape special characters : Disabled


3. Page - CSS - Inline


.t-Badge.apex-cal-default { background-color: #2578CF; border-color: #2578CF; color: #FFFFFF; }
.t-Badge.apex-cal-black { background-color: #303030; border-color: #303030; color: #FFFFFF; }
.t-Badge.apex-cal-blue { background-color: #4183D7; border-color: #4183D7; color: #FFFFFF; }
.t-Badge.apex-cal-bluesky { background-color: #6BB9F0; border-color: #6BB9F0; color: #404040; }
.t-Badge.apex-cal-brown { background-color: #D88935; border-color: #D88935; color: #404040; }
.t-Badge.apex-cal-cyan { background-color: #1ABC9C; border-color: #1ABC9C; color: #404040; }
.t-Badge.apex-cal-darkblue { background-color: #1F5F97; border-color: #1F5F97; color: #FFFFFF; }
.t-Badge.apex-cal-gray { background-color: #A0A0A0; border-color: #A0A0A0; color: #404040; }
.t-Badge.apex-cal-green { background-color: #2ECC71; border-color: #2ECC71; color: #404040; }
.t-Badge.apex-cal-lime { background-color: #28A346; border-color: #28A346; color: #FFFFFF; }
.t-Badge.apex-cal-orange { background-color: #F39C12; border-color: #F39C12; color: #404040; }
.t-Badge.apex-cal-red { background-color: #D91E18; border-color: #D91E18; color: #FFFFFF; }
.t-Badge.apex-cal-silver { background-color: #BDC3C7; border-color: #BDC3C7; color: #404040; }
.t-Badge.apex-cal-white { background-color: #F0F0F0; border-color: #F0F0F0; color: #404040; }
.t-Badge.apex-cal-yellow { background-color: #F1C40F; border-color: #F1C40F; color: #404040; }



3. Sub 리전2 - Type : Calendar


select a.cal_id
     , nvl(b.css_cal,'') as css
     , a.sdt
     , a.edt
     , nvl(b.cal_type_nm||': ','') ||a.mst as mst
     , a.dtl
  from x0822_calendar     a
     , x0822_calendar_css b
 where a.css_id = b.css_id(+)

Appearance - Template : Standard

Template Options : Use Template Defaults, Hidden, Remove UI Decoration, Scroll Default

Attributes - CSS Class : CSS

Create Link : Page

Name : P8_SDT

Value : &APEX$NEW_START_DATE.



Built in Calendar CSS

  • apex-cal-red
  • apex-cal-cyan
  • apex-cal-blue
  • apex-cal-bluesky
  • apex-cal-darkblue
  • apex-cal-green
  • apex-cal-yellow
  • apex-cal-silver
  • apex-cal-brown
  • apex-cal-lime
  • apex-cal-white
  • apex-cal-gray
  • apex-cal-black
  • apex-cal-orange


4. 완성 UI






20210829 - Interactive Grid 행 추가 버튼, 편집, 저장 버튼 위치 변경 및 탭 그룹화

1. 탭 그룹화

Static Content 리전을 만들고

Appearance - Template : Tabs Container로 설정

그리고 각 탭에 위치할 Sub 하위 리전들을 생성




2. 편집, 저장, 행 추가 기본 위치 좌측인데 우측으로 변경

Attributes - Advanced - JavaScript Initialization Code


function(config) {
    let $                = apex.jQuery,
        toolbarData      = $.apex.interactiveGrid.copyDefaultToolbar();
        addrowAction     = toolbarData.toolbarRemove("selection-add-row");
        saveAction       = toolbarData.toolbarRemove("save");
        editAction       = toolbarData.toolbarRemove("edit");
        actionsMenuGroup = toolbarData.toolbarFind("actions4");

    actionsMenuGroup.controls.push({
        type  : "BUTTON",
        action: "edit",
        label : "편집"
        });

    actionsMenuGroup.controls.push({
        type  : "BUTTON",
        action: "save",
        label : "저장",
        icon  : "icon-ig-save-as",
        iconBeforeLabel: true,
        hot   : true
        });

    actionsMenuGroup.controls.push({
        type  : "BUTTON",
        action: "selection-add-row",
        label : "행 추가",
        icon  : "icon-ig-add-row",
        iconBeforeLabel: true,
        hot   : true
        });

    config.toolbarData = toolbarData;
    return config;
}




참고

https://tm-apex.blogspot.com/2021/03/customize-your-toolbar-interactive-grid.html

https://www.stinolez.com/2018/10/25/interactive-grids-more-customization/

























20210829 - Interactive Grid 행 추가 버튼 제어

1. IG 리전

Attributes - Advanced - JavaScript Initialization Code


function(config) { 
config.initActions = function( actions ) {
  actions.remove('selection-add-row');
  actions.add({
    name: "selection-add-row",
    label: "행 추가",
    iconBeforeLabel: "true",
    action: function(event, focusElement) {
      var vVal = apex.item("P4_PO_ID").getValue();
      if(vVal == "")
      {
        apex.message.alert("발주 내역을 먼저 등록/선택 후 상품을 등록하십시오.");
        return config;
      }

      let model = $(actions.context).interactiveGrid('getCurrentView').model;
      var vNewR = model.getRecord(model.insertNewRecord());

      model.setValue(vNewR,"PO_ID", vVal);
    }
  });
}
return config;
}









 

20210828 - 폼 버튼 제어 (등록시, 수정시 각 조건에 따른 보이기/감추기)

1. 신규 생성 폼 - 취소는 항상 보이기(조건없음), 등록 버튼만 보임

Create 등록 버튼

Button - Server-side Condition - Type : Item is NULL

Item : P5_PO_ID (key로 설정되어 있고, hidden 상태)



2. 수정 폼 - 저장과 삭제 버튼 보임

Button - Server-side Condition - Type : Item is NOT NULL

Item : P5_PO_ID (key로 설정되어 있고, hidden 상태)














20210827 - 상품 마스터 - 상품 입출고 디테일 Interactive Grid Master-Detail

1. 페이지 생성, Master Detail, Stacked 선택 후 테이블과 키값 입력 : 

한 페이지에 Master Detail 표현




2. 마스터 SQL : 상품과 입/출고, 재고 수량


select a.prod_id
     , a.prod_nm
     , a.prod_color
     , nvl(b.sum1_qty,0) sum1_qty
     , nvl(b.sum2_qty,0) sum2_qty
     , nvl(b.sum_qty,0)  sum_qty
  from x0822_prod_mst a
     , (
         select prod_id
              , sum(decode(stock_type, '1', qty, 0)) sum1_qty
              , sum(decode(stock_type, '2', qty, 0)) sum2_qty
              , sum(decode(stock_type, '1', qty, '2', -qty, 0)) sum_qty
           from x0822_prod_stock
          group by prod_id
       ) b
 where a.prod_id = b.prod_id(+)


3. 마스터 리전 : 상품 마스터

PK PROD_ID hidden

입고, 출고, 재고는 Display Only, Source - Query Only : Enabled

저장 업데이트 시 For Update 오류 때문에 Process - Identification - Lock Row : No




4. 디테일 리전 : 상품 입출고

1) 조건 없이 Query만 등록


select STOCK_ID,
       STOCK_DATE,
       STOCK_TYPE,
       PROD_ID,
       QTY
  from X0822_PROD_STOCK

2) Master Detail - Master Region : 상품 마스터


3) 좌측 항목에서 FK PROD_ID 선택, 우측 속성에서

Master Detail - Master Column : PROD_ID (마스터 리전 것 선택)



5. 디자인 조정 : 마스터 리전의 입고, 출고, 재고 항목들은 동일 배분 사이즈가 아닌 

픽셀 70으로 고정해서 작게하면 상품명과, 상품 색상은 자연스럽게 길어짐



6. 최종 화면
































20210824 - 전화번호 포맷

1. JS 파일 업로드 (파일 다운로드는 하단 링크 참조)

Shared Components - Static Workspace Files




select rowid
     , user_mobile
     , replace(to_CHAR(user_mobile,'000,9999,9999'),',','-') user_mobile_vw
     , user_nm
     , role
  from x0822_users


var gridID = "myStaticIG";

var ig$    = apex.region(gridID).widget();

var grid   = ig$.interactiveGrid("getViews","grid");

var model  = ig$.interactiveGrid("getViews","grid").model;

var selectedRecords = grid.getSelectedRecords();


for (idx = 0; idx < selectedRecords.length; idx++) {

    record = model.getRecord(selectedRecords[idx][0]);

    model.setValue(record, 'USER_MOBILE', this.triggeringElement.value);

}

/* reference

  //insert new record on a model

  var myNewRecordId = model.insertNewRecord();

  console.log(record);

  console.log(model.getValue(record,"USER_NAME"));

*/





참고 : 

https://css-tricks.com/input-masking/

https://github.com/RobinHerbots/Inputmask

20210824 - 임의 랜덤 데이터 생성 준비 : 이름 및 전화번호

1. DB Function 함수 생성


CREATE OR REPLACE FUNCTION GET_KORNM 
    ( V_FROM IN VARCHAR2,
      V_TO   IN VARCHAR2 )
RETURN VARCHAR2 
IS
    OUT_REAL_NM VARCHAR2(100);
    TYPE V_ARR IS TABLE OF VARCHAR2(10);
    V_FIRST V_ARR;
    V_LAST V_ARR;
    V_MID V_ARR;
BEGIN 
    V_LAST := V_ARR('김' , '이' , '박' , '최' , '정'
                  , '강' , '조' , '윤' , '장' , '임' 
                  , '오' , '한' , '신' , '서' , '권' 
                  , '황' , '안' , '송' , '유' , '홍' 
                  , '전' , '고' , '문' , '손' , '양' 
                  , '배' , '조' , '백' , '허' , '남');
                  
    V_MID := V_ARR('민' , '현' , '동' , '인' , '지'
                 , '현' , '재' , '우' , '건' , '준' 
                 , '승' , '영' , '성' , '진' , '준' 
                 , '정' , '수' , '광' , '영' , '호' 
                 , '중' , '훈' , '후' , '우' , '상' 
                 , '연' , '철' , '아' , '윤' , '은');
                 
    V_FIRST := V_ARR('유' , '자' , '도' , '성' , '상' 
                   , '남' , '식' , '일' , '철' , '병' 
                   , '혜' , '영' , '미' , '환' , '식' 
                   , '숙' , '자' , '희' , '순' , '진' 
                   , '서' , '빈' , '정' , '지' , '하' 
                   , '연' , '성' , '공' , '안' , '원'); 
                   
SELECT SUBSTR(V_LAST(ROUND(DBMS_RANDOM.VALUE(1 , 30), 0)) ||
              V_MID(ROUND(DBMS_RANDOM.VALUE(1 , 30), 0)) ||
              V_FIRST(ROUND(DBMS_RANDOM.VALUE(1 , 30), 0)) ||
              V_MID(ROUND(DBMS_RANDOM.VALUE(1 , 30), 0)) ||
              V_FIRST(ROUND(DBMS_RANDOM.VALUE(1 , 30), 0)) 
             , V_FROM, V_TO)
     INTO OUT_REAL_NM 
    FROM DUAL; 
    
    RETURN OUT_REAL_NM; 
    
END;

출처: https://cyh0214.tistory.com/entry/무작위-한글이름-만들기 [맑은안개이야기]


입력 변수를 통해 1글자, 2, 3, 4, 5자 성명 글자 생성


select GET_KORNM('1','3') from dual


전화번호는 너무 진짜같지 않게 중간에 0000 으로 생성


select trim('0100000'||trunc(DBMS_RANDOM.value(0,9)*1000)) from dual










20210824 - 프로토타입 페이지 작성 - 메인홈 카드 리전 Lottie Animation

1. 카드 리전 추가 후 SQL 작성 (Lottie File 위치 추가)


select '발주, 배송관리 시스템' card_title
     , '' card_subtitle
     , '주문 등록, 배송 관리, C/S업무' card_body
     , '' card_secondary_body
     , 'fa fa-package' card_icon
     , '81' card_badge
     , 'https://assets10.lottiefiles.com/private_files/lf30_ow8fqzzg.json' card_image
  from dual


2. Lottie Animation 사용 설정

Page 설정에서 

Javascript - File URLs : https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js

CSS - Inline : 

lottie-player {

    margin: 0 auto;

}



Card Region - Attributes - Appearance - Layout : Grid

Grid Columns : 4 Columns

Title - Column : CARD_TITLE

Subtitle - HTML Expression :

<lottie-player src="&CARD_IMAGE."  background="transparent"  speed="1"  style="width: 200px; height: 200px;"  loop  autoplay></lottie-player>

Body - Column : CARD_BODY

Icon and Badge - Icon Source : Icon Class Column

Icon Column : CARD_ICON

Badge Column : CARD_BADGE









 

20210821 - 포트폴리오 메인 페이지 작성 - 예상금액확인

1. 단가 표현을 위한 Collection 생성

Pre-Rendering - Before Regions - Processes

Identification - Name : CreateCollection

Type : Execute Code

Source - Location : Local Database

Language : PL/SQL

PL/SQL Code : 


declare
  --l_session apex_application.g_instance%type := apex_application.g_instance;
  l_query varchar2(20000) := 
    'select cd
          , to_number(grp2) hh24
          , to_number(grp3) amt
          , 0 page_cnt
          , 0 page_amt
          , null, null, null, null, null, null
       from jkmst_cd_mst 
      where grp_id = 1 and cd != ''00''
      order by cd';
begin
  APEX_COLLECTION.DELETE_ALL_COLLECTIONS;
  APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY2 (
    p_collection_name => 'ESTIMATION', 
    p_query => l_query,
    p_generate_md5 => 'YES');
end;


2. 예상금액확인 리전 생성

Identification - Name : 예상금액확인

Type : Classic Report

** 앞서 만들어 놓은 collection 에서 데이터를 읽어 오면서 컬럼별 스타일 적용


select '<span class="t-Icon fa fa-number-'||trim(to_char(n001))||'-o fa-2x" aria-hidden="true"></span>' cd
     , n002 hh24, n003 amt
     , n004 page_cnt
     , (n003 * n004) page_amt
     , '<button class="ButtonXU t-Button t-Button--default t-Button--hot" id=U-'||trim(to_char(n001))||' type="button"><span aria-hidden="true" class="fa fa-arrow-circle-o-up"></span></button>' btn_up
     , '<button class="ButtonXD t-Button t-Button--default" id=D-'||trim(to_char(n001))||' type="button"><span aria-hidden="true" class="fa fa-arrow-circle-o-down"></span></button>' btn_down
  from apex_collections 
 where collection_name = 'ESTIMATION'
 order by seq_id


Appearance - Template Options : Use Template Defaults, Show Region Icon, Accent 2, Scroll - Default

Icon : fa-dollar fa-2x

그리고 디자인이 들어간 CD, BTN_UP, BTN_DOWN 은 컬럼 Type을 Markdown 으로하여 HTML 표현



Dynamic Action - Name : UbtnClicked

When - Event : Click

Selection Type : jQuery Selector

jQuery Selector : .ButtonXU (button class name in sql design)


-- True Action1 : Set Value (PL/SQL에서 클릭 버튼 종류를 인식하기 위해 U, D 값 셋팅)

Set Type : JavaScript Expression : this.triggeringElement.id

Affected Elements : P3_ID


-- True Action2 : Execute Server-side Code (클릭된 Row의 값 계산, 누적)


declare
  lv_value varchar2(100) := :P3_ID;
  lv_calc  varchar2(1)   := substr(lv_value,1,1);
  ln_level number        := to_number(substr(lv_value,3));
  ln_cnt   number        := 0;
begin
--raise_application_error(-20001, substr(lv_value,1,1));

  if :P3_ID is null then return; end if;

  select n004 into ln_cnt 
    from apex_collections
   where collection_name = 'ESTIMATION'
     and seq_id          = ln_level;
  
  if lv_calc = 'U' then
    ln_cnt := ln_cnt + 1;
  else
    ln_cnt := ln_cnt - 1;
  end if;

  if ln_cnt < 0 then return; end if;

--raise_application_error(-20001, ln_cnt);
  APEX_COLLECTION.UPDATE_MEMBER_ATTRIBUTE (
    p_collection_name => 'ESTIMATION',
    p_seq             => to_char(ln_level),
    p_attr_number     => 4,
    p_number_value    => ln_cnt);

  select sum(n003 * n004) into ln_cnt 
    from apex_collections
   where collection_name = 'ESTIMATION';

  :P3_SUM := TO_CHAR(ln_cnt,'999,999,999,999');
end;



-- True Action3 : Refresh (계산된 Collection에서 값 읽어오기)

Selection Type : Region

Region : 예상금액확인


-- True Action4 : Execute JavaScript Code (리전 상단의 합계 버튼에 값 셋팅)

$('#myStaticBTN span.t-Button-label').text(apex.item('P3_SUM').getValue())



참고

https://docs.oracle.com/en/database/oracle/application-express/21.1/aeapi/CREATE_COLLECTION_FROM_QUERY2-Procedure.html#GUID-7800CD9E-FD29-4E49-B637-A426D78A644C


CREATE_COLLECTION_FROM_QUERY2 Procedure

Use this procedure to create a collection from a supplied query. This method is identical to CREATE_COLLECTION_FROM_QUERY, however, the first 5 columns of the SELECT clause must be numeric and the next 5 must be date. After the numeric and date columns, there can be up to 50 character columns in the SELECT clause. The query is parsed as the application owner. If a collection exists with the same name for the current user in the same session for the current Application ID, an application error is raised.                   

이 프로시저를 사용할 경우 반드시 첫 5개는 숫자, 다음 5개는 일자 그리고 1개는 문자가 필요함. Null이라도 표시해야 함.


declare
  l_query varchar2(20000) := 
    'select prod_id, prod_qty, 0, 0, 0, null, null, null, null, null, null 
from po_mst where rownum <= 3';
begin
  
  APEX_COLLECTION.CREATE_COLLECTION_FROM_QUERY2 (
    p_collection_name => 'PRODLIST', 
    p_query => l_query,
    p_generate_md5 => 'YES',
    p_truncate_if_exists => 'YES');

end;

20250202 - IG 다운로드 버튼 바로 보이기

JS initialization Code : function (config) {     var $ = apex.jQuery,         toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),  ...