교통수단 행추가 중

DDUBINI·2025년 3월 8일

      <div class="cont-box-inner search-box">
        <div class="cont-box-inner">
          <div class="title flex">
            <h3>국내출장신청</h3>
            <h3 class="red-txt">(①~③ 필수입력)</h3>
            <div class="right-part">
              <!-- <button type="button" class="btn default" (click)="btnCrgrCncl()" [disabled]="btnCancelDisabled">
                <i class="material-icons outlined iconL">task_alt</i>담당자취소
              </button> -->
              <a2m-aplf-button 
                [rqstNo]="saveParam.bztrpRqstNo"
                [statusCode]="saveParam.misApprvStatCd"
                (save)="btnSave($event)"
                (delete)="btnDelete()"
                (init)="getForm0101()">
              </a2m-aplf-button>
            </div>
          </div>

          <div class="tbl grid-layout grid4">

            <div class="grid-item">
              <label>신청번호</label>
              <div class="tbl-basic-td center">
                {{saveParam?.bztrpRqstNo}}
                <!-- <div class="select-wrap">
                  <ejs-dropdownlist
                    [dataSource]="sWrkAreaCd"
                    [value]="userInfo.wrkAreaCd"
                    [enabled]="false"
                    [fields]="{ text: 'nm', value: 'cd' }">
                  </ejs-dropdownlist>
                </div> -->
              </div>
            </div>
            <div class class="grid-item">
              <label>소속부서</label>
              <div class="tbl-basic-td center">
                {{saveParam.rqstrDeptNm}}
              </div>
            </div>
            <div class class="grid-item">
              <label>신청일자</label>
              <div class="tbl-basic-td center">
                {{saveParam?.rqstDt | comDatePipe}}
              </div>
            </div>
            <div class class="grid-item">
              <label>신청자</label>
              <div class="tbl-basic-td center">
                {{saveParam.rqstrEmpNm}}
              </div>
            </div>

            <div class class="grid-item colspan2">
              <label>제목</label>
              <div class="tbl-basic-td">
                {{saveParam.apprvTitl}}
              </div>
            </div>
           
            <div class class="grid-item">
              <label>회계금액</label>
              <div class="tbl-basic-td center">
                {{ saveParam.rqstAmt | comCommaPipe}}
                <!-- <div class="input-wrap w100 right">
                  <ejs-textbox
                    class="e-input e-small"
                    [value]="saveParam.rqstAmt"
                    [enabled]="false">
                  </ejs-textbox>
                </div> -->
              </div>
            </div>

            <div class="grid-item">
              <label class="right">결재상태</label>
              <div class="tbl-basic-td center">
                {{saveParam.misApprvStatNm}}
              </div>
            </div>

          </div>
        </div>
      </div>

      <div class="cont-box-inner">
        <div class="title">
          <h3>① 예산내역</h3>
        </div>

        <div class="tbl grid-layout grid3">
          <div class="grid-item colspan2">
            <label class="verticalM">예산과목<em class="org-txt asterisk">*</em></label>
            <div class="tbl-basic-td">
              <div class="input-wrap w80">
                <app-search-data
                  [component]="bdgPrjDtlDComponent"
                  [width]="bdgPrjDtlDWidth"
                  [height]="bdgPrjDtlDHeight"
                  [class]="['w40','w15']"
                  [disabled]="[!bscInptItemEnabled, !bscInptItemEnabled]"
                  [initValue]="[saveParam.bdgNm, saveParam.bdgCd]"
                  [param]="{bizClDivCd:'01'}"
                  (dataEmit)="dialogSaveParamChange($event, 'bdgCd')">
                </app-search-data>
                <!-- <div class="input-wrap w20">
                  <ejs-textbox
                    class="e-input e-small"
                    [value]="saveParam.exenmiv"
                    [enabled]="false">
                  </ejs-textbox>
                </div>
                <div class="input-wrap w15">
                  <ejs-textbox
                    class="e-input e-small"
                    [value]="saveParam.execdiv"
                    [enabled]="false">
                  </ejs-textbox>
                </div> -->
              </div>
            </div>
          </div>
          <div class class="grid-item">
            <label class="verticalM">비용항목</label>
            <div class="tbl-basic-td">
              <div class="input-wrap">
                <div class="input-wrap inputwnormal">
                  <ejs-textbox
                    class="e-input e-small"
                    [value]="saveParam.eptmNm"
                    [enabled]="false">
                  </ejs-textbox>
                </div>
                &nbsp;
                <div class="input-wrap inputwXshort">
                  <ejs-textbox
                    class="e-input e-small"
                    [value]="saveParam.eptmCd"
                    [enabled]="false">
                  </ejs-textbox>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="cont-box-inner">
        <div class="title">
          <h3>② 출장정보</h3>
        </div>
        <div class="tbl grid-layout grid3">
          <div class class="grid-item">
            <label class="verticalM">출장기간<em class="org-txt asterisk">*</em></label>
            <div class="tbl-basic-td">
              <div class="flex datepicker-wrap">
                <div class="datepicker-item px110">
                  <app-datepicker
                    [value]="saveParam.bztrpBginDt"
                    (dateEmit)="dateSaveParamChange($event, 'bztrpBginDt')"
                    [enabled]="bscInptItemEnabled"
                    selectionMode="date" #beginDatepicker [endDatepicker]="endDatepicker"
                  >
                  </app-datepicker>
                </div>
                <span class="cal-dash"></span>
                <div class="datepicker-item px110">
                  <app-datepicker
                    [value]="saveParam.bztrpEndDt"
                    (dateEmit)="dateSaveParamChange($event, 'bztrpEndDt')"
                    [enabled]="bscInptItemEnabled"
                    selectionMode="date" #endDatepicker [beginDatepicker]="beginDatepicker"
                  >
                  </app-datepicker>
                </div>
              </div>
            </div>


          </div>
          <div class class="grid-item">
            <label class="verticalM">출장일수</label>
            <div class="tbl-basic-td">
              <div class="w100">
                <div class="input-wrap px30">
                  <!-- {{saveParam.bztrpTotLodgNum}} -->
                  <ejs-numerictextbox
                    class="e-input e-small right"
                    format="N"
                    min="0"
                    [showSpinButton]='false'
                    [(ngModel)]="saveParam.bztrpTotLodgNum"
                    [enabled]="bscInptItemEnabled"
                    (blur)="bztrpTotLodgNumChange($event)"
                    >
                  </ejs-numerictextbox>
                </div>
                &nbsp;&nbsp;
                <div class="input-wrap px40 center">
                  {{ saveParam.bztrpTotDdNum }}
                </div>
                &nbsp;</div>
            </div>
          </div>
          <div class class="grid-item">
            <label class="verticalM">출장형태<em class="org-txt asterisk">*</em></label>
            <div class="tbl-basic-td">
              <div class="select-wrap">
                <ejs-dropdownlist
                  [dataSource]='sBztrpShpCd'
                  [fields]="{ text: 'nm', value: 'cd' }"
                  [value]="saveParam.bztrpShpCd"
                  (change)="dropdownSaveParamChange($event, 'bztrpShpCd')"
                  [enabled]="!saveParam.extrlLctrRqstNo">
                </ejs-dropdownlist>
              </div>
            </div>
          </div>

          <div class class="grid-item">
            <label>대결지정</label>
            <div class="tbl-basic-td">
              <div class="input-wrap px100">
                <ejs-dropdownlist
                  [dataSource]='sUseYn'
                  [fields]="{ text: 'nm', value: 'cd' }"
                  [value]="grdD0101Data.sapvApntYn"
                  (change)="grdD0101Change($event, 'sapvApntYn')"
                  [enabled]="grdItemEnabled">
                </ejs-dropdownlist>
              </div>
            </div>
          </div>
          <div class class="grid-item colspan2">
            <label>업무 대행자</label>
            <div class="tbl-basic-td">
              <div class="input-wrap">
                <app-search-data-grid
                  [component]="empDComponent"
                  [width]="empDWidth"
                  [height]="empDHeight"
                  [class]="['w60', '']"
                  [dataHidden]="true"
                  [enabled]="[grdItemEnabled, grdItemEnabled]"
                  [param]="{deptCd: grdD0101Data.bztrpDeptCd, deptNm: grdD0101Data.bztrpDeptNm }"
                  [initValue]="[grdD0101Data.angtEmpNm, grdD0101Data.angtEmpNo]"
                  (dataEmit)="grdD0101AngtNmChange($event)">
                </app-search-data-grid>
              </div>
            </div>
          </div>

          <!-- <div class class="grid-item colspan3">
            <label>0원 출장여부</label>
            <div class="tbl-basic-td">
              <div class="input-wrap">
                <app-checkbox
                  [value]="saveParam.bztrp0AmtYn"
                  (dataEmit)="bztrp0AmtYnChange($event)"
                  [disabled]="!bscInptItemEnabled">
                </app-checkbox>
                <p class="highlight blu-txt">&nbsp; ※ 체크 시 여비산출내역은 0원 처리됩니다.</p>
              </div>
            </div>
          </div> -->

          <div class class="grid-item">
            <label>교통수단</label>
            <div class="tbl-basic-td">
              <div class="input-wrap w100 flex">
                <div class="input-wrap px100">
                  <ejs-dropdownlist
                      [dataSource]='sTrfcMensCd'
                      [fields]="{ text: 'nm', value: 'cd' }"
                      [value]="saveParam.trfcMensCd"
                      (change)="trfcMensCdChange($event.value)"
                  >
                  </ejs-dropdownlist>
                </div>
                <div *ngIf="saveParam.trfcMensCd === '7' && saveParam.bztrpRqstNo" class="input-wrap">
                  <button class="btn xx-small" (click)="fn_veclRqst()">배차신청</button>
                </div>
              </div>
            </div>
          </div>

          <div class class="grid-item">
            <label>식비</label>
            <div class="tbl-basic-td">
              <div class="input-wrap w100">
                방문기관 식사 제공
                <div class="input-wrap px30">
                  <ejs-numerictextbox
                    class="e-input e-small right"
                    format="N"
                    min="0"
                    [(ngModel)]="saveParam.vsitInstMealInclNum"
                    (blur)="ddctNumChange($event.value, 'vsitInstMealInclNum')"
                    [showSpinButton]="false"
                    [enabled]="bscInptItemEnabled">
                  </ejs-numerictextbox>
                </div></div>
            </div>
          </div>

          <div class="grid-item overlap">
            <label class="label-float verticalM">숙박비</label>
            <div class="tbl-basic-td">
              <div class="tbl grid-layout  grid1">
                <div class="grid-item pd">
                  <div class="tbl-basic-td">
                    방문기관 제공
                    <div class="input-wrap px30">
                      <ejs-numerictextbox
                        class="e-input e-small right"
                        format="N"
                        min="0"
                        [(ngModel)]="saveParam.vsitInstLodgInclNum"
                        (blur)="ddctNumChange($event.value, 'vsitInstLodgInclNum')"
                        [showSpinButton]="false"
                        [enabled]="bscInptItemEnabled">
                      </ejs-numerictextbox>
                    </div></div>
                </div>
              </div>
            </div>
          </div>

          <!-- <div class="grid-item colspan3">
            <label>출장목적<em class="org-txt asterisk">*</em></label>
            <div class="tbl-basic-td">
              <div class="input-wrap w100">
                <div class="input-wrap w50">
                  <ejs-textbox
                    class="e-input e-small"
                    [value]="saveParam.bztrpRsnCntn"
                    (change)="commonSaveParamChange($event.value, 'bztrpRsnCntn')"
                  >
                  </ejs-textbox>
                  <a2m-valid title="출장목적"
                      objname="bztrpRsnCntn"
                      required="true"
                      [saveData]="saveParam?.bztrpRsnCntn"
                      [saveValid]="saveValid">
                  </a2m-valid>
                </div>
              </div>
            </div>
            

          </div> -->
        </div>
      </div>

      <div class="cont-box-inner">
        <div class="title">
          <h3>③ 출장지역(다중경로 선택가능)</h3>
          <div class="right-part">
            <div class="btn-wrap">
              <button *ngIf="saveParam.misApprvStatCd == '01'"
                type="button" class="btn small default disbtn" (click)="btnGrdD0102AddRow()" [disabled]="btnSaveDisabled">
                <i class="material-icons iconL">add</i>행추가
              </button>
              <button *ngIf="saveParam.misApprvStatCd == '01'"
                type="button" class="btn small default disbtn" (click)="btnGrdD0102RemoveRow()" [disabled]="btnSaveDisabled">
                <i class="material-icons iconL">remove</i>행삭제
              </button>
              <button type="button" class="btn default iconbtn small" (click)="btnGrdD0102Excel()">
                <i class="excel-icon"></i>엑셀
              </button>
            </div>
          </div>
        </div>

        <ejs-grid #grdD0102
                  locale="ko"
                  [dataSource]="grdD0102Data"
                  [height]="grdD0102Height"
                  [allowExcelExport]="true"
                  (excelQueryCellInfo)="excelQueryCellInfoHandler($event)"
                  [allowResizing]="true"
                  (keydown)="keydown($event)"
                  [pageSettings]="pageSettings"
                  (recordDoubleClick)="recordDoubleClickGrdD0102($event)"
                  (created)="createdD0102()"
                  >
          <e-columns>
            <e-column field="idx"  headerText="순번" width="60" minWidth="50" maxWidth="70" textAlign="Center" isPrimaryKey="true"></e-column>
            <e-column field="chk" headerTextAlign="Center" width="40" minWidth="30" maxWidth="50" textAlign="Center" [headerTemplate]="template03_CHK_HEADER" [template]="template03_CHK">
              <ng-template #template03_CHK_HEADER let-data>
                <ejs-checkbox [(checked)]="headerChkGrdD0102" (change)="grdD0102HeaderChkChange($event)"></ejs-checkbox>
              </ng-template>
              <ng-template #template03_CHK let-data>
                <ejs-checkbox [checked]="grdD0102Data[data.index]?.chk" (change)="grdD0102ChkChange($event, data.index)"></ejs-checkbox>
              </ng-template>
            </e-column>
            <e-column field="crud" headerText="상태" width="60" minWidth="50" maxWidth="60" textAlign="Center" [template]="template03_CRUD" [visible]="false">
              <ng-template #template03_CRUD let-data>
                {{grdD0102Data[data.index]?.crud_view}}
              </ng-template>
            </e-column>
            <e-column field="bstrGradCd" headerText="출장자직급코드" [visible]="false"></e-column>
            <e-column field="trfcCd" headerText="교통코드" [visible]="false"></e-column>
            <e-column
              field="trfcDivCd"
              [template]="template_TRFC_DIV_CD"
              headerText="교통구분"
              headerTextAlign="Center"
              textAlign="Center"
              width="100"
              [visible]="false"
            >
              <ng-template #template_TRFC_DIV_CD let-data>
                {{ grdD0102Data[data.index]?.trfcDivNm }}
              </ng-template>
            </e-column>
            <e-column
              field="mvBginDt"
              [template]="template_mvBginDt"
              headerText="시작일자&lt;em class='g-asterisk'&#47;&gt;"
              headerTextAlign="Center"
              textAlign="Center"
              [disableHtmlEncode]="false"
              width="110">
              <ng-template #template_mvBginDt let-data>
                <app-datepicker-grid
                    [value]="grdD0102Data[data.index]?.mvBginDt"
                    (dateEmit)="grdD0102Change($event, data.index, 'mvBginDt')"
                    [enabled]="grdItemEnabled">
                  </app-datepicker-grid>
              </ng-template>
            </e-column>
            <e-column
              field="mvEndDt"
              [template]="template_mvEndDt"
              headerText="종료일자&lt;em class='g-asterisk'&#47;&gt;"
              headerTextAlign="Center"
              [disableHtmlEncode]="false"
              textAlign="Center"
              width="110">
              <ng-template #template_mvEndDt let-data>
                <app-datepicker-grid
                    [value]="grdD0102Data[data.index]?.mvEndDt"
                    (dateEmit)="grdD0102Change($event, data.index, 'mvEndDt')"
                    [enabled]="grdItemEnabled">
                  </app-datepicker-grid>
              </ng-template>
            </e-column>
            <e-column
              field="stpnNm"
              [template]="template_stpnNm"
              headerText="출발지"
              headerTextAlign="Center"
              textAlign="Center"
              width="140">
              <ng-template #template_stpnNm let-data>
                {{grdD0102Data[data.index]?.stpnNm}}
              </ng-template>
            </e-column>
            <e-column
              field="arpnNm"
              [template]="template_arpnNm"
              headerText="도착지"
              headerTextAlign="Center"
              textAlign="Center"
              width="140">
              <ng-template #template_arpnNm let-data>
                {{grdD0102Data[data.index]?.arpnNm}}
              </ng-template>
            </e-column>
            <e-column
              field="chaeDivNm"
              [template]="template_CHAE_DIV_CD"
              headerText="요금구분"
              headerTextAlign="Center"
              textAlign="Center"
              width="100">
              <ng-template #template_CHAE_DIV_CD let-data>
                {{ grdD0102Data[data.index]?.chaeDivNm }}
              </ng-template>
            </e-column>
            <e-column
                field="trfcAmt"
                [template]="template03_trfcMensCd"
                headerText="교통수단"
                headerTextAlign="Center"
                textAlign="Right"
                width="100">
                <ng-template #template03_trfcMensCd let-data>
                  <ejs-dropdownlist
                        [dataSource]='sTrfcMensCd'
                        [fields]="{ text: 'nm', value: 'cd' }"
                        [value]="grdD0102Data[data.index].trfcMensCd"
                        (change)="trfcMensCdChange($event.value, data.index)"
                        >
                  </ejs-dropdownlist>
                  <ng-template #template03_trfcMensCd_view>
                    {{ grdD0102Data[data.index]?.trfcMensCd | comCommaPipe }}
                  </ng-template>
                </ng-template>
            </e-column>

            <e-column
              field="trfcAmt"
              [template]="template03_trfcAmt"
              headerText="교통비"
              headerTextAlign="Center"
              textAlign="Right"
              width="100">
              <ng-template #template03_trfcAmt let-data>
                <ejs-numerictextbox
                  *ngIf="grdD0102Data[data.index]?.crud_mode; else template03_trfcAmt_view"
                  class="e-input e-small right"
                  format="N" [showSpinButton]="false"
                  [value]="grdD0102Data[data.index].trfcAmt"
                  (change)="grdD0102Change($event.value, data.index, 'trfcAmt')"
                  [enabled]="trfcCldvInptItemEnabled">
                </ejs-numerictextbox>
                <ng-template #template03_trfcAmt_view>
                  {{ grdD0102Data[data.index]?.trfcAmt | comCommaPipe }}
                </ng-template>
              </ng-template>
            </e-column>
            <e-column
              field="drmtLodgYn"
              [template]="template03_drmtLodgYn"
              headerText="기숙사숙박여부"
              headerTextAlign="Center"
              textAlign="Center"
              width="120">
              <ng-template #template03_drmtLodgYn let-data>
                <ejs-checkbox [checked]="grdD0102Data[data.index]?.drmtLodgYn == 'Y' ? true : false" (change)="grdD0102Change($event, data.index, 'drmtLodgYn')"
                [disabled]="this.saveParam.misApprvStatCd !== '01'"
                ></ejs-checkbox>
              </ng-template>
            </e-column>
            <e-column
              field="lodgDdNum"
              [template]="template02_lodgDdNum"
              headerText="숙박일수"
              headerTextAlign="Center"
              textAlign="Center"
              width="80">
              <ng-template #template02_lodgDdNum let-data>
                <div class="input-wrap w30">
                <ejs-numerictextbox
                  *ngIf="grdD0102Data[data.index]?.crud_mode; else template02_lodgDdNum_view"
                  class="e-input e-small right"
                  format="N" [showSpinButton]="false"
                  [value]="grdD0102Data[data.index].lodgDdNum"
                  (change)="grdD0102Change($event.value, data.index, 'lodgDdNum')"
                  [enabled]="trfcCldvInptItemEnabled">
                </ejs-numerictextbox>
                </div>
                <ng-template #template02_lodgDdNum_view>
                  {{ grdD0102Data[data.index]?.lodgDdNum | comCommaPipe }}
                </ng-template></ng-template>
            </e-column>
            <e-column
              field="rmchrAmt"
              [template]="template03_rmchrAmt"
              headerText="숙박비"
              headerTextAlign="Center"
              textAlign="Right"
              width="80"
              >
              <ng-template #template03_rmchrAmt let-data>
                <ejs-numerictextbox
                  *ngIf="grdD0102Data[data.index]?.crud_mode; else template03_rmchrAmt_view"
                  class="e-input e-small right"
                  format="N" [showSpinButton]="false"
                  [value]="grdD0102Data[data.index].rmchrAmt"
                  (change)="grdD0102Change($event.value, data.index, 'rmchrAmt')"
                  [enabled]="false">
                </ejs-numerictextbox>
                <ng-template #template03_rmchrAmt_view>
                  {{ grdD0102Data[data.index]?.rmchrAmt | comCommaPipe }}
                </ng-template>
              </ng-template>
            </e-column>
            <e-column
              field="dwntBztrp"
              [template]="template02_dwntTime"
              headerText="시내출장"
              headerTextAlign="Center"
              textAlign="Center"
              width="150"
              *ngIf="dwntBztrpVisible"
            >
              <ng-template #template02_dwntTime let-data>
                <div class="input-wrap flex" *ngIf="grdD0102Data[data.index]?.crud_mode else template02_dwntTime_view">
                  <div class="input-wrap w45">
                    <app-timepicker 
                      [value]="grdD0102Data[data.index]?.dwntBztrpBginHh"
                      (dateEmit)="grdD0102Change($event, data.index, 'dwntBztrpBginHh')"
                    >
                    </app-timepicker>
                  </div>
                  <span>
                  ~
                  </span>
                  <div class="input-wrap w45">
                    <app-timepicker
                      [value]="grdD0102Data[data.index]?.dwntBztrpEndHh"
                      (dateEmit)="grdD0102Change($event, data.index, 'dwntBztrpEndHh')"
                    >
                    </app-timepicker>
                    </div>
                  </div>
                <ng-template #template02_dwntTime_view>
                  {{grdD0102Data[data.index]?.dwntBztrpBginHh | comDateTimePipe}} ~ {{grdD0102Data[data.index]?.dwntBztrpEndHh | comDateTimePipe}}
                </ng-template>
              </ng-template>
            </e-column>

            <e-column
              field="extrlLctrYn"
              [template]="template02_extrlLctrYn"
              headerText="외부강의여부"
              headerTextAlign="Center"
              textAlign="Center"
              width="130"
              *ngIf="saveParam.bztrpShpCd == '5'"
            >
              <ng-template #template02_extrlLctrYn let-data>
                <div class="input-wrap center w100">
                  <ejs-checkbox [checked]="grdD0102Data[data.index]?.extrlLctrYn == 'Y'" (change)="grdD0102Change($event, data.index, 'extrlLctrYn')"
                  [disabled]="this.saveParam.misApprvStatCd !== '01' || grdD0102Data[data.index]?.extrlLctrRqstNo"></ejs-checkbox>
                  <ng-container *ngIf="grdD0102Data[data.index]?.extrlLctrYn == 'Y' && saveParam.bztrpRqstNo && grdD0102Data[data.index]?.sn">
                  <!-- <ng-container *ngIf="extrlLctrDisabled"> -->
                    <ng-container *ngIf="grdD0102Data[data.index]?.extrlLctrRqstNo">
                      <button class="btn xx-small" (click)="fnEduPopup($event, data.index);">교육/자문신청 조회</button>
                    </ng-container>
                    <ng-container *ngIf="!grdD0102Data[data.index]?.extrlLctrRqstNo">
                      <button class="btn xx-small" (click)="fnEduPopup($event, data.index);">교육/자문신청 등록</button>
                    </ng-container>
                  </ng-container>
                </div>
              </ng-template>
            </e-column>
            
            <e-column
              field="bstaNm"
              [template]="template02_bstaNm"
              headerText="목적지(기관)&lt;em class='g-asterisk'&#47;&gt;"
              headerTextAlign="Center"
              [disableHtmlEncode]="false"
              textAlign="Left"
              width="100">
              <ng-template #template02_bstaNm let-data>
                <ejs-textbox
                  class="e-input e-small"
                  [value]="grdD0102Data[data.index]?.bstaNm"
                  (change)="grdD0102Change2($event, data.index, 'bstaNm')"
                  [enabled]="true">
                </ejs-textbox>
              </ng-template>
            </e-column>
            <e-column
              field="bztrpCntn"
              [template]="template02_bztrpCntn"
              headerText="출장내역&lt;em class='g-asterisk'&#47;&gt;"
              headerTextAlign="Center"
              [disableHtmlEncode]="false"
              textAlign="Left"
              width="150">
              <ng-template #template02_bztrpCntn let-data>
                <ejs-textbox
                    class="e-input e-small"
                    [value]="grdD0102Data[data.index]?.bztrpCntn"
                    (change)="grdD0102Change2($event, data.index, 'bztrpCntn')"
                    [enabled]="true">
                </ejs-textbox>
              </ng-template>
            </e-column>

            <e-column
              field="supptTrfcAmt"
              headerText="지원교통금액"
              headerTextAlign="Center"
              textAlign="Right"
              width="100"
              [template]="template02_supptTrfcAmt"
              *ngIf="saveParam.bztrpShpCd == '5'"
            >
            <ng-template #template02_supptTrfcAmt let-data>
              <ejs-numerictextbox
                *ngIf="grdD0102Data[data.index]?.crud_mode; else template02_supptTrfcAmt_view"
                class="e-input e-small right"
                format="N" [showSpinButton]="false"
                [value]="grdD0102Data[data.index]?.supptTrfcAmt"
                (change)="grdD0102Change($event.value, data.index, 'supptTrfcAmt')"
                [enabled]="false"
                >
                <!-- [enabled]="bscGrdInptItemEnabled" -->
              </ejs-numerictextbox>
              <ng-template #template02_supptTrfcAmt_view>
                {{ grdD0102Data[data.index]?.supptTrfcAmt | comCommaPipe }}
              </ng-template>
            </ng-template>
            </e-column>

            <e-column
              field="supptCpdAmt"
              headerText="지원일비금액"
              headerTextAlign="Center"
              textAlign="Right"
              width="100"
              [template]="template02_supptCpdAmt"
              *ngIf="saveParam.bztrpShpCd == '5'"
            >
            <ng-template #template02_supptCpdAmt let-data>
              <ejs-numerictextbox
                *ngIf="grdD0102Data[data.index]?.crud_mode; else template02_supptCpdAmt_view"
                class="e-input e-small right"
                format="N" [showSpinButton]="false"
                [value]="grdD0102Data[data.index]?.supptCpdAmt"
                (change)="grdD0102Change($event.value, data.index, 'supptCpdAmt')"
                [enabled]="false"
                >
                <!-- [enabled]="bscGrdInptItemEnabled" -->
              </ejs-numerictextbox>
              <ng-template #template02_supptCpdAmt_view>
                {{ grdD0102Data[data.index]?.supptCpdAmt | comCommaPipe }}
              </ng-template>
            </ng-template>
            </e-column>

            <e-column
              field="supptFoodEpnsAmt"
              headerText="지원식비금액"
              headerTextAlign="Center"
              textAlign="Right"
              width="100"
              [template]="template02_supptFoodEpnsAmt"
              *ngIf="saveParam.bztrpShpCd == '5'"
            >
            <ng-template #template02_supptFoodEpnsAmt let-data>
              <ejs-numerictextbox
                *ngIf="grdD0102Data[data.index]?.crud_mode; else template02_supptFoodEpnsAmt_view"
                class="e-input e-small right"
                format="N" [showSpinButton]="false"
                [value]="grdD0102Data[data.index]?.supptFoodEpnsAmt"
                (change)="grdD0102Change($event.value, data.index, 'supptFoodEpnsAmt')"
                [enabled]="false"
                >
              </ejs-numerictextbox>
              <ng-template #template02_supptFoodEpnsAmt_view>
                {{ grdD0102Data[data.index]?.supptFoodEpnsAmt | comCommaPipe }}
              </ng-template>
            </ng-template>
            </e-column>

            <e-column
              field="rmrkCntn"
              [template]="template02_rmrkCntn"
              headerText="비고"
              headerTextAlign="Center"
              textAlign="Left"
              width="300">
              <ng-template #template02_rmrkCntn let-data>
                <ejs-textbox
                    class="e-input e-small"
                    [value]="grdD0102Data[data.index]?.rmrkCntn"
                    (change)="grdD0102Change($event.value, data.index, 'rmrkCntn')"
                    [enabled]="true">
                </ejs-textbox>
              </ng-template>
            </e-column>
          </e-columns>
        </ejs-grid>
      </div>
      
      <div class="cont-box-inner">
        <div class="title">
          <h3>④ 여비산출내역(출장자내역)</h3>
          <div class="left-part" style="padding-top: 5px">
            <p class="red-txt">&nbsp;* 총 출장비 : &nbsp;{{saveParam.rqstAmt | comCommaPipe }}</p>
          </div>
        </div>

        <div class="tbl-wrap">
          <table class="tbl">
              <caption></caption>
              <colgroup>
                  <col style="width: 10%">
                  <col style="width: 10%">
                  <col style="width: 10%">
                  <col style="width: 10%">
                  <col style="width: 10%">
                  <col style="width: 10%">
                  <col style="width: 12%" *ngIf="saveParam.bztrpShpCd == '5'">
                  <col style="width: 10%">
                  <col style="width: 12%" *ngIf="saveParam.bztrpShpCd == '5'">
                  <col style="width: 10%">
                  <col style="width: 20%">
                  <col style="width: 12%" *ngIf="saveParam.bztrpShpCd == '5'">
                  <col style="width: 10%">
              </colgroup>
              <thead>
                  <tr>
                      <th scope="col">출장자</th>
                      <th scope="col">직원번호</th>
                      <th scope="col">직급</th>
                      <th scope="col">예금주</th>
                      <th scope="col">0원 출장여부</th>
                      <th scope="col">교통비</th>
                      <th scope="col" *ngIf="saveParam.bztrpShpCd == '5'">제외교통비금액</th>
                      <th scope="col">일비</th>
                      <th scope="col" *ngIf="saveParam.bztrpShpCd == '5'">제외일비금액</th>
                      <th scope="col">숙박비</th>
                      <th scope="col">식비</th>
                      <th scope="col" *ngIf="saveParam.bztrpShpCd == '5'">제외식비금액</th>
                      <th scope="col">총합계</th>
                  </tr>
              </thead>
              <tbody>
                  <tr>
                      <td>
                        {{grdD0101Data.bztrpEmpNm}}
                      </td>
                      <td>
                        {{grdD0101Data.bztrpEmpNo}}
                      </td>
                      <td>
                        {{grdD0101Data.bztrpGradNm}}
                      </td>
                      <td>
                        {{grdD0101Data.dpownNm}}
                      </td>
                      <td>
                        <app-checkbox
                          [value]="saveParam.bztrp0AmtYn"
                          (dataEmit)="bztrp0AmtYnChange($event)"
                          [disabled]="!bscInptItemEnabled">
                        </app-checkbox>
                      </td>
                      <td> 
                        <ejs-numerictextbox
                          class="e-input e-small right"
                          format="N" [showSpinButton]="false"
                          [value]="grdD0101Data?.trfcAmt"
                          (change)="grdD0101Change($event.value, 'trfcAmt')"
                          [enabled]="false"
                          >
                        </ejs-numerictextbox>
                      </td>
                      <td *ngIf="saveParam.bztrpShpCd == '5'">
                        <div class="input-wrap w80">
                          <ejs-numerictextbox
                            class="e-input e-small right"
                            format="N" [showSpinButton]="false"
                            [value]="grdD0101Data?.xcldTrfcAmt"
                            (change)="grdD0101Change($event.value, 'xcldTrfcAmt')"
                            [enabled]="false"
                            >
                          </ejs-numerictextbox>
                        </div>
                        <div class="input-wrap">
                          <button class="btn xx-small" (click)="fn_dialog('xTrfc')">?</button>
                        </div>
                      </td> <!--제외교통비-->
                      <td>
                        <div class="input-wrap w80">
                          <ejs-numerictextbox
                            class="e-input e-small right"
                            format="N" [showSpinButton]="false"
                            [value]="grdD0101Data?.atplTrfcAmt"
                            (change)="grdD0101Change($event.value, 'atplTrfcAmt')"
                            [enabled]="trfcCldvInptItemEnabled">
                          </ejs-numerictextbox>
                        </div>
                        <div class="input-wrap">
                          <button class="btn xx-small" (click)="fn_dialog('daily')">?</button>
                        </div>
                      </td> <!--일비-->
                      <td *ngIf="saveParam.bztrpShpCd == '5'">
                        <div class="input-wrap w80">
                          <ejs-numerictextbox
                            class="e-input e-small right"
                            format="N" [showSpinButton]="false"
                            [value]="grdD0101Data?.xcldCpdAmt"
                            (change)="grdD0101Change($event.value, 'xcldCpdAmt')"
                            [enabled]="false"
                            >
                          </ejs-numerictextbox>
                        </div>
                        <div class="input-wrap">
                          <button class="btn xx-small" (click)="fn_dialog('xCpd')">?</button>
                        </div>
                      </td> <!--제외일비-->
                      <td>
                        <ejs-numerictextbox
                          class="e-input e-small right"
                          format="N" [showSpinButton]="false"
                          [value]="grdD0101Data?.lodgAmt"
                          (change)="grdD0101Change($event.value, 'lodgAmt')"
                          [enabled]="false"
                          >
                        </ejs-numerictextbox>
                      </td> <!--숙박비-->
                      <td> 
                        <span class="input-wrap w100 flex">
                          <div class="input-wrap w30 flex">
                            <ejs-numerictextbox
                              class="e-input e-small right"
                              format="N" [showSpinButton]="false"
                              [min]="0"
                              [value]="grdD0101Data?.mealCnt"
                              (change)="grdD0101Change($event.value, 'mealCnt')"
                              [enabled]="false"
                              >
                            </ejs-numerictextbox>
                            <div style="margin:0px"></div>
                          </div>
                          <div class="input-wrap w70 flex" style="margin:0px;">
                            <ejs-numerictextbox
                              class="e-input e-small right"
                              format="N" [showSpinButton]="false" min="0"
                              [value]="grdD0101Data?.mealAmt"
                              (change)="grdD0101Change($event.value, 'mealAmt')"
                              >
                            </ejs-numerictextbox>
                            <div style="margin:0px;">
                              <button class="btn xx-small" style="margin:0px;margin-right:2px" (click)="fn_calMeal('+')">+</button>
                              <button class="btn xx-small" style="margin:0px;margin-right:2px" (click)="fn_calMeal('-')">-</button>
                            </div>
                            <div style="margin:0px;">
                              <button class="btn xx-small" (click)="fn_dialog('meal')">?</button>
                            </div>
                          </div>
                        </span>
                      </td> <!--식비-->
                      <td *ngIf="saveParam.bztrpShpCd == '5'">
                        <div class="input-wrap w80">
                          <ejs-numerictextbox
                            class="e-input e-small right"
                            format="N" [showSpinButton]="false"
                            [value]="grdD0101Data?.xcldChfdAmt"
                            (change)="grdD0101Change($event.value, 'xcldChfdAmt')"
                            [enabled]="false"
                            >
                          </ejs-numerictextbox>
                        </div>
                        <div class="input-wrap">
                          <button class="btn xx-small" (click)="fn_dialog('xChfd')">?</button>
                        </div>
                      </td> <!--제외식비--> 
                      <td class="right">{{ grdD0101Data?.totAmt | comCommaPipe }}</td> <!--총합계-->
                  </tr>
              </tbody>
          </table>
      </div>

      </div>

<app-toast-util (toastEmit)="toastEmit($event)"></app-toast-util>
import { ChangeDetectorRef, Component, Input, OnInit, Renderer2, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subject, takeUntil } from 'rxjs';
import { CommonUtil } from 'src/app/shared/utils/common-util';
import { PerUtil } from 'src/app/util/per/per-util';
import { PerEmpDialogComponent } from '../../dialog/per/per-emp-dialog.component';
import { CommonGridService } from './../../../kernel/service/common.grid.service';

import { MatDialog } from '@angular/material/dialog';

import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { GridComponent, PageSettingsModel } from '@syncfusion/ej2-angular-grids';
import { CommonApvService } from 'src/app/kernel/service/common.apv.service';
import { CommonDateService } from 'src/app/kernel/service/common.date.service';
import { CommonExcelService } from 'src/app/kernel/service/common.excel.service';
import { CommonHttpService } from 'src/app/kernel/service/common.http.service';
import { CommonMessageService } from 'src/app/kernel/service/common.message.service';
import { NeroComponent } from 'src/app/shared/component/nero/nero.component';
import { CommonMatDialogConfig } from 'src/app/shared/config/common-mat-dialog.config';
import { GridAddModel, GridDeleteModel, GridUpdateModel, GridViewModel } from 'src/app/shared/model/grid.model';
import { ComCommaPipe } from 'src/app/shared/pipe/com-comma.pipe';
import { ComDateTimePipe } from 'src/app/shared/pipe/com-date-time.pipe';
import { ComDatePipe } from 'src/app/shared/pipe/com-date.pipe';
import { ComHmsTimePipe } from 'src/app/shared/pipe/com-hms-time.pipe';
import { CommonDate } from 'src/app/shared/utils/common-date';
import { GafUtil } from 'src/app/util/gaf/gaf-util';
import message from 'src/assets/json/common.message.json';
import { BdgPrjEptmDialogComponent } from '../../dialog/bdg/bdg-prj-eptm-dialog.component';
import { GafAsetOutYnYComponent } from '../../dialog/gaf/gaf-aset-out-yn-y-dialog.component';
import { Gaf0708D01Data, Gaf0708D02Data, Gaf0708D03Data, Gaf0708Model } from './gaf0708.model';
import { Gaf070810Component } from './gaf070810.component';
import { Gaf070815Component } from './gaf070815.component';
import { Gaf0708dpComponent } from './gaf0708dp.component';
import { Gaf0708mComponent } from './gaf0708m.component';
import { Gaf0708m2Component } from './gaf0708m2.component';
/********************************************************************************
 * @author ysb
 * @since 
 * [시스템명]	경영정보
 * [업 무 명]	근태
 * [세부업무]	국내출장신청
 * [설    명] 국내출장신청 팝업을 구성하는 Typescript.
 ********************************************************************************/

@Component({
  selector: 'app-gaf0708',
  templateUrl: './gaf070801.component.html',
  styles: [
  ]
})
export class Gaf070801Component implements OnInit {

  @Input()
  pgmId = 'gaf0708';
  
  /** 저장 validation */
  saveValid = 'N';

  /** 업무구분코드 */
  busiDivCd = '';

  /** 정산여부 */
  fixYn = '';

  /** 조회용 Param */
  searchParam: any = new Object();

  /** 저장용 Param */
  saveParam: any = new Gaf0708Model();

  /** 여비산출내역 저장용 Param */
  grdD0101Data: any = new Object();

  /** 여비산출내역 GridComponent */
  // @ViewChild('grdD0101')
  // grdD0101: GridComponent | undefined;
  // grdD0101Height = 50;
  /** 여비산출내역 Array datagrid1 ac */
  // grdD0101Data: any | Object[] = [];

  /** 여행명세 GridComponent */
  @ViewChild('grdD0102')
  grdD0102: GridComponent | undefined;
  grdD0102Height = 100;
  /** 여행명세 Array datagrid2 ac2 */
  grdD0102Data: any [] = [];
  copyGrdD0102: any [] = [];
  copyLodgD0102: any [] = [];

  /** 출장내용 GridComponent */
  @ViewChild('grdD0103')
  grdD0103: GridComponent | undefined;
  grdD0103Height = 90;
  /** 출장내용 Array datagrid3 ac3 */
  // grdD0103Data:  Array<Gaf0708D03Data> = new Array<Gaf0708D03Data>();
  grdD0103Data: any | Object[] = [];

  /** 전자결재 직위 코드 변수 */
  gwpAdecPosiCd: any;

  //사용자 정보
  userInfo = CommonUtil.getLocalStorage('SESS_USER');             

  /** Grid 가상화 옵션 */
  isVirtualization = false;
  /** page 설정 */
  pageSettings: PageSettingsModel | undefined;
  /** 헤더 체크박스 제어 변수 */
  headerChkGrdD0103 = false;
  headerChkGrdD0101 = false;
  headerChkGrdD0102 = false;

  toastObj: any;
  adminChk: boolean = false;

  destroy: Subject<boolean> = new Subject<boolean>();

  perEmpDComponent = PerEmpDialogComponent;
  perEmpDWidth     = PerUtil.perEmpDWidth;
  perEmpDHeight    = PerUtil.perEmpDHeight;

  // 직원조회 다이얼로그
  empDComponent: any = PerEmpDialogComponent;
  empDWidth = PerUtil.perEmpDWidth; // 1200px
  empDHeight = PerUtil.perEmpDHeight; // 500px

  gafExtrDComponent = PerEmpDialogComponent;
  gafExtrDWidth = PerUtil.perEmpDWidth; // 1200px
  gafExtrDHeight =PerUtil.perEmpDHeight; // 500px

  /** 예산과제검색 다이얼로그 */
  bdgPrjDtlDComponent: any = BdgPrjEptmDialogComponent;
  bdgPrjDtlDWidth =PerUtil.perEmpDWidth; // 1200px
  bdgPrjDtlDHeight = PerUtil.perEmpDHeight; // 500px

  /** 자산 검색 다이얼로그 */
  astDComponent = PerEmpDialogComponent;
  astDWidth = PerUtil.perEmpDWidth; // 1200px
  astDHeight = PerUtil.perEmpDHeight; // 500px

  /* 공통코드 */
  /** 사업장코드 */
  BPLC_CD_LIST: any[] = [];
  /** 출장형태코드 */
  BTRP_SHP_CD_LIST: any[] = [];
  /** 교통구분코드 */
  TRFC_DIV_CD_LIST: any[] = [];
  /**  내부인여부 */
  IMN_YN_LIST: any[] = [{'nm':'내부인','cd':'Y'},{'nm':'외부인','cd':'N'}];
  /** 요금구분 */
  CHAE_DIV_CD_LIST: any[] = [];
  /** 대결지정여부 */
  RPRV_APNT_YN_LIST: any[] =[];
  //겸직겸무 부서콤보리스트
  cncPosComboList: any[] = [];  

  // 화면 및 프로세스 제어 변수

  /** 휴가 대결 지정 프로세스 사용 여부 */
  rprvApntMngrAuthYn = 'Y';

  /** 결재상신 버튼 제어 변수 */
  btnRqstDisabled = false;
  /** 저장 버튼 제어 변수 */
  btnSaveDisabled = false;
  /** 삭제 버튼 제어 변수 */
  btnDeleteDisabled = true;
  /** 담당자 취소 버튼 제어 변수 */
  btnCancelDisabled = true;
  /** 출장내용 grid 입력 제어 변수 itemEnableYn */
  grdItemEnabled = true;
  /** 기본 입력 항목 제어 변수 */
  bscInptItemEnabled = true;
  /** 기본 그리드 입력 항목 제어 변수 itemEnableDefault */
  bscGrdInptItemEnabled = true;
  /** 교통 구분별 입력 항목 제어 변수 itemRenderEnabledTRP_COLS */
  trfcCldvInptItemEnabled = true;
  /** 임원 숙박비 항목 제어 FLAG */
  extvLoadFlag : boolean = false;
  /** 외부강의여부 제어 변수 */
  extrlLctrDisabled = false;
  // asetDDisabled

  //파일관련
  @ViewChild("nero")
  nero?: NeroComponent;
  fileDivCd: string = 'gaf0708';

  //파일공통
  neroMode = NeroComponent.MODE_NEW;
  neroIds: string[] = [];
  post: any = new Object();

  totDay: number = 0; // 출장일수(외부인&출장일수3일 이상일 경우 식비 직접 수정가능 처리때문에 추가) 2022.07.11
  mealAmt: number = 0; // 식비(외부인&출장일수3일 이상일 경우 식비 직접 수정가능 처리때문에 추가) 2022.07.11
  // mealPay: number = 10000; // 하루 식비
  lodgAmt: number = 0;   // 총 숙박비 (출장기간 변경시 dialog에 있던 값을 불러오기 위해)

  //시내출장여부
  dwntBztrpVisible : boolean = false;

  tempTotAmt : number = 0;
  supptAmt = 0;   //출장지원비

  private unlistener!: (() => void);

  constructor(
    private dialog: MatDialog,
    private commonGridService: CommonGridService,
    private commonDateService: CommonDateService,
    private activatedRoute: ActivatedRoute,
    private commonHttpService: CommonHttpService,
    private commonMessageService: CommonMessageService,
    private commonExcelService: CommonExcelService,
    private renderer2: Renderer2,
    private comHmsTimePipe: ComHmsTimePipe,
    private comDatePipe: ComDatePipe,
    private comDateTimePipe: ComDateTimePipe,
    private comCommaPipe: ComCommaPipe,
    private commonApvService: CommonApvService,
    private cdr: ChangeDetectorRef,
  ) {
    this.activatedRoute.queryParams
      .pipe(takeUntil(this.destroy))
      .subscribe((params) => {
        //console.log(params);

        if(CommonUtil.isNotEmpty(params)) {
          const bztrpRqstNo = params["bztrpRqstNo"];
          if (CommonUtil.isNotEmpty(bztrpRqstNo)) {
            this.searchParam.bztrpRqstNo = bztrpRqstNo;
          }
        }

        this.initPopup();
      });
  }

  ngOnInit(): void {
    this.pageSettings = { pageSize: 50 };
    this.setAuth();
  }

  ngOnDestroy(): void {
    this.destroy.next(true);
    this.destroy.unsubscribe();
  }

  setAuth() {
    this.adminChk = CommonUtil.hasRole('000000','R00201');  // 권한여부
  }

  /*-----------------  Init Method Start  -----------------*/

  /**
   * param의 bztrpRqstNo 변경등의 대응을 위한 팝업 초기화
   *
   */
  initPopup(): void {
    // 출장현황조회에서 창을 호출했을 때
    if (this.pgmId === 'gaf0708') {
      this.changeBtnDisabled(); // 버튼 제어 불가능하게..
    }
    this.initCode();
  }


  /**
   * 공통코드 초기 설정
   * > 결재상태, 출장형태, 정산여부
   */
  sWrkAreaCd : object = [];
  sBztrpShpCd : object = [];
  sPrtbYn : object = [];
  sUseYn : object = [];
  sInthVecl : object = [{cd:'N', nm:'일반'},{cd:'Y', nm:'공용(동승)'}];      // 원내차량여부
  sTrfcMensCd : Object[] | any[] = [];  // 교통수단
  initCode(): void {
    const param = [ { comnGrpCd : 'WRK_AREA_CD' }    // 사업장
                  , { comnGrpCd : 'BZTRP_SHP_CD' }   // 출장형태
                  , { comnGrpCd : 'PRTB_YN' }        // 휴대여부
                  , { comnGrpCd : 'USE_YN' }         // 대결지정 - 사용여부
                  , { comnGrpCd : 'CHAE_DIV_CD' }    // 요금구분코드
                  , { comnGrpCd : 'TRFC_DIV_CD' }    // 교통구분코드
                  , { comnGrpCd : 'TRFC_MENS_CD' }   // 교통수단코드
                  ];        
    this.commonHttpService.getCode(param).subscribe({
      next: (response) => {
        if(CommonUtil.isNotEmpty(response)) {
          this.sWrkAreaCd = CommonUtil.addFirstCodeList('TEXT_ALL', response.WRK_AREA_CD);
          this.sBztrpShpCd = CommonUtil.addFirstCodeList('TEXT_SELECT', response.BZTRP_SHP_CD);
          this.sPrtbYn = CommonUtil.addFirstCodeList('TEXT_SELECT', response.PRTB_YN);
          this.sUseYn = response.USE_YN;
          this.sTrfcMensCd = response.TRFC_MENS_CD;
          this.CHAE_DIV_CD_LIST = response.CHAE_DIV_CD;
          this.TRFC_DIV_CD_LIST = response.TRFC_DIV_CD;
        }
      },
      error: () => {},
      complete: () => {
         //겸직겸무 부서콤보리스트
        //  this.commonApvService.getCncposCombo(null, this.toastObj, (state:boolean, response:any) => {
        //   if(state) {
        //     this.cncPosComboList = response;
        //   }
        // });
        // 공통코드 조회 후 조회
        if (CommonUtil.isNotEmpty(this.searchParam.bztrpRqstNo)) {
          this.getForm0101(); //출장신청 조회 (마스터)
        } else {
          this.initSaveParam();
        }
      }
    });

  }

  /**
   * 검색조건 초기 설정
   */
  initSaveParam(): void {

    this.saveParam = new Gaf0708Model();
    this.saveParam.rqstrEmpNo = this.userInfo.empNo;  //신청자사원번호
    this.saveParam.rqstrEmpNm = this.userInfo.name;  //신청자사원이름
    this.saveParam.rqstrDeptCd = this.userInfo.deptCd; //부서코드
    this.saveParam.rqstrDeptNm = this.userInfo.deptNm; //부서명

    //전자결재
    this.saveParam.misApprvStatNm = '작성중'; // 결재상태
    this.saveParam.misApprvStatCd = '01'; // 결재상태코드

    this.saveParam.bplcCd = this.userInfo.wrkAreaCd; // 사업장코드설정
    this.saveParam.rqstrGradNm = this.userInfo.gradNm; // 직급명설정(그룹웨어 결제문서에서 필요)
    this.saveParam.rqstrGradCd = this.userInfo.gradCd; // 직급명설정(그룹웨어 결제문서에서 필요)
    this.saveParam.rqstAmt = 0;

    this.saveParam.trfcMensCd = this.sTrfcMensCd[1].cd; // 교통수단

    //console.log(this.userInfo);
    // let param = {imnYn:'Y', sapvApntYn:'N'}
    
    this.grdD0101Data.imnYn = 'Y';
    this.grdD0101Data.sapvApntYn = 'N';

    // const obj: GridAddModel = {
    //   gridObj : this.grdD0101
    //   , gridData : this.grdD0101Data
    //   , position: 'bottom'
    //   , newData : param
    // }
    // this.commonGridService.gridAddRow(obj);

    this.getBstrInfo();

    // if(!this.adminChk) {
      this.fn_trexInfo();
    // }

  }

  /*-----------------  Init Method End  -----------------*/

  /*-----------------  Baclend Handler Start  -----------------*/

  // 신규 시 출장자 정보 조회
  getBstrInfo() {

    const param = { empNo : this.userInfo.empNo, hffcDivCd: '1' };
    this.commonHttpService.get('/per/dialog/getemplist.do', param).pipe(takeUntil(this.destroy)).subscribe({
      next: (response: any) => {
        const data = response.body?.[0];
        this.grdD0101Data.bztrpEmpNo = data?.empNo ?? '';
        this.grdD0101Data.bztrpEmpNm = data?.name ?? '';
        this.grdD0101Data.bztrpDeptCd = data?.deptCd ?? '';
        this.grdD0101Data.bztrpDeptNm = data?.deptNm ?? '';
        this.grdD0101Data.bztrpGradCd = data?.gradCd ?? '';
        this.grdD0101Data.bztrpGradNm = data?.gradNm ?? '';
        this.grdD0101Data.bstrPosiCd = data?.posiCd ?? '';
        this.grdD0101Data.bankCd = data?.bztrpBankCd ?? '';
        this.grdD0101Data.bactNo = data?.bztrpBactNo ?? '';
        this.grdD0101Data.dpownNm = data?.name ?? '';
        this.grdD0101Data.scpsGrdCd = data?.scpsGrdCd ?? '';  //신분등급코드
        this.grdD0101Data.trexGrdCd = data?.gradDivCd ?? '';  //여비등급

        if(CommonUtil.isNotEmpty(data?.posiCd)) {
          this.grdD0101Data.artckDivCd = data.posiCd === '10' ? '844-030' : '844-010';
        }
      },
      error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      },
      complete: () => {
        if (
          CommonUtil.isEmpty(this.grdD0101Data.bankCd) ||
          CommonUtil.isEmpty(this.grdD0101Data.bactNo) ||
          CommonUtil.isEmpty(this.grdD0101Data.dpownNm)
        ) {
          this.commonMessageService.showMsg(this.toastObj, { message : '경비계좌가 등록되어있지 않습니다. 급여관리자에게 문의하시기 바랍니다.', type : 'W' });  
        }
      }
    });
  }


  /**
   * 국내출장 마스터정보조회
   * @see doSearchTrp()
   */
  getForm0101(): void {
    this.commonHttpService
      .get('/gaf/gaf0708/getfrmr01.do', this.searchParam).pipe(takeUntil(this.destroy)).subscribe({
        next: (response : any) => {
          if (CommonUtil.isNotEmpty(response)) {
            console.log(response.body);
            this.saveParam = response.body;

            const gridMvGrid: GridViewModel = { 
              gridData: response.body.mvList,
            };
            const gridCntnGrid: GridViewModel = { 
              gridData: response.body.cntnList,
            };
            
            this.grdD0101Data = response.body.btrpEmpVo[0];  //출장자
            this.grdD0102Data = this.commonGridService.gridList(gridMvGrid);     //경유지
            this.grdD0103Data = this.commonGridService.gridList(gridCntnGrid);   //출장내용
            
            // 작성중일때 무조건 수정모드로 
            if(this.saveParam?.misApprvStatCd <= '01') {
              this.grdD0101Data.crud_mode = true;
            }

            this.copyGrdD0102 = JSON.parse(JSON.stringify(this.grdD0102Data)); //경유지 그리드 복사
            this.copyLodgD0102 = JSON.parse(JSON.stringify(this.grdD0102Data)); //경유지 숙박비 그리드 복사

            if(CommonUtil.isNotEmpty(this.grdD0102Data) && CommonUtil.isEmpty(this.grdD0101Data.totAmt)) {
              this.grdD0101Data.totAmt = this.tempTotAmt;
            }

            if(CommonUtil.isNotEmpty(this.grdD0102Data)) {
              // 시내출장 컬럼 visible -> 첫번째 행이 시내출장이며 그 다음행도 시내출장임 
              this.grdD0102Data[0].stpnCd == this.grdD0102Data[0].arpnCd ? this.dwntBztrpVisible = true : this.dwntBztrpVisible = false;
              
              // if('5' === this.saveParam.bztrpShpCd) {
              //   // 지원금액 합계
              //   this.grdD0102Data.forEach((item:any)=>{
              //     this.supptAmt += item.supptCpdAmt + item.supptFoodEpnsAmt + item.supptTrfcAmt;
              //   })
              // }
              // console.log("지원금 합계", this.supptAmt);
            }

          }
        },
        error: (error: any) => {
          this.commonMessageService.showSaveMsg(this.toastObj, error);
        },
        complete: () => {
          //this.resetFlag = false;
          //this.commonGridService.customResortingGridData(this.grdR01Data, this.grdR01, this.destroy);
        }
      })

  }

  /**
   * 저장
   *
   * @see doTrpRqstSave()
   * @param misApprvStatCd '
   */
  async saveForm0101(misApprvStatCd: string = '') {
    let confirmMsg = '';

     // TODO 검증하기
     //const validation = this.checkBeforeSave();

    //데이터 세팅
    this.saveParam.bztrpEmpVo = this.grdD0101Data;  //출장자
    this.saveParam.mvList = this.grdD0102Data;     //경유지
    this.saveParam.cntnList = this.grdD0103Data;   //출장내용
    this.saveParam.approvYn = misApprvStatCd;
    this.saveParam.dwntBztrpCd = this.dwntBztrpVisible ? '1' : '0';  // 시내출장여부 1:시내출장 0:전일출장

    if (misApprvStatCd === '01') {
      // 저장 처리일 때
      confirmMsg = message.com_info_save; // 저장 하시겠습니까?
      
    } else {
      // 외부강의 일 때 -> 교육신청 등록 해야함
      if(this.saveParam.bztrpShpCd == '5') {
        const cnt = this.grdD0102Data.filter((d) => d.extrlLctrYn === 'Y').length;
        if(cnt === 0) {
          this.commonMessageService.showMsg(this.toastObj, { message: "출장지역에서 하나 이상의 외부강의여부에 체크 해주시기 바랍니다.", type: 'W'});
          return;
        }
      }else {
        if(this.grdD0102Data.filter((f) => f.dwntBztrpCd === '1').length > 1) {  // 시내출장 행이 여러개
          this.commonMessageService.showMsg(this.toastObj, { message: "시내출장은 한 건만 등록할 수 있습니다", type: 'W'});
          return;
        }
      }

      
      // 대결지정 사용일 때 대리인 필수
      if(CommonUtil.isNotEmpty(this.grdD0101Data)) {
        if(this.grdD0101Data.sapvApntYn === 'Y') {
          if(CommonUtil.isEmpty(this.grdD0101Data.angtEmpNo)) {
            this.commonMessageService.showMsg(this.toastObj, { message : message.com_warn_need_data.replace('{0}','대결지정 사용일 때 대리인'), type : 'W', title : '경고알람' });
            return;
          }
          // const schema2 = {
          //   angtEmpNo: { title: '대리인', required: true },
          // };
          // const validation2 = this.commonGridService.gridValidation(this.grdD0101, this.grdD0101Data, this.toastObj, schema2);
          // if(!validation2) { return; }
        }
      }

      // 결재상신처리일 때
      // 저장하지 않았으면 결재상신 할 수 없음
      if(CommonUtil.isEmpty(this.saveParam.bztrpRqstNo)) {
        this.commonMessageService.showMsg(this.toastObj, { message: '저장 후 전자결재 요청 바랍니다.', type: 'W'});
        return;
      }
      
      // 외부강의 일 때 -> 교육신청 등록 해야함
      if(this.saveParam.bztrpShpCd == '5') {
        let validate = true;
        const extrlList = this.grdD0102Data.filter((item:any) => CommonUtil.isEmpty(item.extrlLctrRqstNo) && item.extrlLctrYn === 'Y');
        if(extrlList.length > 0) {
          this.commonMessageService.showMsg(this.toastObj, { message: "외부강의 출장은 반드시 교육/자문신청을 함께 해주시기 바랍니다.", type: 'W'});
          validate = false;
          return;
        }
        // this.grdD0102Data.forEach((d)=> {
        //   if(CommonUtil.isEmpty(d.extrlLctrRqstNo) && d.extrlLctrYn === 'Y') {
        //     this.commonMessageService.showMsg(this.toastObj, { message: "외부강의 출장은 반드시 교육/자문신청을 함께 해주시기 바랍니다.", type: 'W'});
        //     validate = false;
        //     return;
        //   }
        // })

        if(!validate) {return}
      }

      // 출장 기간에 주말이 포함되어 있을 경우 협조전 발송 팝업
      const bginDt = this.comDatePipe.transform(this.saveParam.bztrpBginDt);
      const endDt = this.comDatePipe.transform(this.saveParam.bztrpEndDt);

      const start = new Date(bginDt);
      const end = new Date(endDt);
      let temp = '';
      while(start <= end) {
        temp = start.toISOString().split('T')[0];
        start.setDate(start.getDate() + 1);
        if(new Date(temp).getDay() == 0 || new Date(temp).getDay() == 6) {
          alert('출장 기간에 주말이 포함된 경우 총무담당자에게 협조전을 발송하고 진행해야합니다.');
          break;
        }
      }

      confirmMsg = message.com_info_approv_submit; // 결재상신 하시겠습니까?
    }
    
    const isConfirm = confirm(confirmMsg);
    if (isConfirm) {
      this.tempTotAmt = this.grdD0101Data.totAmt;

      this.commonHttpService.post('/gaf/gaf0708/01/save.do', this.saveParam).pipe(takeUntil(this.destroy)).subscribe({
        next: (response:any) => {
          if (CommonUtil.isNotEmpty(response)) {
            const result = response.body.results;
            this.commonMessageService.showSaveMsg(this.toastObj, response);
            this.saveParam.bztrpRqstNo = result.bztrpRqstNo;
            this.searchParam.bztrpRqstNo = result.bztrpRqstNo;
            window.postMessage('save', location.origin);
          }
        },
        error: (error: any) => {
          this.commonMessageService.showSaveMsg(this.toastObj, error);
        },
        complete: () => {
          history.pushState(null, '', `${CommonUtil.getContextPath()}/#/popup/gaf/gaf070801?bztrpRqstNo=${this.saveParam.bztrpRqstNo}`);
          if(misApprvStatCd === '11') {
            this.commonApvService.apvDocView(this.saveParam.bztrpRqstNo);
          } else {
            this.getForm0101();
          }
        }
      });
    } 
  }

  /**
   * 출장신청서 삭제
   * @see doTrpDelete(flag:String)
   * @param crgrCnclYn
   */
  deleteform0101(crgrCnclYn: string = 'N'): void {
    if (CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo)) {
      
      let confirmMsg = message.com_info_delete;
      let isConfirm = false;
      if ('Y' === crgrCnclYn) {
        isConfirm = true;
      } else {
        isConfirm = confirm(confirmMsg);
      }
      if (isConfirm) {
        this.saveParam.crgrCnclYn = crgrCnclYn;

        // this.saveParam.AHFL_IDFN_ID = this.saveParam.bztrpRqstNo;
        // this.saveParam.FILE_DIV_CD = this.fileDivCd;

        this.commonHttpService
          .post('/gaf/gaf0708/01/delete.do', this.saveParam).pipe(takeUntil(this.destroy)).subscribe({
            next: (response: any) => {
              //this.commonMessageService.showSaveMsg(this.toastObj, response);
            },
            error: (error: any) => {
              this.commonMessageService.showSaveMsg(this.toastObj, error);
            },
            complete: () => {
              this.btnClose();
              window.postMessage('delete', location.origin);
            }
          });
      }
    }
  }

  /**
   * 직급별 여비 조회
   *
   * @see doGetJobGradAmt(value:String)
   * @see getJobGradeAmt(value:int)
   * @see fGetBkAcctCallBack(rtn:Object)
   */
  getGradClbTrex(): void {
    
    if (CommonUtil.isNotEmpty(this.grdD0101Data)) {
      /** 출장자 Data */
      const btrpEmpData: Gaf0708D01Data = this.grdD0101Data;

      if (CommonUtil.isNotEmpty(btrpEmpData)) {
        if (
          btrpEmpData.imnYn === 'Y' &&
          CommonUtil.isNotEmpty(btrpEmpData.bztrpEmpNo)
        ) {
          // 내부인일 때만 조회

          //서버보낼 파라미터
          const param = {
            totDdNum: this.saveParam.bztrpTotDdNum ?? 0,
            totLodgNum: this.saveParam.bztrpTotLodgNum ?? 0,
            gradCd: btrpEmpData.bztrpGradCd ?? '',
          };

          let gradClbTrex: any = new Object();

          this.commonHttpService
            .get('/gaf/com/getGradClbTrex.do', param)
            .pipe(takeUntil(this.destroy))
            .subscribe(
              (response) => {
                if (CommonUtil.isNotEmpty(response)) {
                  gradClbTrex = response;
                }
              },
              (error) => {},
              () => {
                // 0원 출장여부에 체크가 되어있으면 0원 처리
                if (this.saveParam.bztrp0AmtYn === 'Y') {
                  btrpEmpData.ddMealAmt = 0; // 일일식사금액
                  btrpEmpData.ddLodgAmt = 0; // 일일숙박금액
                  btrpEmpData.atplTrfcAmt = 0; // 현지교통금액
                  btrpEmpData.tmpAtplTrfcAmt = 0; // 임시현지교통금액
                  btrpEmpData.mealAmt = 0; // 식사금액
                  btrpEmpData.tmpMealAmt = 0; // 임시식사금액
                  btrpEmpData.lodgAmt = 0; // 숙박금액
                  btrpEmpData.tmpLodgAmt = 0; // 임시숙박금액
                  btrpEmpData.airAmt = 0; // 항공금액
                  if (CommonUtil.isEmpty(btrpEmpData.trfcAmt)) {
                    btrpEmpData.trfcAmt = 0; // 교통금액
                  }
                } else {
                  if (CommonUtil.isEmpty(btrpEmpData.trfcAmt)) {
                    btrpEmpData.trfcAmt = 0; // 교통금액
                  }
                  btrpEmpData.ddMealAmt = gradClbTrex.ddMealAmt; // 일일식사금액
                  btrpEmpData.ddLodgAmt = gradClbTrex.ddLodgAmt; // 일일숙박금액
                  btrpEmpData.atplTrfcAmt = gradClbTrex.atplTrfcAmt; // 현지교통금액
                  btrpEmpData.atplTrfcAmt = gradClbTrex.atplTrfcAmt; // 임시현지교통금액
                  btrpEmpData.mealAmt = gradClbTrex.mealAmt; // 식사금액
                  btrpEmpData.tmpMealAmt = gradClbTrex.mealAmt; // 임시식사금액
                  // btrpEmpData.LODG_AMT = gradClbTrex.LODG_AMT; // 숙박금액
                  // btrpEmpData.TMP_LODG_AMT = gradClbTrex.TMP_LODG_AMT; // 임시숙박금액

                  // ---------------------기존 정액지급에서 사후 실비정산 시 숙박비 한도 값 변경--------------------------------------------

                  /**
                   * GafUtil.toInteger의 경우 null이나 nan을 0으로 다 치환해버림
                   */
                  let lodgAmt = 0;
                  if (
                    GafUtil.toInteger(this.saveParam.bztrpTotLodgNum) !== 0
                  ) {
                    /** 임원숙박수 */
                    const extvLodgNum = GafUtil.toInteger(
                      this.saveParam.exctvLodgNum
                    );
                    if (extvLodgNum !== 0) {
                      lodgAmt += extvLodgNum * GafUtil.CONST_EXTV_LODG_AMT;
                    }

                    /** 서울숙박수 */
                    const seulLodgNum = GafUtil.toInteger(
                      this.saveParam.seulLodgNum
                    );
                    if (seulLodgNum !== 0) {
                      lodgAmt += seulLodgNum * GafUtil.CONST_SEUL_LODG_AMT;
                    }

                    /** 광역숙박수 */
                    const wdarLodgNum = GafUtil.toInteger(
                      this.saveParam.wdarLodgNum
                    );
                    if (wdarLodgNum !== 0) {
                      lodgAmt += wdarLodgNum * GafUtil.CONST_WDAR_LODG_AMT;
                    }

                    /** 기타지역숙박수 */
                    const etcAreaLodgNum = GafUtil.toInteger(
                      this.saveParam.etcAreaLodgNum
                    );
                    if (etcAreaLodgNum !== 0) {
                      lodgAmt +=
                        etcAreaLodgNum * GafUtil.CONST_ETC_AREA_LODG_AMT;
                    }

                    /** 친척숙박수 */
                    const rltvLodgNum = GafUtil.toInteger(
                      this.saveParam.cusnLodgNum
                    );
                    if (rltvLodgNum !== 0) {
                      lodgAmt += rltvLodgNum * GafUtil.CONST_RLTV_LODG_AMT;
                    }

                    /** 공동숙박수 */
                    const colbLodgNum = GafUtil.toInteger(
                      this.saveParam.colbLodgNum
                    );
                    if (colbLodgNum !== 0) {
                      lodgAmt += colbLodgNum * GafUtil.CONST_COLB_LODG_AMT;
                    }
                  }

                  btrpEmpData.lodgAmt = lodgAmt; // 숙박금액
                  btrpEmpData.tmpLodgAmt = lodgAmt; // 임시숙박금액

                  // ------------------------------------------------------------------------------------------------------
                  if (this.saveParam.trfcMensCd === '7') {
                    btrpEmpData.atplTrfcAmt = this.saveParam.bztrpTotDdNum * GafUtil.CONST_INTH_VECL_AMT; // 현지교통금액
                    btrpEmpData.tmpAtplTrfcAmt = this.saveParam.bztrpTotDdNum * GafUtil.CONST_INTH_VECL_AMT; // ; // 임시현지교통금액
                  }
                }
                // 출장비의 총합계를 구하고 총 출장비, 총 운영비흡수액, 총 개인지급액을 셋팅
                // 총합계(교통비 + 현지교통비 + 일비 + 숙박비 + 식비)
                this.calcTotAmt();

                if (CommonUtil.isNotEmpty(btrpEmpData)) {
                  // 지급계좌정보 가져오기 PAY-002-002 : 수당계좌

                  // GetBkAcct("313-002",selectedRow.TRP_ID,"","PAY-002-002","",fGetBkAcctCallBack);
                  const param0104 = {
                    SPPE_DIV_CD: '313-002',
                    PARAM_CD: btrpEmpData.bztrpEmpNo,
                    EXPS_PRVD_DIV_CD: 'PAY-002-002',
                  };

                  let acctInfo: any = new Object();

                  this.commonHttpService
                    .get('/com/com0104/getBnkBactNoMap01', param0104)
                    .subscribe(
                      (response) => {
                        acctInfo = response;
                      },
                      (error) => {},
                      () => {
                        if (
                          CommonUtil.isEmpty(acctInfo.BNK_CD) ||
                          CommonUtil.isEmpty(acctInfo.BACT_NO) ||
                          CommonUtil.isEmpty(acctInfo.DPWN_NM)
                        ) {
                          this.commonMessageService.showMsg(this.toastObj, {message:'경비계좌가 등록되어있지 않습니다. 급여관리자에게 문의하시기 바랍니다.', type:'W' });
                          

                          /**
                           * AS-IS에서는 해당 데이터만 삭제하였으나
                           * 출장자는 1명 한정이므로 여행명세와 여비산출내역(출장자) 둘다 초기화
                           *
                           */
                          // this.grdD0102Data = [];
                          // this.grdD0101Data = [];

                          // const obj : GridAddModel = {
                          //   gridObj : this.grdD0101
                          // , gridData : this.grdD0101Data
                          // }
                          // this.commonGridService.gridAddRow(obj);

                        } else {
                          btrpEmpData.bnkCd = acctInfo.BNK_CD; // 은행코드
                          btrpEmpData.backNo = acctInfo.BACT_NO; // 계좌번호
                          btrpEmpData.dpwnNm = acctInfo.DPWN_NM; // 예금주
                        }
                      }
                    );
                }
              }
            );
        }
      }
    }
  }

  /**
   * 부재자 체크
   *
   * @see allAbsenteeCheck(trpId:String)
   * @see allGetAbstChk(value:int)
   * @see doAbsenteeCheck(value:int)
   * @param noticeYn
   */
  getAbntAbleYn(noticeYn: string = 'N'): void {

    let abntAbleYn = 'Y';

    /** 출장자 Data */
    const btrpEmpData: Gaf0708D01Data = this.grdD0101Data;
    if (CommonUtil.isNotEmpty(btrpEmpData)) {
        // 내부인만 부재자 체크 진행
        const param = {
          empNo: btrpEmpData.bztrpEmpNo,
          bginDt: this.saveParam.bztrpBginDt,
          endDt: this.saveParam.bztrpEndDt
        };

        this.commonHttpService.get('/gaf/com/getabntableyn', param).pipe(takeUntil(this.destroy)).subscribe({
          next: (response: any) => {
            // Y:부재자아님 N:부재자
            abntAbleYn = response.body.abntAbleYn;
          },
          error: (error: any) => {
            this.commonMessageService.showSaveMsg(this.toastObj, error);
          },
          complete: () => {
            if (CommonUtil.isNotEmpty(abntAbleYn) && abntAbleYn !== 'Y') {
              CommonUtil.commonMsg(
                this.toastObj,
                '해당 직원은 설정된 출장기간에 ['+abntAbleYn+'](으)로 등재되어 있습니다.',
                'W'
              );

              /**
               * AS-IS에서는 해당 데이터만 삭제하였으나
               * 출장자는 1명 한정이므로 여행명세와 여비산출내역(출장자) 둘다 초기화
               *
               */
              // this.grdD0102Data = [];
              // this.grdD0101Data = [];
              // CommonUtil.commonGridAddRow(
              //   this.grdD0101,
              //   this.grdD0101Data,
              //   new Gaf0708D01Data()
              // );

              this.calcTotAmt(); // 삭제하고난뒤 출장비 다시 계산
            }
          }
        });
    }
  }

  /*-----------------  Baclend Handler End  -----------------*/

  /*-----------------  Data Handler Start  -----------------*/

  /**
   * 일반 saveParam 값 변경 처리
   *
   * @param value
   * @param property
   */
  commonSaveParamChange(value: any, property: string): void {
    this.saveParam[property] = value;
  }

  /**
   * 날짜 변경 처리
   * - 출장정보 출장기간 validation
   *
   * @see doDayBagil('form')
   * @param value
   * @param property
   */
  dateSaveParamChange(value: any, property: string): void {

    this.commonSaveParamChange(value, property);

    if (property === 'bztrpBginDt' || property === 'bztrpEndDt') {
      // 출장기간 변경의 경우
      // 숙박비 수정 (1박이 넘어갈 경우)
      let bgnDt: string = this.saveParam.bztrpBginDt;
      let endDt: string = this.saveParam.bztrpEndDt;

      if (CommonUtil.isNotEmpty(bgnDt) && CommonUtil.isEmpty(endDt)) {
        endDt = bgnDt;
        this.commonSaveParamChange(bgnDt, 'bztrpEndDt');
      }
      if (CommonUtil.isNotEmpty(endDt) && CommonUtil.isEmpty(bgnDt)) {
        bgnDt = endDt;
        this.commonSaveParamChange(endDt, 'bztrpBginDt');
      }


      // 검증 처리 후 데이터 최신화
      bgnDt = this.saveParam.bztrpBginDt;
      endDt = this.saveParam.bztrpEndDt;

      const bgnDate: Date = new Date(CommonDate.getFormattedDate(bgnDt)); // 시작일 Date 객체
      const endDate: Date = new Date(CommonDate.getFormattedDate(endDt)); // 종료일 Date 객체

      const oneDay: number = 1000 * 60 * 60 * 24;

      const bztrpTotDdNum: number =
        (endDate.getTime() - bgnDate.getTime() + oneDay) / oneDay;
      this.totDay = bztrpTotDdNum; // 외부인&출장일수3일 이상일 경우 식비 직접 수정 처리때문에 추가 2022.07.11
      const bztrpTotLodgNum: number = bztrpTotDdNum - 1;

      // this.saveParam.bztrpTotLodgNum = bztrpTotLodgNum;
      this.commonSaveParamChange(bztrpTotLodgNum, 'bztrpTotLodgNum');
      this.saveParam.bztrpTotDdNum = bztrpTotDdNum;

      // 출장일수가 1박이 넘을 경우 -> 하루여도 숙박가능
      // if(bztrpTotDdNum > 1) {
      //   this.grdD0101Data.lodgAmt = this.lodgAmt;
      // }else {
      //   this.grdD0101Data.lodgAmt = 0;
      // }


      //식비 set 
      //하루3끼로 고정 but 시내출장이면 안줌
      this.calDdMealAmt();  // 하루 식비 계산
      // this.grdD0101Data.mealCnt = this.saveParam.bztrpTotDdNum*3;
      // this.grdD0101Data.mealAmt = this.saveParam.bztrpTotDdNum*3*GafUtil.MEAL_PAY;

      if(CommonUtil.isNotEmpty(this.grdD0102Data)) {
        this.grdD0102Data.forEach((d) => {
          if(d.stpnCd == d.arpnCd) {
            this.grdD0101Data.mealCnt = 0;
            this.grdD0101Data.mealAmt = 0;
          }
        })
      }

      //일비 계산
      //일반 , 공용
      //this.calAtplTrfcAmtAll();   // 이제 행별로 더하니까 굳이 마스터 출장기간이 변경되었다고 일비를 계산할 필요가 없다.

      //this.getGradClbTrex();  //직급별 여비조회

      // 출장기간이 변경되면 출장그리드에 있는 모든출장자들의 부재자 내역을 다시 확인
      // allAbsenteeCheck("TRP_ID");
      this.getAbntAbleYn('N');
      // 출장비의 총합계를 구하고 총 출장비, 총 운영비흡수액, 총 개인지급액을 셋팅
      // doTotalAmtValue();
      this.calcTotAmt();
    }
  }

  // 일비 계산
  calAtplTrfcAmt(index:any) {
    let amt = 0;

    // 공용여부
    // const trfcMensCd = this.saveParam.trfcMensCd;
    const trfcMensCd = this.grdD0102Data[index].trfcMensCd;

    // 출장기간(일)
    // const bztrpTotDdNum = this.saveParam.bztrpTotDdNum;
    const bztrpTotDdNum = this.fnCalDate(index);

    // 경유지 확인 (시내, 시외)
    // 시내일 경우 시간계산
    const stpnCd = this.grdD0102Data[index].stpnCd;  //출발지
    const arpnCd = this.grdD0102Data[index].arpnCd;  //도착지

    if(CommonUtil.isNotEmpty(this.grdD0102Data)) {
      if(trfcMensCd == '7') { // 공용

        if(stpnCd != arpnCd) {
          amt = GafUtil.OUT_COMMON * Number(bztrpTotDdNum);   //12500
        }else {
          amt = 0;
        }

        // 20250308 교통수단수정
        // this.grdD0102Data.forEach((d) => {
        //   if(d.stpnCd != d.arpnCd) {
        //     amt = GafUtil.OUT_COMMON * Number(bztrpTotDdNum);   //12500
        //   }else {
        //     amt = 0;
        //   }
        // })

      }else { // 일반

        // 20250308 교통수단 수정
        // this.grdD0102Data.forEach((d) => {
          if(stpnCd != arpnCd) {
            amt = GafUtil.OUT_NORMAL * Number(bztrpTotDdNum);   //25000
          }else { // 시내출장
            //시간계산
            const time = this.fn_calTime();
            if(time < 4) {
              amt = GafUtil.IN_NORMAL_LESS * Number(bztrpTotDdNum);  //10000
            }else {
              amt = GafUtil.IN_NORMAL_MORE * Number(bztrpTotDdNum);  //20000
            }
            
            // 20250305
            // if(this.grdD0102Data.length === 1 && d.extrlLctrYn === 'Y') {
            //   amt = 0;
            // }

            // if(this.saveParam.bztrpShpCd === '5') {  // 외부강의
            //   amt = 0;
            // }
          }
        // })
      }
    }else {
      amt = 0;
    }
    
    console.log("일비계산", amt);
    this.grdD0101Data.atplTrfcAmt = GafUtil.toInteger(this.grdD0101Data.atplTrfcAmt) + GafUtil.toInteger(amt);
    console.log("최종일비계산", this.grdD0101Data.atplTrfcAmt);
  }

   // 전체일비 계산
   calAtplTrfcAmtAll() {
    let amt = 0;

    for(let index = 0; index <this.grdD0102Data.length; index++) {

      // 공용여부
      // const trfcMensCd = this.saveParam.trfcMensCd;
      const trfcMensCd = this.grdD0102Data[index].trfcMensCd;
  
      // 출장기간(일)
      // const bztrpTotDdNum = this.saveParam.bztrpTotDdNum;
      const bztrpTotDdNum = this.fnCalDate(index);
  
      // 경유지 확인 (시내, 시외)
      // 시내일 경우 시간계산
      const stpnCd = this.grdD0102Data[index].stpnCd;  //출발지
      const arpnCd = this.grdD0102Data[index].arpnCd;  //도착지
  
      if(CommonUtil.isNotEmpty(this.grdD0102Data)) {
        if(trfcMensCd == '7') { // 공용
  
          if(stpnCd != arpnCd) {
            amt = GafUtil.OUT_COMMON * Number(bztrpTotDdNum);   //12500
          }else {
            amt = 0;
          }
  
          // 20250308 교통수단수정
          // this.grdD0102Data.forEach((d) => {
          //   if(d.stpnCd != d.arpnCd) {
          //     amt = GafUtil.OUT_COMMON * Number(bztrpTotDdNum);   //12500
          //   }else {
          //     amt = 0;
          //   }
          // })
  
        }else { // 일반
  
          // 20250308 교통수단 수정
          // this.grdD0102Data.forEach((d) => {
            if(stpnCd != arpnCd) {
              amt = GafUtil.OUT_NORMAL * Number(bztrpTotDdNum);   //25000
            }else { // 시내출장
              //시간계산
              const time = this.fn_calTime();
              if(time < 4) {
                amt = GafUtil.IN_NORMAL_LESS * Number(bztrpTotDdNum);  //10000
              }else {
                amt = GafUtil.IN_NORMAL_MORE * Number(bztrpTotDdNum);  //20000
              }
              
              // 20250305
              // if(this.grdD0102Data.length === 1 && d.extrlLctrYn === 'Y') {
              //   amt = 0;
              // }
  
              // if(this.saveParam.bztrpShpCd === '5') {  // 외부강의
              //   amt = 0;
              // }
            }
          // })
        }
      }else {
        amt = 0;
      }
      this.grdD0101Data.atplTrfcAmt = GafUtil.toInteger(this.grdD0101Data.atplTrfcAmt) + GafUtil.toInteger(amt);
    }
    
  }

  /**
   * 출장박수 변경 이벤트 처리
   */
  bztrpTotLodgNumChange(event: any): void {
    let value = event.value;
    const bztrpTotDdNum = this.saveParam.bztrpTotDdNum;
    value = Math.floor(value);

    if(value > bztrpTotDdNum) {
      this.saveParam.bztrpTotLodgNum = bztrpTotDdNum - 1;
      this.commonMessageService.showMsg(this.toastObj, { message : '출장일수를 확인해주세요.', type : 'W', title : '경고 알람' });
    }else {
      this.saveParam.bztrpTotLodgNum = value;
    }
    this.calcTotAmt();
  }

  /**
   * dropdownlist saveParam 값 변경 처리
   *
   * @param event
   * @param property
   */
  dropdownSaveParamChange(event: any, property: string): void {
    //if (CommonUtil.isNotEmpty(event.previousItemData)) {
      // this.commonSaveParamChange(event.value, property);
      this.saveParam[property] = event.value;
    //}
    
    if(property === 'bztrpShpCd') {
      // 외부강의가 아닐경우 체크 해제 -> 기존 교육신청, 외부강의 여부 삭제 필요
      if(event.value !== '5') {
        this.grdD0102Data = JSON.parse(JSON.stringify(this.copyLodgD0102)); //숙박비그리드 복사
        this.grdD0102Data.forEach((d) => {
          d.extrlLctrYn = 'N';   // 외부강의 여부
        })
      } else {  // 외부강의 선택시
        this.grdD0102Data.forEach((d) => {
          if(CommonUtil.isNotEmpty(d.extrlLctrRqstNo)) { // 외부강의 pk가 있으면 외부강의 여부 Y로
            d.extrlLctrYn = 'Y';   // 외부강의 여부
          }
        })
      }
    }

  }

  /** 교육신청 팝업 */
  fnEduPopup(args: any, index: number) {

    let obj;
    
    obj = {
      url: '/popup/edu/edu050101',
      param: { lnkCd: '2', rqstNo: this.grdD0102Data[index].extrlLctrRqstNo 
              , lnkDcmtNo: this.saveParam.bztrpRqstNo , lnkDcmtSn: this.grdD0102Data[index].sn},   //구분값 1휴가,2출장
      width: 1300,
      height: 800,
      target: 'edu050101_new',
    };

    let crud = '';
    if(CommonUtil.isEmpty(this.grdD0102Data[index].extrlLctrRqstNo)) {
      crud = 'C';
    }

    const popup = CommonUtil.openWindowPopup(obj);

    if(popup) {
      this.unlistener = this.renderer2.listen(popup, 'message', (e) => {
        if (e.origin === location.origin && CommonUtil.isNotEmpty(e.data.eduSave)) {   // 교육pk 리턴
          // TODO 출장 테이블에 교육pk update 해주기
          const extrlLctrRqstNo = e.data.eduSave;
          this.grdD0102Data[index].extrlLctrRqstNo = extrlLctrRqstNo;
          const param = {extrlLctrRqstNo:extrlLctrRqstNo, sn: this.grdD0102Data[index].sn, bztrpRqstNo:this.saveParam.bztrpRqstNo, extrlLctrYn:this.grdD0102Data[index].extrlLctrYn};
          this.fnEduUpdate(param);
          if(crud != 'C') {
            this.fnGetMvList();  // 외부강의 저장후 지원금액 차감
          }
          
        } else if(e.origin === location.origin && e.data === 'delete') {
          this.commonMessageService.showMsg(this.toastObj, { message: message.com_succ_delete});
          this.grdD0102Data[index].extrlLctrRqstNo = '';
          const param = {extrlLctrRqstNo:this.grdD0102Data[index].extrlLctrRqstNo, sn: this.grdD0102Data[index].sn, bztrpRqstNo:this.saveParam.bztrpRqstNo, extrlLctrYn:'N'};
          this.fnEduUpdate(param);
        }
      });
    }
  }

  // 외부강의 저장후 지원금액 불러오기 위한 함수
  fnGetMvList() {
    this.commonHttpService.get('/gaf/gaf0708/01/getmvlist.do', this.searchParam).pipe(takeUntil(this.destroy)).subscribe({
      next: (response:any) => {
        const list = response.body;
        const grdList: GridViewModel = { 
          gridData: list,
        };
        this.grdD0102Data = this.commonGridService.gridList(grdList);  // 경유지 목록 리로딩
        console.log(this.grdD0102Data);
        let spptTrfc = 0;  // 지원교통비
        let spptMeal = 0;  // 지원식비
        let spptDd = 0;    // 지원일비
        const grdD0101Data = this.grdD0101Data;
        const nowMealAmt = grdD0101Data.mealAmt + grdD0101Data?.xcldChfdAmt ?? 0; // 식비 - 기존제외식비 =  현재 제외가능한 금액
        const nowAtplAmt = grdD0101Data.atplTrfcAmt + grdD0101Data?.xcldCpdAmt ?? 0; // 일비 - 기존제외일비 =  현재 제외가능한 금액
    
        list.forEach((item:any)=>{
          // 한 행의 지원 교통비가 전체 교통비보다 많으면 그냥 전체 교통비만큼만 제외하는거
          // 마이너스 처리는 안함!
          if(item.supptTrfcAmt > item.trfcAmt) {
            spptTrfc += GafUtil.toInteger(item.trfcAmt);
          }else {
            spptTrfc += GafUtil.toInteger(item.supptTrfcAmt);
          }
    
          // 한 행의 지원 식비가 하루 최대식비(30000원) 보다 많으면 그냥 하루 최대 식비만큼만
          // 마이너스 처리는 안함!
          let tempMealAmt = 0;
          if(item.supptFoodEpnsAmt > GafUtil.MEAL_PAY*3) { 
            tempMealAmt = GafUtil.toInteger(GafUtil.MEAL_PAY*3);
          }else {
            tempMealAmt = GafUtil.toInteger(item.supptFoodEpnsAmt);
          }
          if(nowMealAmt < tempMealAmt) {
            spptMeal += nowMealAmt;
          }else {
            spptMeal += tempMealAmt;
          }

          
          // 일비 최대 25000원까지 지원가능
          // 마이너스 처리는 안함!
          let tempCpdAmt = 0;
          if(item.supptCpdAmt > GafUtil.OUT_NORMAL) {
            tempCpdAmt = GafUtil.toInteger(GafUtil.OUT_NORMAL);
          }else {
            tempCpdAmt = GafUtil.toInteger(item.supptCpdAmt);
          }
          if(nowAtplAmt < tempCpdAmt) {
            spptDd += nowAtplAmt;
          }else {
            spptDd += tempCpdAmt;
          }

        })
    
        grdD0101Data.xcldTrfcAmt = -spptTrfc;
        grdD0101Data.xcldCpdAmt = -spptDd;
        grdD0101Data.xcldChfdAmt = -spptMeal;
  
        console.log(spptTrfc, spptMeal, spptDd);
        console.log('결과',this.grdD0101Data);
        
        this.calcTotAmt();  // 출장자내역 합계 계산
        this.fnXcldUpdate(grdD0101Data);  // 제외금액 저장
      }
      ,error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      }
    })
  }

  /* 제외금액 저장 */
  fnXcldUpdate(param:any) {
    this.commonHttpService.post('/gaf/gaf0708/01/updatebztrpxcld.do', param).pipe(takeUntil(this.destroy)).subscribe({
      next: (response:any) => {
        //this.commonMessageService.showSaveMsg(this.toastObj, response);
      }
      ,error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      }
      ,complete: () => {
        
      }
    })
  }

  /** 외부강의 pk 저장 */
  fnEduUpdate(param:any) {

    this.commonHttpService.post('/gaf/gaf0708/01/updateExtrlNo.do', param).pipe(takeUntil(this.destroy)).subscribe({
      next: (response:any) => {
        //this.commonMessageService.showSaveMsg(this.toastObj, response);
        this.fnGetMvList();  // 외부강의 저장후 지원금액 차감
      }
      ,error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      }
    })

  }

  /**
   * 다이얼로그 검색 콜백 이벤트 처리
   * @param event
   * @param property
   */
  dialogSaveParamChange(event: any, property: string): void {
    let param: any = {};

    if ('empNo' === property) {
      // 신청자 검색
      param = {
        empNo: event?.empNo ?? '',
        EMP_NM: event?.NAME ?? '',
        DEPT_CD: event?.DEPT_CD ?? '',
        DEPT_NM: event?.DEPT_NM ?? '',
        GRAD_CD: event?.GRAD_CD ?? '',
        GRAD_NM: event?.GRAD_NM ?? '',
      };

      if (CommonUtil.isEmpty(param.empNo)) {
        Object.keys(param).forEach((key) => {
          param[key] = '';
        });
      }
    } else if ('bdgCd' === property) {
      // 예산과목 검색
      //console.log("예산",event);
      if(CommonUtil.isNotEmpty(event)) {
        // 첫번째 항목이 예산과목
        this.saveParam.bdgCd = event[0].bdgCd; // 예산코드
        this.saveParam.bdgNm = event[0].bdgNm; // 예산명
        this.saveParam.bdgRspsrEmpNo = event[0].rspsrEmpNo;   //예산책임자
        this.saveParam.bdgDeptCd = event[0].supvDeptCd;       //예산부서코드
        this.saveParam.bizEndDt = event[0].endDt;       //사업종료일자

        // 두번째 항목이 비용항목
        this.saveParam.eptmCd = event[1].eptmCd; // 비목코드
        this.saveParam.eptmNm = event[1].eptmNm; // 비목명
        this.saveParam.acctCd = event[1].acctCd; // 계정코드
        this.saveParam.bdgLmitAmt = event[1].blncAmt;  //예산한도금액 잔액
      }

      param = {
        bdgCd: event?.bdgCd ?? '', // 예산코드
        bdgNm: event?.bdgNm ?? '', // 예산명
        eptmCd: event?.eptmCd ?? '', // 비목코드
        eptmNm: event?.eptmNm ?? '', // 비목명
        execdiv: event?.execdiv ?? '', // 이지바로 집행구분
        exenmiv: event?.exenmiv ?? '', // 이지바로 집행구분
        bdgRspnr_emp_no: event?.rspnrEmpNo ?? '', // 예산책임자직원번호
        bdgRspnr_emp_nm: event?.rspnrEmpNm ?? '', // 예산책임자직원번호
        bizEnd_dt: event?.bizEndDt ?? '', // 사업종료일자
        rcmsYn: event?.rcmsYn ?? '', // rcms 과제 여부
      };

      if (CommonUtil.isEmpty(param.bdgCd)) {
        Object.keys(param).forEach((key) => {
          param[key] = '';
        });
      } else {
        // RCMS 과제 여부 체크
        if (param.rcmsYn === 'Y') {
          // RCMS 과제 dialog open
          alert('해당예산은 RCMS 과제입니다.');
        }
      }
    } 

    this.commonSaveParamChange(param, '');
  }

  /**
   * 0원 출장 체크박스 클릭
   *
   * - 별도항목 설정하여 일괄 적용 가능토록 요청(원차량 이용과 동일)
   *
   * @see doZeroChk()
   * @param value
   */
  bztrp0AmtYnChange(value: any): void {
    this.commonSaveParamChange(value, 'bztrp0AmtYn');

    /** 출장자 Data */
    const bztrpEmpData = this.grdD0101Data;

    if (CommonUtil.isNotEmpty(bztrpEmpData)) {
      if (value === 'Y') {
        // 여비를 모두 0원처리 한다.

        bztrpEmpData.trfcAmt = 0; // 교통금액
        bztrpEmpData.tmpAtplTrfcAmt = 0; // 임시현지교통금액
        bztrpEmpData.airAmt = 0; // 항공금액
        bztrpEmpData.atplTrfcAmt = 0; // 현지교통금액
        bztrpEmpData.tmpLodgAmt = 0; // 임시숙박금액
        bztrpEmpData.lodgAmt = 0; // 숙박금액
        bztrpEmpData.tmpMealAmt = 0; // 임시식사금액
        bztrpEmpData.mealAmt = 0; // 식사금액
        bztrpEmpData.totAmt = 0; // 총합계금액
        bztrpEmpData.persProvdAmt = 0;
        bztrpEmpData.ddMealAmt = 0; // 일일식사금액
        bztrpEmpData.ddLodgAmt = 0; // 일일숙박금액
        bztrpEmpData.mealCnt = 0;   // n식
      
        // 여행명세 요금을 0원처리 한다.

        if (CommonUtil.isNotEmpty(this.grdD0102Data)) {
          for (let index = 0; index < this.grdD0102Data.length; index++) {
            this.grdD0102Data[index].trfcAmt = 0;
            this.grdD0102Data[index].rmchrAmt = 0;
            //this.grdD0102Data[index].lodgDdNum = 0;   //숙박일수  -> 0원 출장이여도 숙박을 할 수 도 있음.
          }
        }
      } else {

        // 식비
        this.calDdMealAmt();  // 하루 식비계산

        //this.getGradClbTrex(); // 직급별 여비가져오기

        // 여행명세(경유지) 원복
        //this.grdD0102Data = JSON.parse(JSON

        for (let index = 0; index < this.copyLodgD0102.length; index++) {
          const rmchrAmt = GafUtil.toInteger(this.grdD0102Data[index].nstLodgAmt ?? (this.copyLodgD0102[index].rmchrAmt > 0 ? GafUtil.toInteger(this.copyLodgD0102[index].rmchrAmt) / GafUtil.toInteger(this.copyLodgD0102[index].lodgDdNum) : 0));
          const lodgDdNum = GafUtil.toInteger(this.grdD0102Data[index].lodgDdNum == 0 ? 1 : this.grdD0102Data[index].lodgDdNum);
          if(this.grdD0102Data[index].drmtLodgYn == 'Y' 
          // || this.grdD0102Data[index].extrlLctrYn == 'Y' //20250305
          ) {
            this.grdD0102Data[index].rmchrAmt = 0;
            //this.grdD0102Data[index].lodgDdNum = 0;
          }else {
            this.grdD0102Data[index].rmchrAmt = rmchrAmt * lodgDdNum;
          }
        }
        
        for (let index = 0; index < this.copyGrdD0102.length; index++) {
          const trfcAmt = this.copyGrdD0102[index].trfcAmt;
          // if(this.grdD0102Data[index].extrlLctrYn == 'Y') {   //20250305
          //   this.grdD0102Data[index].trfcAmt = 0;
          // }else {
            this.grdD0102Data[index].trfcAmt = trfcAmt;
          // }
        }

        // 여행명세 요금을 여비산출내역 교통비로 복사
        let pv = 0; 
        let pv2 = 0;
        for (let index = 0; index < this.copyGrdD0102.length; index++) {
          if(bztrpEmpData.bztrpEmpNo === this.copyGrdD0102[index].bztrpEmpNo) {
            pv += this.copyGrdD0102[index].trfcAmt;
            pv2 += this.copyGrdD0102[index].rmchrAmt;
          }
        }
        bztrpEmpData.trfcAmt = pv;
        bztrpEmpData.lodgAmt = pv2;

        // bztrpEmpData.trfcAmt = this.grdD0102Data
        //   .filter((f) => bztrpEmpData.bztrpEmpNo === f.bztrpEmpNo)
        //   .reduce((pv: number, cv: Gaf0708D02Data) => {
        //     return pv + Number(cv.trfcAmt);
        //   }, 0);
        // 출장자의 여행명세에서 교통금액을 연산처리하여 출장자의 교통금액에 저장

        // 여행명세 요금을 되돌린다.
        // this.grdD0102Data.forEach((d) => {
        //   d.trfcAmt = d.tmpTrfcAmt;
        // });

        //this.copyGrdD0102 = JSON.parse(JSON.stringify(this.grdD0102Data));
        this.calcGrdD0102AmtChange();
      }
    }
  }

  /**
   * 교통수단 변경
   */
  trfcMensCdChange(value: any, index:any): void {
    this.commonSaveParamChange(value, 'trfcMensCd');

    /** 출장자 Data */
    const btrpEmpData: Gaf0708D01Data = this.grdD0101Data;
    if (CommonUtil.isNotEmpty(btrpEmpData)) {
      if (value === '7') {  //공용

        // 교통비 0원 처리
        this.grdD0102Data[index].trfcAmt = 0;

        // 교통비 0원 처리
        // btrpEmpData.trfcAmt = 0;
        // this.grdD0102Data.forEach((d) => {
        //   d.trfcAmt = 0;
        // });

        this.calAtplTrfcAmt(index);  // 일비 계산

      } else if(value === '0'){  // 일반

        //nst 갔다오기 -> 교통비, 숙박비
        this.fn_getNstInfoForMv(index);
        // 일비계산
        this.calAtplTrfcAmt(index);  

        // this.grdD0102Data.forEach((d, index) => {
        //   d.trfcAmt = CommonUtil.isEmpty(this.copyGrdD0102[index].nstTrfcAmt) ? this.copyGrdD0102[index].trfcAmt : this.copyGrdD0102[index].nstTrfcAmt;
        // });

        // 교통비 계산
        // this.grdD0102Data
        // .forEach((data: Gaf0708D02Data) => {
        //   data.trfcAmt = data.tmpTrfcAmt;
        // });


        this.commonSaveParamChange('N', 'instVeclUseYn');
        this.commonSaveParamChange('N', 'etcVeclUseYn');
        this.commonSaveParamChange('', 'etcVeclUseRsnCntn');
        this.commonSaveParamChange('', 'wkndInthVeclUseYn');

        //this.getGradClbTrex();

      }
      // 여행명세 그리드에서 출장자의 교통비를 합산하여 출장자내역 교통비에 셋팅
      this.calcGrdD0101TrfcAmt();
      // 출장비의 총합계를 구하고 총 출장비, 총 운영비흡수액, 총 개인지급액을 셋팅
      this.calcTotAmt();
    }

    // this.fnCalVecl();
    // // 여행명세 그리드에서 출장자의 교통비를 합산하여 출장자내역 교통비에 셋팅
    // this.calcGrdD0101TrfcAmt();
    // // 출장비의 총합계를 구하고 총 출장비, 총 운영비흡수액, 총 개인지급액을 셋팅
    // this.calcTotAmt();

  }

  /**
   * 공제 회수 변경 이벤트 처리
   */
  ddctNumChange(event: any, property: string): void {
    const value = Math.floor(event);
    this.saveParam[property] = value;

    if(property === 'vsitInstMealInclNum') {  // 방문기관식사공제
      if(value > 0) {
        this.saveParam.vsitInstMealInclYn = 'Y';
      }else {
        this.saveParam.vsitInstMealInclYn = 'N';
      }
    }else if(property === 'vsitInstLodgInclNum') {  //방문기관숙박공제
      if(value > 0) {
        this.saveParam.vsitInstLodgInclYn = 'Y';
      }else {
        this.saveParam.vsitInstLodgInclYn = 'N';
      }
    }
    
    this.calcTotAmt('ddct');
  }

  /**
   * 차량 사용 여부 변경 이벤트 처리
   * - INST_VECL_USE_YN: 기관차량사용여부
   * - ETC_VECL_USE_YN: 기타차량사용여부
   * @param value
   * @param property
   */
  veclUseYnChange(value: any, property: string): void {
    this.commonSaveParamChange(value, property);
    this.calcTotAmt();
  }

  /**
   * 출장일수안내 다이얼로그 호출
   *
   * @see showPop()
   */
  openGafBtrpNotice(): void { 
    const dialogConfig = new CommonMatDialogConfig();
    dialogConfig.width = '700px';
    dialogConfig.height = '550px';
    dialogConfig.panelClass = ['modal-center'];
    dialogConfig.data = { PGM_ID: 'gaf0708' };

    this.dialog.open(Gaf070810Component, dialogConfig); 
  }

  /**
   * NST API 연동 교통금액 조회
   *
   * @param index
   */
  openNstApiTrfcAmt(index: number): void {

    this.searchParam.startCityCode = this.grdD0102Data[index].stpnCd;
    this.searchParam.endCityCode = this.grdD0102Data[index].arpnCd;
    const chaeDivCd = this.grdD0102Data[index].chaeDivCd;

    let respObj: any;

    this.commonHttpService.get('/gaf/com/getnstpath.do', this.searchParam).pipe(takeUntil(this.destroy)).subscribe({
        next: (response : any) => {
          if(CommonUtil.isNotEmpty(response.body)) {
            respObj = response.body;
          } else {
            this.commonMessageService.showSaveMsg(this.toastObj, response); // Exception 메시지 처리
          }
        },
        error: () => { 
          this.commonMessageService.showMsg(
            this.toastObj,
            {message:'NST에서 해당 경로의 운임비를 조회하지 못 하였습니다. <br/> 직접 입력해주세요.',
            type:'W'}
          );
        },
        complete: () => {
          
          if(chaeDivCd === 'A') {
            this.grdD0102Data[index].trfcAmt = respObj.payment*2; // 요금
          }else {
            this.grdD0102Data[index].trfcAmt = respObj.payment
          }

          this.grdD0102Data[index].rmchrAmt = respObj.rmchrAmt;   //숙박비

        }
      });

  }

  /**
   * 담당자 취소 사유 입력 다이얼로그 호출
   */
  openCrgrCnclDialog(): void {/* 
    const dialogConfig = new CommonMatDialogConfig();
    dialogConfig.width = '700px';
    dialogConfig.height = '240px';
    dialogConfig.panelClass = ['modal-center'];

    const dialogRef = this.dialog.open(Gaf070813Component, dialogConfig);

    dialogRef
      .afterClosed()
      .pipe(takeUntil(this.destroy))
      .subscribe((res) => {
        this.saveParam.CRGR_CNCL_YN = 'Y';
        this.saveParam.CRGR_CNCL_RSN_CNTN = res.CRGR_CNCL_RSN_CNTN;
        this.deleteform0101('Y');
      }); */
  }

  /**
   * 정보기기 반출 시 유의사항 다이얼로그 호출
   *
   */
  openGafAsetOutYn(): void {
    const dialogConfig = new CommonMatDialogConfig();
    dialogConfig.width = '700px';
    dialogConfig.height = '500px';
    dialogConfig.panelClass = ['modal-center'];

    this.dialog.open(GafAsetOutYnYComponent, dialogConfig);
  }

  /**
   * grdD0102의 요금이 바뀔때 출장비 자동계산
   *
   * @see amtChg()
   */
  calcGrdD0102AmtChange(): void {
    this.calcGrdD0101TrfcAmt(); // 여행명세 그리드에서 출장자의 교통비를 합산하여 출장자내역 교통비에 셋팅
  }

  /**
   * 출장자 이동 내역(여행명세) 중 교통별 구분 금액 구해서 출장자 내역의 교통비 합계에 대이터 넣기
   *
   * @see doTraffAmtMakeValue()
   */
  calcGrdD0101TrfcAmt(): void {
    // if (CommonUtil.isNotEmpty(this.grdD0102Data)) {
      
      // 일비 계산
      this.calAtplTrfcAmtAll();

      /**
       * 원내차량 이용일 경우 (교통비 0원)
       * NST 연계 추가
       * 교통구분이 육로, NST인 데이터를 초기화
       */
      if (this.saveParam.trfcMensCd === '7') {
        this.grdD0102Data.forEach((d: Gaf0708D02Data) => {
          d.trfcAmt = 0;
        });
      }

      /**
       * 0원 출장
       * NST 연계 추가
       * 교통비 초기화
       */
      if (this.saveParam.bztrp0AmtYn === 'Y') {
        this.grdD0102Data.forEach((d: Gaf0708D02Data) => {
          d.trfcAmt = 0;
          d.rmchrAmt = 0;
        });
      }

      // for (let index = 0; index < this.grdD0102Data.length; index++) {
      //   this.fnCalDrmtLodgYn(index);  //기숙사여부
      //   this.fnCalLctr(index);  //외부강의
      // }

      /** 교통금액 */
      let trfcAmt = 0;
      /** 항공금액 */
      let airAmt = 0;
      /** 숙박비 */
      let rmchrAmt = 0;

      // 교통구분이 항공이 아닌 것들의 합
      trfcAmt = this.grdD0102Data
        .filter((f: Gaf0708D02Data) => '807-003' !== f.trfcDivCd)
        .reduce((pv: number, cv: Gaf0708D02Data) => {
          return pv + Number(cv.trfcAmt ?? 0);
        }, 0);

      // 교통구분이 항공인 것들의 합.
      airAmt = this.grdD0102Data
        .filter((f: Gaf0708D02Data) => '807-003' === f.trfcDivCd)
        .reduce((pv: number, cv: Gaf0708D02Data) => {
          return pv + Number(cv.trfcAmt ?? 0);
        }, 0);
      
      // 여행명세(경유지) 숙박비 합
      // if(this.saveParam.bztrpTotDdNum > 1) {
      rmchrAmt = this.grdD0102Data.reduce((pv: number, cv: Gaf0708D02Data) => {
        return pv + Number(cv.rmchrAmt ?? 0);
      }, 0);
      // }

      /** 출장자 Data */
      const bztrpEmpData: Gaf0708D01Data = this.grdD0101Data;
      if (CommonUtil.isNotEmpty(bztrpEmpData)) {
        if (this.saveParam.bztrp0AmtYn === 'Y') {
          // 0원 출장일 떄
          bztrpEmpData.trfcAmt = 0;
          bztrpEmpData.airAmt = 0;
          bztrpEmpData.lodgAmt = 0;
          bztrpEmpData.mealAmt = 0;
          bztrpEmpData.atplTrfcAmt = 0;
          
        } else {
          // 0원 출장이 아닐 떄
          bztrpEmpData.trfcAmt = trfcAmt;
          bztrpEmpData.airAmt = airAmt;
          bztrpEmpData.lodgAmt = rmchrAmt;
          //bztrpEmpData.atplTrfcAmt = atplTrfcAmt;
        }
      }
    // }

    // 여행명세 데이터가 있을 때
    //console.log("여행명세데이터",this.grdD0102Data);
    this.calcTotAmt(); // 출장비의 총합계를 구하고 총 출장비, 총 운영비흡수액, 총 개인지급액을 셋팅
  }

  /**
   * 출장내용 그리드 행추가
   * grdD0103 값 변경 처리
   *
   * @param args
   * @param index
   * @param column
   */
  grdD0103Change(args: any, index: number, column: string): void {
    let value = args;
    if(CommonUtil.isNotEmpty(args)) {
      this.grdD0103Data[index][column] = value;
    }

    let bginDt = '';
    let endDt = '';

    if('bginDt' === column || 'endDt' === column) {
      bginDt = this.grdD0103Data[index].bginDt;
      endDt = this.grdD0103Data[index].endDt;
    }

    if(CommonUtil.isNotEmpty(bginDt) && CommonUtil.isNotEmpty(endDt)) {
      // 날짜역전 검증
      if(bginDt > endDt) {
        this.commonMessageService.showMsg(this.toastObj, { message : message.puc_warn_date_compare.replace('{0}', '시작일자').replace('{1}', '종료일자').replace('{2}', '클'), type : 'W', title : '경고 알람' }); // 시작일자는 종료일자 보다 클 수 없습니다.
        this.grdD0103Data[index][column] = '';
        return;
      }

      const bztrpBginDt = this.saveParam.bztrpBginDt;
      const bztrpEndDt = this.saveParam.bztrpEndDt;

      if(bginDt < bztrpBginDt || endDt > bztrpEndDt) {
        this.commonMessageService.showMsg(this.toastObj, { message : '해당 일자가 출장기간에 포함되지 않습니다.', type : 'W', title : '경고 알람' });
        this.grdD0103Data[index][column] = '';
        return;
      }

      const dy = GafUtil.getDayName(bginDt)+'~'+GafUtil.getDayName(endDt)
      this.grdD0103Data[index].dy = dy;

    }

    const crudgrid: GridUpdateModel = {
      gridData: this.grdD0103Data,
      value: value,
      index: index,
      column: column
    };
    this.commonGridService.gridCrudUpdate(crudgrid);
  }

  /**
   * 내외부인 다이얼로그 Component 조회
   *
   * @param imnYn \
   * @returns
   */
  getImnYnDComponent(imnYn: string = 'Y'): any {
    if (imnYn === 'Y') {
      return this.empDComponent;
    } else {
      return this.gafExtrDComponent;
    }
  }

  /**
   * 내외부인 다이얼로그 Width 조회
   *
   * @param imnYn \
   * @returns
   */
  getImnYnDWidth(imnYn: string = 'Y'): any {
    if (imnYn === 'Y') {
      return this.empDWidth;
    } else {
      return this.gafExtrDWidth;
    }
  }

  /**
   * 내외부인 다이얼로그 Height 조회
   *
   * @param imnYn \
   * @returns
   */
  getImnYnDHeight(imnYn: string = 'Y'): any {
    if (imnYn === 'Y') {
      return this.empDHeight;
    } else {
      return this.gafExtrDHeight;
    }
  }

  /**
   * grdD0101 값 변경 처리
   *
   * @see amtCalcu()
   * @param event
   * @param index
   * @param property
   */
  grdD0101Change(event: any, property: string): void {
   
    if (
      property === 'atplTrfcAmt' || // 일비
      property === 'lodgAmt' || // 숙박비
      property === 'mealAmt' || // 식비
      property === 'trfcAmt'    // 교통비
      || property === 'xcldChfdAmt'  // 제외식비
      || property === 'xcldCpdAmt'   // 제외일비
      || property === 'xcldTrfcAmt'  // 제외교통비
    ) {
      //if(property === 'MEAL_AMT') this.mealAmt = event;
      this.grdD0101Data[property] = event;
      this.calcTotAmt(); // 비용 총합계 계산

    }else if(property === 'sapvApntYn') {  // 대결지정
      this.grdD0101Data[property] = event.value;
    }
    
  }


  /**
   * grdD0101 출장자 변경 이벤트 처리
   *
   * @see clickEmpGridPopup(value:String="")
   * @see enterEmpGridPopup(event:CommonEvent)
   * @see popupExtrPers()
   * @param event
   * @param index
   */
  grdD0101BtrpNmChange(event: any, index: number): void {
    // 기존정보 초기화
    /** 출장직원번호 BTRP_EMP_NO */
    let bztrpEmpNo = '';
    /** 출장자 BTRP_EMP_NM */
    let bztrpEmpNm = '';
    /** 출장부서코드 BTRP_DEPT_CD */
    let bztrpDeptCd = '';
    /** 출장부서 BTRP_DEPT_NM */
    let bztrpDeptNm = '';
    /** 출장직급코드 BTRP_GRAD_CD */
    let bztrpGradCd = '';
    /** 출장직급 BTRP_GRAD_NM */
    let bztrpGradNm = '';
    /** 출장직급코드 BTRP_POSI_CD */
    let bztrpPosiCd = '';
    /** 외부인소속기관명 OUTR_PSTN_INST_NM */
    let outrPstnInstNm = '';
    /** 외부인직위명 OUTR_POSI_NM */
    let outrPosiNm = '';
    /** 은행코드 BNK_CD */
    let bnkCd = '';
    /** 예금주명 DPWN_NM */
    let dpownNm = '';
    /** 계좌번호 BACT_NO */
    let bactNo = '';
    /** 계좌번호 */
    let bztrpBactNo = '';
    /** 은행코드 */
    let bztrpBankCd = '';
    /** 사업장코드 */
    let bplcCd = '';
    //여비등급코드
    let trexGrdCd = '';
    //신분등급코드
    let scpsGrdCd = '';

    if (CommonUtil.isNotEmpty(event)) {
      // callback으로 전달 받은 데이터 매핑
      if (this.grdD0101Data.imnYn === 'Y') {
        // 내부인
        if (CommonUtil.isNotEmpty(event.empNo)) {
          console.log("내부인",event);

          bztrpEmpNo = event.empNo;
          bztrpEmpNm = event.name;
          bztrpDeptCd = event.deptCd;
          bztrpDeptNm = event.deptNm;
          bztrpGradCd = event.gradCd;
          bztrpGradNm = event.gradNm;
          bztrpPosiCd = event.posiCd;
          bztrpBactNo = event.bztrpBactNo;
          bztrpBankCd = event.bztrpBankCd;
          dpownNm = event.name;
          bplcCd = event.wrkAreaCd;
          trexGrdCd = event.gradDivCd; // 여비등급
          scpsGrdCd = event.scpsGrdCd; // 신분등급

          if( CommonUtil.isEmpty(bztrpBactNo) ||
              CommonUtil.isEmpty(bztrpBankCd)
            ) {
              this.commonMessageService.showMsg(this.toastObj, { message: '경비계좌가 등록되어있지 않습니다. 급여관리자에게 문의하시기 바랍니다.', type: 'W'});
              bztrpEmpNo = '';
              bztrpEmpNm = '';
              bztrpDeptCd = '';
              bztrpDeptNm = '';
              bztrpGradCd = '';
              bztrpGradNm = '';
              bztrpPosiCd = '';
              bztrpBactNo = '';
              bztrpBankCd = '';
              dpownNm = '';
              bplcCd = '';
              trexGrdCd = '';
              scpsGrdCd = '';
              //return;
            }
        }
      }
    }

    // 데이터 매핑 결과가 없음 그대로 empty string으로 치환
    // const crudgrid: GridUpdateModel = {
    //   gridData: this.grdD0101Data,
    //   value: bztrpEmpNo,
    //   index: index,
    //   column: 'bztrpEmpNo'
    // }
    //update crud
    // this.commonGridService.gridCrudUpdate(crudgrid);

    this.grdD0101Data.bztrpEmpNm = bztrpEmpNm;
    this.grdD0101Data.bztrpDeptCd = bztrpDeptCd;
    this.grdD0101Data.bztrpDeptNm = bztrpDeptNm;
    this.grdD0101Data.bztrpGradCd = bztrpGradCd;
    this.grdD0101Data.bztrpGradNm = bztrpGradNm;
    this.grdD0101Data.bztrpPosiCd = bztrpPosiCd;
    this.grdD0101Data.outrPosiNm = outrPosiNm;
    this.grdD0101Data.outrPstnInstNm = outrPstnInstNm;
    this.grdD0101Data.bnkCd = bnkCd;
    this.grdD0101Data.dpownNm = dpownNm;
    this.grdD0101Data.bankCd = bztrpBankCd;  //은행코드
    this.grdD0101Data.bplcCd = bplcCd;  //사업장코드
    

    // 변경 후 처리
    if (this.grdD0101Data.imnYn === 'Y') {
      // 내부인
      this.getAbntAbleYn('Y'); // 부재자 체크
    } 
  }

  /**
   * 여비등급 조회
   */
  fn_trexInfo() {
    const param = {empNo:this.userInfo.empNo}
    this.commonHttpService.get('/per/dialog/getemplist.do', param).pipe(takeUntil(this.destroy)).subscribe({
      next: (response: any) => {
        if(CommonUtil.isNotEmpty(response.body)) {
          const resultList = response.body;
          if(CommonUtil.isNotEmpty(resultList[0].bztrpBactNo)) {
            this.grdD0101Data.dpownNm = resultList[0].name;
            this.grdD0101Data.bztrpEmpNo = resultList[0].empNo;
            this.grdD0101Data.bztrpEmpNm = resultList[0].name;
            this.grdD0101Data.bztrpDeptCd = resultList[0].deptCd;
            this.grdD0101Data.bztrpDeptNm = resultList[0].deptNm;
            this.grdD0101Data.bztrpGradCd = resultList[0].gradCd;
            this.grdD0101Data.bztrpGradNm = resultList[0].gradNm;
            this.grdD0101Data.bztrpPosiCd = resultList[0].posiCd;
            this.grdD0101Data.bankCd = resultList[0].bztrpBankCd;
            this.grdD0101Data.dpownNm = resultList[0].name;
            this.grdD0101Data.bplcCd = resultList[0].wrkAreaCd;
            this.grdD0101Data.trexGrdCd = resultList[0].gradDivCd; // 여비등급
            this.grdD0101Data.scpsGrdCd = resultList[0].scpsGrdCd; // 신분등급

          }else {
            this.commonMessageService.showMsg(this.toastObj, {message:'경비계좌가 등록되어있지 않습니다. 급여관리자에게 문의하시기 바랍니다.', type:'W' });
            return;
          }
        }
      },
      error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      },
      complete: () => { console.log(this.grdD0101Data); }
    })
  }

  /**
   * grdD0101 대리인 변경 이벤트 처리
   *
   * @see clickAgyGridPopup(value:String="")
   * @see enterAgyGridPopup(event:CommonEvent)
   * @see getAbstChkforAgt(value:int)
   * @param event
   * @param index
   */
  grdD0101AngtNmChange(event: any): void {
     
    /** 대리인직원번호 angtEmpNo */
      let angtEmpNo = '';
      /** 대리인 angtEmpNm */
      let angtEmpNm = '';
      /** 대리인 ANGT_DEPT_CD */
      let angtDeptCd = '';
      /** 대리인직급코드 ANGT_GRAD_CD */
      let angtGradCd = '';
      /** 대결지정여부 RPRV_APNT_YN */
      let rprvApntYn = 'N';
  
      if (CommonUtil.isNotEmpty(event)) {
        // callback으로 전달 받은 데이터 매핑
        
        if (CommonUtil.isNotEmpty(event.empNo)) {
          angtEmpNo = event.empNo;
          angtEmpNm = event.name;
          angtDeptCd = event.deptCd;
          angtGradCd = event.posiCd;
          rprvApntYn = 'Y';
        }
      }
  
      /** 출장자 Data */
      const bztrpEmpData: Gaf0708D01Data = this.grdD0101Data;
  
      /** 출장자 Data */
      if (CommonUtil.isNotEmpty(bztrpEmpData)) {
        if (CommonUtil.isNotEmpty(angtEmpNo)) {
          // 내부인만 부재자 체크 진행
          const param = {
            empNo: angtEmpNo,
            bginDt: this.saveParam.bztrpBginDt,
            endDt: this.saveParam.bztrpEndDt,
          };
          // 부재자 체크하는 파라미터 VO확인하기@@@@

          let abntAbleYn = '';
  
          this.commonHttpService.get('/gaf/com/getabntableyn', param).pipe(takeUntil(this.destroy)).subscribe({
            next: (response: any) => {
              // Y:부재자아님 N:부재자
              abntAbleYn = response.body.abntAbleYn;
            },
            error: (error: any) => {
              this.commonMessageService.showSaveMsg(this.toastObj, error);
            },
            complete: () => {
              let refreshFlag = false;
              if (bztrpEmpData.bztrpEmpNo === angtEmpNo) {
                CommonUtil.commonMsg(
                  this.toastObj,
                  '해당 직원은 출장자에 포함되어 있습니다.',
                  'W'
                );
                refreshFlag = true;
              } else if (
                CommonUtil.isNotEmpty(abntAbleYn) &&
                abntAbleYn === 'N'
              ) {
                CommonUtil.commonMsg(
                  this.toastObj,
                  '해당 직원은 설정된 출장기간에 부재자로 등재되어 있습니다.',
                  'W'
                );
                refreshFlag = true;
              }
  
              // 데이터 매핑 결과가 없음 그대로 empty string으로 치환
              // angtEmpNo 세팅
              // const crudgrid: GridUpdateModel = {
              //   gridData: this.grdD0101Data,
              //   value: angtEmpNo,
              //   index: index,
              //   column: angtEmpNo
              // };

              this.grdD0101Data.angtEmpNo = angtEmpNo;
              this.grdD0101Data.angtEmpNm = angtEmpNm;
              // this.grdD0101Data[index].angtDeptCd = angtDeptCd;
              this.grdD0101Data.angtGradCd = angtGradCd;
  
              if (refreshFlag) {
                this.grdD0101Data.angtEmpNo = '';
                this.grdD0101Data.angtEmpNm = '';
                this.grdD0101Data.angtGradCd = '';
                //this.grdD0101?.refresh();
              }

              // this.commonGridService.gridCrudUpdate(crudgrid);
            }
          });
        } else {
          // 데이터 매핑 결과가 없음 그대로 empty string으로 치환
          // const crudgrid: GridUpdateModel = {
          //   gridData: this.grdD0101Data,
          //   value: angtEmpNo,
          //   index: index,
          //   column: 'angtEmpNo'
          // }
          //update crud
          // this.commonGridService.gridCrudUpdate(crudgrid);
          // angtEmpNo 세팅
  
          this.grdD0101Data.angtEmpNm  = angtEmpNm;
          this.grdD0101Data.angtGradCd = angtGradCd;
        }
      }
  } 
  

  /*-----------------  Data Handler End  -----------------*/

  /*-----------------  Event Handler Start  -----------------*/

  // created(): void {
  //   this.calcGridHeight();
  //   // 새로고침 이슈 해결 법
  //   setTimeout(() => {
  //     this.calcGridHeight();
  //   }, CommonUtil.gridHeightDelay);
  // }


  // /**
  //  * grid 높이 계산
  //  *
  //  */
  // calcGridHeight(): void {
  //   this.grdD0103Height = CommonUtil.commonGridHeight(0, 50);
  // }

  /**
   * 권한 및 결재상태에 따른 버튼 제어
   *
   * @see setBtnHidden()
   */
  changeBtnDisabled(): void {
    this.adminChk = CommonUtil.hasRole('000000','R00201');  // 권한여부

    if (GafUtil.getBooleanByApvStat(this.saveParam.misApprvStatCd)) {
      this.btnRqstDisabled = true;
      this.btnSaveDisabled = true;
      this.btnDeleteDisabled = true;
      this.grdItemEnabled = false;
      this.bscGrdInptItemEnabled = false;
      this.trfcCldvInptItemEnabled = false;
    } else {
      // 미저장/반려/저장 상태일 경우 수정/입력 가능
      this.btnRqstDisabled = false;
      this.btnSaveDisabled = false;
      this.btnDeleteDisabled = false;
      this.grdItemEnabled = true;
      this.bscGrdInptItemEnabled = true;
      this.trfcCldvInptItemEnabled = true;
    }

    if (CommonUtil.isEmpty(this.saveParam.misApprvStatCd)) {
      this.btnDeleteDisabled = true;
    }

    /**
     * @todo pgmId에 따른 분기 처리
     */
    // 출장현황조회에서 창을 호출했을 때
    if (this.pgmId === 'gaf1040') {
      // CommonUtil.componentsEnable(false, idArr);
      // CommonUtil.componentsVisible(false,btnArr);
      // itemEnableYn = false;
      // itemRenderEnabledTRP_COLS = false;
      // btnC.visible = false;
      this.btnRqstDisabled = true;
      this.btnSaveDisabled = true;
      this.btnDeleteDisabled = true;

      this.grdItemEnabled = false;
      this.bscInptItemEnabled = false;
      this.bscGrdInptItemEnabled = false;
      this.trfcCldvInptItemEnabled = false;
    }

    // 결재완료된 출장신청서 중 정산되지 않은 신청서는 출장 담당자 취소할 수 있음.
    /**
     * @todo 정산여부 칼럼 및 조건 추가해야 함.
     * - FIX_YN === 'N'
     */
    if (
      this.adminChk &&
      this.saveParam.misApprvStatCd === '31' &&
      this.fixYn === 'N'
    ) {
      this.btnCancelDisabled = false;
    }

  }

  keydown(args: Event): void {
    args.stopImmediatePropagation();
  }

  /**
   * 행추가 시 필수값 체크
   *
   * @see requiredChk()
   * @returns
   */
  checkAddRow(): boolean {
    if (CommonUtil.isEmpty(this.saveParam.bdgCd)) {
      // 예산
        this.commonMessageService.showMsg(
        this.toastObj,
        {message:message.com_warn_need_data.replace('{0}', '예산'),
        type:'W'}
      );
      return false;
    }

    if (CommonUtil.isEmpty(this.saveParam.bztrpBginDt)) {
      // 출장시작일자
       this.commonMessageService.showMsg(
        this.toastObj,
        {message : message.com_warn_need_data.replace('{0}', '출장시작일자'),
        type : 'W'}
      ); 
      return false;
    }

    if (CommonUtil.isEmpty(this.saveParam.bztrpEndDt)) {
      // 출장종료일자
       this.commonMessageService.showMsg(
        this.toastObj,
        {message : message.com_warn_need_data.replace('{0}', '출장종료일자'),
        type : 'W'}
      ); 
      return false;
    }

    if (CommonUtil.isEmpty(this.saveParam.bztrpTotLodgNum)) {
      // 박수
      this.commonMessageService.showMsg(
        this.toastObj,
        {message : message.com_warn_need_data.replace('{0}', '박수'),
        type : 'W'}
      ); 
      return false;
    }

    if (CommonUtil.isEmpty(this.saveParam.bztrpShpCd)) {
      // 출장형태
      this.commonMessageService.showMsg(
        this.toastObj,
        {message : message.com_warn_need_data.replace('{0}', '출장형태'),
        type : 'W'}
      ); 
      return false;
    }

    return true;
  }

  recordDoubleClickGrdD0103(args: any): void {
    if (this.saveParam.misApprvStatCd === '01') {
      // 수정 가능일 경우만 수정 모드 활성화
      this.commonGridService.gridCrudMode(this.grdD0103Data, args);
    }
  }

  dataSourceChangeGrdD0103(args: any): void {
    /* CommonUtil.commonGridScrollTop(this.grdD0103, args); // 조회 후 스크롤 상단으로 이동 */
  }

  grdD0103HeaderChkChange(args: any): void {
    this.commonGridService.gridHeaderChkChange(this.grdD0103Data, args);
    // CommonUtil.commonGridHeaderChkChange(this.grdD0103Data, args);
  }

  grdD0103ChkChange(args: any, index: number): void {
    this.grdD0103Data[index].chk = args.checked;
    this.headerChkGrdD0103 = this.commonGridService.gridDataChkChange(this.grdD0103Data);

  //  this.grdD0103Data[index].CHK = args.checked;
  //   this.headerChkGrdD0103 = CommonUtil.commonGridVirtualHeaderChk(
  //     this.grdD0103Data
  //   );
  }

  /**
   * grdD0103 (출장내용) 행 추가
   *
   * @see addRow3()
   */
  grdD0103AddRow(): void {
    if (this.checkAddRow()) {
      /** 삭제 대상이 아닌 실 출장내용 Array */
      const existDataArray = this.grdD0103Data.filter((f: any) => f.crud !== 'D');

      if (existDataArray.length > 4) {
        this.commonMessageService.showMsg(this.toastObj, {message:'출장내용은 최대 5개로 제한해 주십시오.', type:'W'});
      } else {
        this.headerChkGrdD0103 = false;
        let item : any = {};

        // if (existDataArray.length === 0) {
          // 첫행일 때
          item = {bginDt : this.saveParam.bztrpBginDt, endDt : this.saveParam.bztrpEndDt};  // 1행 내용 입력 시 출장 시작일자로 일자 셋팀
        // } 
        /*
        else {
          // 마지막 등록 데이터
          const lastData = existDataArray[existDataArray.length - 1];
          if (this.saveParam.bztrpBginDt === this.saveParam.bztrpEndDt) {
            // 출장 시작일자와 종료일자가 같을 때 일자를 출장 시작일자로 셋팅
            item = {dwupDt : this.saveParam.bztrpBginDt}; // 1행 내용 입력 시 출장 시작일자로 일자 셋팀
          } else if (lastData.dwupDt === this.saveParam.bztrpEndDt) {
            // 바로 전 행의 일자와 출장 종료일자가 같을 때 일자에 출장 종료일자 셋팅
            item = {dwupDt : this.saveParam.bztrpEndDt};
          } else if (
            lastData.dwupDt !== this.saveParam.bztrpEndDt &&
            this.saveParam.bztrpBginDt !== this.saveParam.bztrpEndDt
          ) {
            // 바로 전 행의 일자가 출장 시작일자나 종료일자와 일치하지 않을 때 바로 전 행의 다음날짜를 일자에 셋팅
              item = {dwupDt : this.commonDateService.getAddDate(1, lastData.dwupDt)};
          }
        }
        */

        // 요일 계산
        item['dy'] = GafUtil.getDayName(item.bginDt) + '~' + GafUtil.getDayName(item.endDt);

        const obj: GridAddModel = {
          gridObj : this.grdD0103
          ,gridData : this.grdD0103Data
          , position: 'bottom'
          , newData : item
        }

        this.commonGridService.gridAddRow(obj);
      }
    }
  }

  /**
   * grdD0103 (출장내용) 행 삭제
   *
   * @see deleteRow3()
   */
  grdD0103RemoveRow(): void {
    this.headerChkGrdD0103 = false;
    this.grdD0103?.clearSelection(); // 직접 구현한 체크박스 사용시 행삭제전 실행
    const obj: GridDeleteModel = {
      gridObj : this.grdD0103
      ,gridData : this.grdD0103Data
      ,toastObj: this.toastObj
      ,apiUrl: '/gaf/gaf0708/01/deleteCntn.do' // 저장 요청 url
      ,destroy : this.destroy
    };
    this.commonGridService.gridDeleteRow(obj);
  }

  /**
   * grdD0103 엑셀 다운로드
   */
  grdD0103ExcelExport(): void {
    this.commonExcelService.gridSelectExcelExport(this.grdD0103, '출장내용');
  }
  /**
   * grdD0102 엑셀 다운로드
   */
  grdD0102ExcelExport(): void {
    this.commonExcelService.gridSelectExcelExport(this.grdD0102, '출장지역');
  }

  /**
   * 엑셀 다운로드 내용 포맷 설정
   * @param $event 
  */
  excelQueryCellInfoHandler($event: any) {
    const field = $event.column.field;
    if (field === 'trfcAmt' || field === 'rmchrAmt'){
      $event.value = this.comCommaPipe.transform($event.value);
    } else if (field === 'dwupDt'){
      $event.value = this.comDatePipe.transform($event.data.bginDt) + "~" + this.comDatePipe.transform($event.data.endDt);
    } else if(field === 'drmtLodgYn') {
      if(CommonUtil.isEmpty($event.value)) {
        $event.value = 'N';
      }
    }else if(field === 'trfcDivCd') {
      $event.value = 'NST';
    }else if(field === 'dwntBztrp') {  //시내출장 시간
      $event.value = this.comDateTimePipe.transform($event.data.dwntBztrpBginHh) + "~" + this.comDateTimePipe.transform($event.data.dwntBztrpEndHh);
    }else if(field === 'mvBginDt' || field === 'mvEndDt') {  // 날짜
      $event.value = this.comDatePipe.transform($event.value);
    }
  }  

  recordDoubleClickGrdD0101(args: any): void {
    if(this.saveParam.misApprvStatCd === '01') {
      // if(this.grdD0101Data.crud_mode) {
      //   this.grdD0101Data.crud_mode = false;
      // }else {
        this.grdD0101Data.crud_mode = true;
      // }
      //this.commonGridService.gridCrudMode(this.grdD0101Data, args);
    }
  }

  grdD0101HeaderChkChange(args: any): void {
   // CommonUtil.commonGridHeaderChkChange(this.grdD0101Data, args);
  }

  grdD0101ChkChange(args: any, index: number): void {
    this.grdD0101Data.chk = args.checked;
   /*  this.headerChkGrdD0101 = CommonUtil.commonGridVirtualHeaderChk(
      this.grdD0101Data
    ); */
  }

  recordDoubleClickGrdD0102(args: any): void {
    if(this.saveParam.misApprvStatCd === '01') {
      this.commonGridService.gridCrudMode(this.grdD0102Data, args);
    }
  }

  /**
   * 여행명세(경유지) 상세 다이얼로그 호출
   */
  openGaf070815Dialog(item: Gaf0708D02Data, idx: number = -1): void {
    
    if (this.checkAddRow()) {
      /** 출장자 Data */
      const btrpEmpData: Gaf0708D01Data = this.grdD0101Data;

      //console.log('경유지', btrpEmpData);

      if (CommonUtil.isEmpty(btrpEmpData?.bztrpEmpNo)) {
        this.commonMessageService.showMsg(
          this.toastObj,
          {message:'여비산출내역에서 출장자를 먼저 선택하여 주십시오.',
          type:'W'}
        );
        return;
      }

      this.headerChkGrdD0102 = false;
      if (idx === -1) {
        // 신규 등록일 때
        item.bztrpEmpNo = btrpEmpData.bztrpEmpNo;
        item.bztrpEmpNm = btrpEmpData.bztrpEmpNm;
        item.bztrpGradCd = btrpEmpData.bztrpGradCd;
        item.bztrpGradNm = btrpEmpData.bztrpGradNm;
        // item.TRFC_AMT = 0;
        item.chaeDivCd = 'A';
        item.chaeDivNm = this.commonGridService.findLabel(
          this.CHAE_DIV_CD_LIST,
          'B'
        ); // 코드라벨 변경

        // NST API 기본 선택
        item.trfcDivCd = '807-008';

        item.trfcDivNm = this.commonGridService.findLabel(
          this.CHAE_DIV_CD_LIST,
          item.trfcDivCd
        ); // 코드라벨 변경
        
        // 여비등급코드
        item.trexGrdCd = btrpEmpData.trexGrdCd;
        // 신분등급코드
        item.scpsGrdCd = btrpEmpData.scpsGrdCd;
      }
      const dialogConfig = new CommonMatDialogConfig();
      dialogConfig.width = '800px';
      dialogConfig.height = '500px';
      dialogConfig.panelClass = ['modal-center'];
      dialogConfig.data = {
        rowData: item,
        saveParam: this.saveParam,
        idx: idx,
      };
      
      const dialogRef = this.dialog.open(Gaf070815Component, dialogConfig);

      // 다이얼로그 데이터 저장
      dialogRef.afterClosed().pipe(takeUntil(this.destroy))
        // tslint:disable-next-line: deprecation
        .subscribe((res: any) => {

          console.log("dialog close", res);

          if (CommonUtil.isNotEmpty(res)) {
            res.trfcDivNm = this.commonGridService.findLabel(
              this.TRFC_DIV_CD_LIST,
              res.trfcDivCd
            ); // 코드라벨 변경

            res.chaeDivNm = this.commonGridService.findLabel(
              this.CHAE_DIV_CD_LIST,
              res.chaeDivCd
            ); // 코드라벨 변경
            
            // 숙박비 저장
            this.lodgAmt = res.rmchrAmt;
            
            this.dwntBztrpVisible = false;
            // 시내출장일경우 (출발지=도착지)
            if(res.arpnCd === res.stpnCd) {  // 교육+시내출장은 한 건 이상 가능
              res.dwntBztrpCd = '1';         // 시내출장
              this.dwntBztrpVisible = true;
              // 식비 없음
              this.grdD0101Data.mealAmt = 0;
              this.grdD0101Data.mealCnt = 0;

              if(CommonUtil.isNotEmpty(this.grdD0102Data)) {  // 이전 행이 존재 (이전행이 시내출장이 아니면 등록 할 수 없음.)
                
                const cntList = this.grdD0102Data.filter((f:any) => f.dwntBztrpCd === '0' || f.stpnCd !== f.arpnCd);
                if(cntList.length > 0) {
                  this.commonMessageService.showMsg(this.toastObj, { message: '시외출장과 시내출장은 함께 등록할 수 없습니다.', type: 'W'});
                  return;
                }
                if(this.saveParam.bztrpShpCd !== '5') {
                  this.commonMessageService.showMsg(this.toastObj, { message: '시내출장은 한 건만 등록할 수 있습니다.', type: 'W'});
                  return;
                }
              }

              // 유연근무 시간 조회
              this.fn_ftmInfo(this.grdD0102Data.length);
            }else {
              res.dwntBztrpCd = '0';  // 전일출장

              // 시외출장을 등록하는데 시내출장 행이 이전에 등록되어있으면 x
              const cntList = this.grdD0102Data.filter((f:any) => f.dwntBztrpCd === '1' || f.stpnCd === f.arpnCd);
              if(cntList.length > 0) {
                this.dwntBztrpVisible = true;
                this.commonMessageService.showMsg(this.toastObj, { message: '시외출장과 시내출장은 함께 등록할 수 없습니다.', type: 'W'});
                return;
              }

            }
            res.nstLodgAmt = res.rmchrAmt;  // nst 숙박비 값 저장
            res.nstTrfcAmt = res.trfcAmt;   // nst 교통비 값 저장

            if(this.grdD0102Data.length === 0) {  // 첫 경유지 등록시 출장 박수에 맞춰서 숙박일수 set + 출장일자로 set
              res.rmchrAmt = this.saveParam.bztrpTotLodgNum * res.nstLodgAmt; // 숙박비
              res.lodgDdNum = this.saveParam.bztrpTotLodgNum;
              // 시작일자, 종료일자 => 출장일자로 기본 셋팅
              res.mvBginDt = this.saveParam.bztrpBginDt;
              res.mvEndDt = this.saveParam.bztrpEndDt;

              // 첫 행 + 외부강의 일 때 체크박스 체크해주기
              if(this.saveParam.bztrpShpCd == '5') {
                res.extrlLctrYn = 'Y';
              }

            }else {
              res.rmchrAmt = 0; // 숙박비
              res.lodgDdNum = 0;
            }

            if (idx === -1) {
              
              const obj: GridAddModel = {
                gridObj: this.grdD0102,
                gridData: this.grdD0102Data,
                newData: res,
                position: 'bottom'
              }
              this.commonGridService.gridAddRow(obj).gridCnt;
              
              // 신규 행 추가일 경우
              this.grdD0102AddRow(res);
              
            } else {
              // 행 수정일 경우
              this.grdD0102UpdateRow(res, idx);
            }

            this.copyGrdD0102 = JSON.parse(JSON.stringify(this.grdD0102Data)); //그리드 복사
            this.copyLodgD0102 = JSON.parse(JSON.stringify(this.grdD0102Data)); //숙박비그리드 복사
          }
        });
    }
  }

  grdD0102HeaderChkChange(args: any): void {
    this.commonGridService.gridHeaderChkChange(this.grdD0102Data, args);
  }

  grdD0102ChkChange(args: any, index: number): void {
    this.grdD0102Data[index].chk = args.checked;
    // this.headerChkGrdD0102 = CommonUtil.gridVirtualHeaderChk(
    //   this.grdD0102Data
    // );
  }
  
  grdD0102Change2(args: any, index: number, column: string) {
    if(args.event) {
      this.grdD0102Data[index][column] = args.value;
      const crudgrid: GridUpdateModel = {
        gridData: this.grdD0102Data,
        value: args,
        index: index,
        column: column
      };
      this.commonGridService.gridCrudUpdate(crudgrid);
    }
  }

  // 경유지 그리드 수정
  grdD0102Change(args: any, index: number, column: string) {
    this.grdD0102Data[index][column] = args;

    // 경유지 요금을 수정할 때 다시 계산 필요
    if(column === 'trfcAmt') {

      let trfcAmt : number = 0;
      this.grdD0102Data.forEach((d) => {
        trfcAmt += Number(d.trfcAmt);
      });

      // 출장자내역의 교통비에 적용
      this.grdD0101Data.trfcAmt = trfcAmt;
      
      if(args !== 0) {
        this.copyGrdD0102[index].trfcAmt = args;
      }

      //this.calcTotAmt();
    }else if(column === 'rmchrAmt'){  //숙박비  -> 수정 불가로 변경
      
      let rmchrAmt : number = 0;
      this.grdD0102Data.forEach((d) => {
        rmchrAmt += Number(d.rmchrAmt);
      });
      // 출장자내역의 숙박비에 적용
      this.grdD0101Data.lodgAmt = rmchrAmt;

    }else if(column === 'dwntBztrpBginHh' || column === 'dwntBztrpEndHh') {
      this.calAtplTrfcAmt(index);  // 일비 계산

    }else if(column === 'drmtLodgYn' || column === 'extrlLctrYn') { // 기숙사숙박여부 //외부강의여부
      args = args.checked ? 'Y' : 'N';
      this.grdD0102Data[index][column] = args;

      if(column === 'extrlLctrYn' && CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo)) {
        this.extrlLctrDisabled = args.checked ? true : false;
      }

      // if ('Y' === args) {
      //   this.grdD0102Data[index].drmtLodgYn = args;
      //   this.grdD0102Data[index].rmchrAmt = 0;
      // }else {
      //   const rmchrAmt = this.copyLodgD0102[index].rmchrAmt;  //숙박비 복사
      //   this.grdD0102Data[index].drmtLodgYn = args;
      //   this.grdD0102Data[index].rmchrAmt = rmchrAmt;
      //   if(this.saveParam.bztrp0AmtYn == 'Y' || this.grdD0102Data[index].extrlLctrYn == 'Y') {  //0원출장 이거나 외부강의 일 때
      //     this.grdD0102Data[index].rmchrAmt = 0;
      //   }
      // }
      //this.copyGrdD0102 = JSON.parse(JSON.stringify(this.grdD0102Data));
    }else if(column === 'lodgDdNum') {  //숙박일수
      // 기숙사 숙박, 외부강의가 아닐 때에만 계산
      if(this.grdD0102Data[index].drmtLodgYn !== 'Y' && this.grdD0102Data[index].drmtLodgYn !== 'Y') {

        const lodgDdNum = GafUtil.toInteger(args);
        //const rmchrAmt = GafUtil.toInteger(this.copyLodgD0102[index].rmchrAmt) > 0 ? GafUtil.toInteger(this.copyLodgD0102[index].rmchrAmt) / GafUtil.toInteger(this.copyLodgD0102[index].lodgDdNum) : 0;  //숙박비
        const rmchrAmt = GafUtil.toInteger(this.grdD0102Data[index].nstLodgAmt ?? (this.copyLodgD0102[index].rmchrAmt > 0 ? GafUtil.toInteger(this.copyLodgD0102[index].rmchrAmt) / GafUtil.toInteger(this.copyLodgD0102[index].lodgDdNum) : 0));  //숙박비
        const totLodg = lodgDdNum * rmchrAmt;
        
        // 숙박일수 * 숙박비
        this.grdD0102Data[index].rmchrAmt = totLodg;
      }
    }
    // else if(column === 'extrlLctrYn') {  //외부강의여부 -> 선택하면 모두 0원 처리
    //   args = args.checked ? 'Y' : 'N';
    //   this.grdD0102Data[index][column] = args;

    //   if(CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo)) {
    //     this.extrlLctrDisabled = args.checked ? true : false;
    //   }
    //   if ('Y' === args) {
    //     this.grdD0102Data[index].trfcAmt = 0;
    //     this.grdD0102Data[index].rmchrAmt = 0;
    //     this.grdD0101Data.atplTrfcAmt = 0;
    //     this.grdD0101Data.mealAmt = 0;
    //     this.grdD0101Data.mealCnt = 0;
        

    //   }else {
    //     this.grdD0102Data[index].trfcAmt = this.copyGrdD0102[index].trfcAmt;

    //     // 기숙사숙박여부 체크에 따른 값 설정
    //     if(this.grdD0102Data[index].drmtLodgYn === 'Y') {
    //       this.grdD0102Data[index].rmchrAmt = 0;
    //     }else {
    //       this.grdD0102Data[index].rmchrAmt = this.copyLodgD0102[index].rmchrAmt;
    //     }

    //     this.grdD0101Data.mealCnt = this.saveParam.bztrpTotDdNum*3;
    //     this.grdD0101Data.mealAmt = this.saveParam.bztrpTotDdNum*3*GafUtil.MEAL_PAY;
    //     this.calAtplTrfcAmtAll();  // 일비계산
    //   }
      
    // }

    if(column === 'drmtLodgYn') {
      // 기숙사숙박여부 계산
      this.fnCalDrmtLodgYn(index);
    }

    if(column === 'extrlLctrYn') {
      // 외부강의여부 계산
      //this.fnCalLctr(index);

      if(CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo) && CommonUtil.isEmpty(this.grdD0102Data[index].sn) && this.grdD0102Data[index].extrlLctrYn === 'Y')  {
        this.fn_autoSaveForMv(index);
      }
    }
    
    this.calcTotAmt();

    const crudgrid: GridUpdateModel = {
      gridData: this.grdD0102Data,
      value: args,
      index: index,
      column: column
    };
    this.commonGridService.gridCrudUpdate(crudgrid);

  }

  /**
   * grdD0102 행 추가
   *
   * @see addRow2()
   */
  grdD0102AddRow(item: Gaf0708D02Data): void {

    this.calcGrdD0102AmtChange();
  }

  /**
   * grdD0102 행 수정
   *
   */
  grdD0102UpdateRow(item: Gaf0708D02Data, IDX: number): void {
  }

  /**
   * grdD0102 행 삭제
   *
   * @see deleteRow2()
   */
  grdD0102RemoveRow(): void {
    this.headerChkGrdD0102 = false;
    this.grdD0102?.clearSelection(); // 직접 구현한 체크박스 사용시 행삭제전 실행

    const obj: GridDeleteModel = {
      gridObj: this.grdD0102
      , gridData :this.grdD0102Data
      , toastObj : this.toastObj
      , apiUrl: '/gaf/gaf0708/01/deleteMv.do' // 저장 요청 url
      , destroy : this.destroy
      , apiComplete: () => { 
        this.calAtplTrfcAmtAll(); //전체일비
        this.calcGrdD0101TrfcAmt(); // 교통비
        this.calcTotAmt(); // 출장비
        // 외부강의 행삭제 일때 경유지 목록 기반으로 제외금액 구해야하기 때문에,
        if(this.saveParam.bztrpShpCd === '5' && CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo)) {
          this.fnGetMvList();
        }
      }
    };

    this.commonGridService.gridDeleteRow(obj).gridCnt;

    // 복사
    this.copyGrdD0102 = JSON.parse(JSON.stringify(this.grdD0102Data));
    this.copyLodgD0102 = JSON.parse(JSON.stringify(this.grdD0102Data));

    // 경유지 그리드 없으면 시내출장 초기화
    if(this.grdD0102Data.length === 0) {
      this.calDdMealAmt();  // 기본 식비 계산
      this.dwntBztrpVisible = false;
    }

    this.calAtplTrfcAmtAll(); //일비
    this.calcGrdD0101TrfcAmt(); // 교통비
    this.calcTotAmt(); // 출장비
    
    
  }

  /**
   * 비용 총합계 계산
   * - (교통비 + 현지교통비 + 일비 + 숙박비 + 식비)
   *
   * @see doTotalAmtValue()
   */
  calcTotAmt(flag:string = ''): void {
    //console.log('calcTotAmt 비용 총합계 계산 >>>>',this.grdD0101Data);

    if (CommonUtil.isEmpty(this.saveParam.trfcMensCd)) {  //교통수단
      this.saveParam.trfcMensCd = '0';
    }

    if (CommonUtil.isNotEmpty(this.grdD0101Data)) {
      this.calcTrxpDdctAmt(flag);   //공제금액계산

      const btrpEmpData = this.grdD0101Data;

      /** 총합계 */
      let totAmt = 0;

      /** 교통금액 traff_amt */
      const trfcAmt = GafUtil.toInteger(btrpEmpData.trfcAmt);
      /** 현지교통금액 cur_trf_exp */
      const atplTrfcAmt = GafUtil.toInteger(btrpEmpData.atplTrfcAmt);
      /** 숙박금액 lodg_exp */
      const lodgAmt = GafUtil.toInteger(btrpEmpData.lodgAmt);
      /** 식사금액 food_exp */
      const mealAmt = GafUtil.toInteger(btrpEmpData.mealAmt);
      /** 항공금액 air_exp */
      //const airAmt = GafUtil.toInteger(btrpEmpData.airAmt);
      /** 신청금액 aprq_amt */
      // let rqstAmt = 0;
      /** 개인지급금액 per_amt */
      let persPrvdAmt = 0;

      // 제외금액
      const xcldCpdAmt = GafUtil.toInteger(btrpEmpData?.xcldCpdAmt??0);
      const xcldTrfcAmt = GafUtil.toInteger(btrpEmpData?.xcldTrfcAmt??0);
      const xcldChfdAmt = GafUtil.toInteger(btrpEmpData?.xcldChfdAmt??0);

      totAmt = trfcAmt + atplTrfcAmt + lodgAmt + mealAmt + (xcldCpdAmt+xcldTrfcAmt+xcldChfdAmt); // 총합계
      persPrvdAmt = trfcAmt + atplTrfcAmt + lodgAmt + mealAmt + (xcldCpdAmt+xcldTrfcAmt+xcldChfdAmt); // 개인지급액(교통비+현지교통비(0원)+일비 + 숙박비 + 식비)

      btrpEmpData.totAmt = totAmt;
      btrpEmpData.persProvdAmt = persPrvdAmt;

      this.saveParam.rqstAmt = totAmt; // 총 출장비
      this.saveParam.persProvdAmt = persPrvdAmt; // 총 개인지급액

      //console.log("총 출장비", this.saveParam.rqstAmt);

    }
  }

  /**
   * 출장비 공제 금액 계산
   * @see calcDeductionExp()
   */
  calcTrxpDdctAmt(flag:string = ''): void {
   // console.log('calcTrxpDdctAmt 출장비 공제 금액 계산');
    /** 공제식사금액 */
    let ddctMealAmt = 0;
    /** 출장총숙박수 */
    const bztrpTotLodgNum = CommonUtil.toInteger(this.saveParam.bztrpTotLodgNum);
    /** 출장0금액여부 */
    const btrp0AmtYn: string = this.saveParam.bztrp0AmtYn ?? 'N';

    /** 출장자 Data */
    const btrpEmpData = this.grdD0101Data;

    // 식비공제가 있는지 확인한 후 ddctMealNum 횟수 저장

    /** 방문기관식사포함수 */
    const vsitInstMealInclNum: number = GafUtil.toInteger(this.saveParam.vsitInstMealInclNum);

    /** 방문기관숙박포함수 */
    const vsitInstLodgInclNum: number = this.saveParam.vsitInstLodgInclNum;

    let extrlLectrCnt = 0;

    // 외부강의 여부 확인
    if(this.saveParam.bztrpShpCd === '5') {
      this.grdD0102Data.forEach((d) => {
        if(d.extrlLctrYn === 'Y') {
          extrlLectrCnt++;
        }
      })
    }

    // 출장 식비 저장---------------------------------------------------------------------------------

    if (CommonUtil.isNotEmpty(this.grdD0101Data) && btrp0AmtYn !== 'Y') {
      // 식비공제 시작

      // 20250305
      // // 외부강의 일 때 0원 처리
      // if(extrlLectrCnt === 1 && this.grdD0102Data.length === 1) {
      //   btrpEmpData.mealAmt = 0;
      //   btrpEmpData.mealCnt = 0;
      // }else {
        // if (vsitInstMealInclNum !== 0) {  //공제항목이 있을 때
          ddctMealAmt = this.saveParam.bztrpTotDdNum * 3 * GafUtil.MEAL_PAY - (vsitInstMealInclNum * GafUtil.MEAL_PAY);
  
          /** 공제된 식비 */
          const rsltDdctMealAmt: number = ddctMealAmt;
          
          if(rsltDdctMealAmt == btrpEmpData.mealAmt) {
            if (rsltDdctMealAmt < 0) {
              // 식비가 0보다 작으면 0으로 계산
              btrpEmpData.mealAmt = 0;
            } else {
              // 식비 공제 
              btrpEmpData.mealAmt = rsltDdctMealAmt;
            }
          }

          if(CommonUtil.isNotEmpty(flag)) {
            btrpEmpData.mealAmt = rsltDdctMealAmt;
            btrpEmpData.mealCnt = this.saveParam.bztrpTotDdNum * 3 - vsitInstMealInclNum;
          }
  
          // 공제 횟수가 N식보다 많을 때 -> 걍 max로 
          if(vsitInstMealInclNum > this.saveParam.bztrpTotDdNum * 3) {
            this.saveParam.vsitInstMealInclNum = this.saveParam.bztrpTotDdNum * 3;
            btrpEmpData.mealAmt = 0;
            btrpEmpData.mealCnt = 0;
            this.commonMessageService.showMsg(this.toastObj, { message: "방문기관 제공 횟수는 최대 식사 횟수를 넘을 수 없습니다.", type: 'W'});
          }
        // }
      // }

    }

    // 외부인&출장일수3일 이상일 경우 식비 직접 수정 처리때문에 추가 2022.07.11
    if(btrpEmpData.imnYn !== 'Y' && this.totDay >= 3) {
      btrpEmpData.mealAmt = this.mealAmt;
    }

    // 숙박일수 검증
    if(bztrpTotLodgNum < vsitInstLodgInclNum) {
      this.saveParam.vsitInstLodgInclNum = 0; 
      this.commonMessageService.showMsg(this.toastObj, { message: "방문기관 제공 횟수는 출장일수를 넘을 수 없습니다.", type: 'W'});
    }

  }

  /**
   * grdD0102의 출발지 도착지 Swap 처리
   *
   * @param number
   * @see plcSwap(event:CommonEvent)
   */
  grdD0102PnNmChange(index: number): void {
    const d0102Data: Gaf0708D02Data = this.grdD0102Data[index];
    const stpnNm = d0102Data.stpnNm;
    const arpnNm = d0102Data.edpnNm;

    d0102Data.stpnNm = arpnNm;
    d0102Data.edpnNm = stpnNm;
  }

  /**
   * 저장 전 체크
   * @see doTrpRqstSaveChk()
   */
  checkBeforeSave(): boolean {
    let validate = false;

    this.saveValid = 'Y';
    validate = CommonUtil.frmValid(this.saveParam, this.toastObj, true);
    if(!validate) {return validate;}

    // 여행명세 경유지 체크
    if (CommonUtil.isEmpty(this.grdD0102Data)) {
      CommonUtil.commonMsg(this.toastObj, '출장지역이 없습니다.', 'W');
      return false;
    }else {
      // 공제 내역 검증
      const bztrpTotLodgNum = this.saveParam.bztrpTotLodgNum;  //출장박수
      const vsitInstLodgInclNum = this.saveParam.vsitInstLodgInclNum;  //숙박비공제횟수
      let lodgDdNum = 0;
      this.grdD0102Data.forEach((d)=>{
        lodgDdNum += GafUtil.toInteger(d.lodgDdNum);
      })

      if(bztrpTotLodgNum - vsitInstLodgInclNum < lodgDdNum) {
        CommonUtil.commonMsg(this.toastObj, '출장지역의 숙박일수를 확인해주세요.', 'W');
        return false;
      }
  
      this.grdD0102Data.forEach((d:any) => {
        if(CommonUtil.isNotEmpty(d.mvBginDt)) {
          if(!(this.saveParam.bztrpBginDt <= d.mvBginDt && d.mvBginDt <= this.saveParam.bztrpEndDt)) {
            CommonUtil.commonMsg(this.toastObj, '출장지역의 일자가 출장정보의 출장기간을 벗어납니다.', 'W');
            validate = false;
            return;
          }
        }else {
          CommonUtil.commonMsg(this.toastObj, '출장지역의 시작일자는 필수입니다.', 'W');
          validate = false;
          return;
        }
        if(CommonUtil.isNotEmpty(d.mvEndDt)) {
          if(!(this.saveParam.bztrpBginDt <= d.mvEndDt && d.mvEndDt <= this.saveParam.bztrpEndDt)) {
            CommonUtil.commonMsg(this.toastObj, '출장지역의 일자가 출장정보의 출장기간을 벗어납니다.', 'W');
            validate = false;
            return;
          }
        }else {
          CommonUtil.commonMsg(this.toastObj, '출장지역의 종료일자는 필수입니다.', 'W');
          validate = false;
          return;
        }
      })
      
      if(!validate) {return false;}

      let cnt1 = 0;
      let cnt2 = 0;
      this.grdD0102Data.forEach((d:any) => {
        // 첫째날과 마지막날이 있는지 확인
        if(this.saveParam.bztrpBginDt === d.mvBginDt) {
          cnt1++;
        }
        if(this.saveParam.bztrpEndDt === d.mvEndDt) {
          cnt2++;
        }
      })
  
      // 둘 중 하나라도 0이면 첫째날과 마지막날이 없는것
      if(cnt1 === 0 || cnt2 === 0) {
        CommonUtil.commonMsg(this.toastObj, '출장정보의 출장기간이 출장지역의 일자에 없습니다.', 'W');
        validate = false;
        return validate;
      }
      
      for(let i=0; i < this.grdD0102Data.length; i++)  {
        if(CommonUtil.isEmpty(this.grdD0102Data[i].bstaNm)) {
          this.commonMessageService.showMsg(this.toastObj, { message: '목적지(기관)은 필수입니다.', type: 'W'});
          return false;
        }else {
          if(CommonUtil.isEmpty(this.grdD0102Data[i].bztrpCntn)) {
            this.commonMessageService.showMsg(this.toastObj, { message: '출장내역은 필수입니다.', type: 'W'});
            return false;
          }
        }
      }

      // this.grdD0102Data.forEach((item:any) => {
      //   if(CommonUtil.isEmpty(item.bstaNm)) {
      //     this.commonMessageService.showMsg(this.toastObj, { message: '목적지(기관)은 필수입니다.', type: 'W'});
      //     validate = false;
      //     return;
      //   }else {
      //     if(CommonUtil.isEmpty(item.bztrpCntn)) {
      //       this.commonMessageService.showMsg(this.toastObj, { message: '출장내역은 필수입니다.', type: 'W'});
      //       validate = false;
      //       return;
      //     }
      //   }
      //   if(!validate) {return;}
      // }) 
      
    }

    return validate;
    // } else {
    //   CommonUtil.commonMsg(this.toastObj, CommonUtil.crudMsg01, 'W');
    //   Object.keys(this.form0101.controls).forEach((field) => {
    //     const control = this.form0101.get(field);
    //     control?.markAsDirty();
    //     control?.markAsTouched();
    //   });
    //   return false;
    // }

    // return true;
  }

  /*-----------------  Event Handler End  -----------------*/

  /*-----------------  Button Handler Start  -----------------*/

  /**
   * 저장 버튼 클릭 이벤트 처리
   * @see doTrpRqstSaveProcedure()
   */
  btnSave(misApprvStatCd : string = ''): void {

    // 출장기간은 필수, 빈값을 임시저장하면 다시 불러올 수 없다. 검색조건에 걸림.
    if(CommonUtil.isEmpty(this.saveParam.bztrpBginDt) && CommonUtil.isEmpty(this.saveParam.bztrpEndDt)) {
      this.commonMessageService.showMsg(this.toastObj, { message: '출장기간은 필수입니다.', type: 'W'});
      return;
    }

    if('01'!==misApprvStatCd) {  // 임시저장이 아닐 때만 검증
      if (!this.checkBeforeSave()) { return; }
    }
    this.saveForm0101(misApprvStatCd);
  }

  /**
   * 삭제 버튼 클릭 이벤트 처리
   */
  btnDelete(): void {
    this.deleteform0101('N');
  }

  /**
   * 담당자 취소 버튼 클릭 이벤트 처리
   */
  btnCrgrCncl(): void {
    this.openCrgrCnclDialog();
  }

  /**
   * 닫기 버튼 클릭 이벤트 처리
   */
  btnClose(): void {
    CommonUtil.windowClose();
  }

  /**
   * 행추가 버튼 클릭 이벤트 처리
   */
  btnGrdD0103AddRow(): void {
    this.grdD0103AddRow();
  }

  /**
   * 행삭제 버튼 클릭 이벤트 처리
   */
  btnGrdD0103RemoveRow(): void {
    this.grdD0103RemoveRow();
  }

  /**
   * 엑셀 버튼 클릭 이벤트 처리
   */
  btnGrdD0103Excel(): void {
    this.grdD0103ExcelExport();
  }

  /**
   * 엑셀 버튼 클릭 이벤트 처리
   */
  btnGrdD0101Excel(): void {
    // this.grdD0101
  }

  /**
   * 행추가 버튼 클릭 이벤트 처리
   */
  btnGrdD0102AddRow(): void {
    let validate = true;

    if(CommonUtil.isNotEmpty(this.grdD0102Data)) {
      this.grdD0102Data.forEach((d) => {
        if(d.stpnCd === d.arpnCd && this.saveParam.bztrpShpCd !== '5') {  // 시내출장
          this.commonMessageService.showMsg(this.toastObj, { message: '시내출장은 한 건만 등록할 수 있습니다.', type: 'W'});
          validate = false;
        }
      });
    }
    
    if(validate) { this.openGaf070815Dialog(new Gaf0708D02Data()); }

  }

  /**
   * 행삭제 버튼 클릭 이벤트 처리
   */
  btnGrdD0102RemoveRow(): void {
    this.grdD0102RemoveRow();
  }

  /**
   * 엑셀 버튼 클릭 이벤트 처리
   */
  btnGrdD0102Excel(): void {
    this.grdD0102ExcelExport();
  }

  /**
   * NST API 연동
   * @param index
   */
  btnNstApiTrfcAmt(index: number): void {
    this.openNstApiTrfcAmt(index);
  }

  
  //메세지 토스트(알림)
  toastEmit(args: any) {
    this.toastObj = args;
  }

  
  // 다이얼로그 OPEN
  fn_dialog(flag: any) {
    const dialogConfig = new CommonMatDialogConfig();
    dialogConfig.panelClass = ['modal-center'];
    dialogConfig.data = { PGM_ID: 'gaf0708' };
    
    if(flag === 'meal') {
      dialogConfig.width = '500px';
      dialogConfig.height = '450px';
      this.dialog.open(Gaf0708mComponent, dialogConfig); 
    }else if(flag === 'daily') {
      dialogConfig.width = '700px';
      dialogConfig.height = '400px';
      this.dialog.open(Gaf0708dpComponent, dialogConfig); 
    }else if(flag === 'xTrfc' || flag === 'xCpd' || flag === 'xChfd') {
      dialogConfig.width = '520px';
      dialogConfig.height = '230px';
      dialogConfig.data = flag;
      this.dialog.open(Gaf0708m2Component, dialogConfig); 
    }
  }

  // 시간계산, 교통수단 검색할때
  fn_calTime() {
    let time = 0;

    const nLstt = '1200'; // 점심시작시간
    const nLend = '1300'; // 점심종료시간
    
    let choiceBginHh = '';
    let choiceEndHh = '';
    choiceBginHh = this.grdD0102Data[0].dwntBztrpBginHh;
    choiceEndHh = this.grdD0102Data[0].dwntBztrpEndHh;
    
    if(this.dwntBztrpVisible && CommonUtil.isNotEmpty(choiceBginHh) && CommonUtil.isNotEmpty(choiceEndHh)) {
      let stTemp = '';
      let edTemp = '';
      
      if(choiceBginHh <= nLend && choiceEndHh >= nLstt) {
        if(choiceEndHh >= nLend) { 
          stTemp = nLend;
        }else {
          stTemp = choiceEndHh;
        }

        if(choiceBginHh <= nLstt) {
          edTemp = nLstt;
        }else {
          edTemp = choiceBginHh;
        }

      }else {
        stTemp = '0';
        edTemp = '0';
      }

      time = (Number(choiceEndHh) - Number(choiceBginHh)) - (Number(stTemp) - Number(edTemp))
      time = time/100;
    }

    return time;

  }

  // 식비
  fn_calMeal(flag:any) {
    let mealAmt = 0;
    let mealCnt = this.grdD0101Data.mealCnt;
    if(flag === '+') {
      mealAmt = this.grdD0101Data.mealAmt + GafUtil.MEAL_PAY;
      mealCnt = mealCnt +1;
    }else if(flag === '-') {
      mealAmt = this.grdD0101Data.mealAmt - GafUtil.MEAL_PAY;
      mealCnt = mealCnt -1;
    }

    if(mealAmt <= this.calMealMax().ddMaxAmt && mealCnt >= 0) {
      this.grdD0101Data.mealCnt = mealCnt;
      this.grdD0101Data.mealAmt = mealAmt;
    }
    
  }

  //유연근무제 신청 정보
  fn_ftmInfo(index:number) {
    const param = {bztrpEmpNo: this.grdD0101Data.bztrpEmpNo , bztrpEndDt: this.saveParam.bztrpEndDt};
    this.commonHttpService
      .get('/gaf/gaf0708/getFtmInfo.do', param).pipe(takeUntil(this.destroy)).subscribe({
        next: (response : any) => {
          if (CommonUtil.isNotEmpty(response)) {
            //console.log(response.body);
            const result = response.body;
            if(CommonUtil.isNotEmpty(result)) {
              this.grdD0102Data[index].dwntBztrpBginHh = result[0].choiceBginHh;
              this.grdD0102Data[index].dwntBztrpEndHh = result[0].choiceEndHh;
              this.saveParam.bginHh = result[0].choiceBginHh;
              this.saveParam.endHh = result[0].choiceEndHh;
            }else {
              this.grdD0102Data[index].dwntBztrpBginHh = '0830';
              this.grdD0102Data[index].dwntBztrpEndHh = '1730';
              this.saveParam.bginHh = '0830';
              this.saveParam.endHh = '1730';
            }
          }
        }, 
        error: (error: any) => {
          this.commonMessageService.showSaveMsg(this.toastObj, error);
        },
        complete: () => {
          this.calAtplTrfcAmtAll();
        }
      })
  }


  // 교통수단에 따른 계산
  fnCalVecl() {
    const veclYn = this.saveParam.trfcMensCd;
    if(veclYn === '7') { //공용
      // 교통비 0원
      // 경유지 요금 0원
      this.grdD0102Data.forEach((d)=>{
        d.trfcAmt = 0;
      })
      
       //일비확인
       this.calAtplTrfcAmtAll();  // 일비계산
    }else {  //일반
      if(this.saveParam.bztrp0AmtYn == 'Y') {
        this.grdD0102Data.forEach((d) => {
          d.rmchrAmt = 0;
          d.trfcAmt = 0;
          d.atplTrfcAmt = 0;
        }) 
      }else {

        //외부강의여부에 확인
        for (let index = 0; index < this.grdD0102Data.length; index++) {
          if(this.grdD0102Data[index].drmtLodgYn ==='Y' 
          // || this.grdD0102Data[index].extrlLctrYn ==='Y'  //20250305
          ) {
            this.grdD0102Data[index].rmchrAmt = 0;
            this.grdD0102Data[index].lodgDdNum = 0;
          }
          // if(this.grdD0102Data[index].extrlLctrYn ==='Y') {   //20250305
          //   this.grdD0102Data[index].trfcAmt = 0;
          // }else {
            this.grdD0102Data[index].trfcAmt = this.copyGrdD0102[index].trfcAmt;
          // }
        }

        //일비확인
        this.calAtplTrfcAmtAll();  // 일비계산
      }
    }
  }

  //기숙사숙박여부에 따른 계산
  fnCalDrmtLodgYn(index:number) {
    const drmtLodgYn = this.grdD0102Data[index].drmtLodgYn;

    if(drmtLodgYn === 'Y') {
      // 해당 로우의 숙박비를 0 처리
      this.grdD0102Data[index].rmchrAmt = 0;
      //this.grdD0102Data[index].lodgDdNum = 0;
    }else {
      //n일때
      //0원 출장여부 확인
      //외부강의여부 확인
      //공용이면 요금 0원
      if(this.saveParam.bztrp0AmtYn == 'Y') {
        this.grdD0102Data[index].rmchrAmt = 0;
        this.grdD0102Data[index].trfcAmt = 0;
        //this.grdD0102Data[index].lodgDdNum = 0;
      }else {
        // if(this.grdD0102Data[index].extrlLctrYn === 'Y') {  // 외부강의 여부   20250305
        //   this.grdD0102Data[index].rmchrAmt = 0;
        // }else {
          //this.grdD0102Data[index].lodgDdNum = this.grdD0102Data[index].lodgDdNum == 0 ? 1 : this.grdD0102Data[index].lodgDdNum;
          //this.grdD0102Data[index].rmchrAmt = this.copyLodgD0102[index].rmchrAmt * this.grdD0102Data[index].lodgDdNum;
          this.grdD0102Data[index].rmchrAmt = 
            GafUtil.toInteger(this.grdD0102Data[index].nstLodgAmt ?? (this.copyLodgD0102[index].rmchrAmt > 0 ? GafUtil.toInteger(this.copyLodgD0102[index].rmchrAmt) / GafUtil.toInteger(this.copyLodgD0102[index].lodgDdNum) : 0)) * GafUtil.toInteger(this.grdD0102Data[index].lodgDdNum);
        // }
      }

    }

    let rmchrAmt : number = 0;
      this.grdD0102Data.forEach((d) => {
        rmchrAmt += Number(d.rmchrAmt);
      });
      // 출장자내역의 숙박비에 적용
      this.grdD0101Data.lodgAmt = rmchrAmt;

  }

  //외부강의여부에 따른 계산
  fnCalLctr(index:number) {
    const extrlLctrYn = this.grdD0102Data[index].extrlLctrYn;
    // y면 모두 0원처리
    if(extrlLctrYn === 'Y') {
      this.grdD0102Data[index].trfcAmt = 0;
      this.grdD0102Data[index].rmchrAmt = 0;
      //this.grdD0102Data[index].lodgDdNum = 0;

      if(this.grdD0102Data.length === 1) {
        this.grdD0101Data.mealAmt = 0;
        this.grdD0101Data.mealCnt = 0;
        this.grdD0101Data.atplTrfcAmt = 0;
        this.grdD0101Data.lodgAmt = 0;
      }

    }else {
      //n일때
      //교통수단 확인
      //0원 출장여부 확인
      if(this.saveParam.bztrp0AmtYn == 'Y') {
        this.grdD0102Data[index].trfcAmt = 0;
        this.grdD0102Data[index].rmchrAmt = 0;
        //this.grdD0102Data[index].lodgDdNum = 0;
      }else {
        //기숙사숙박여부 확인
        // 기숙사숙박여부 체크에 따른 값 설정
        if(this.grdD0102Data[index].drmtLodgYn === 'Y') {
          this.grdD0102Data[index].rmchrAmt = 0;
          //this.grdD0102Data[index].lodgDdNum = 0;
        }else {
          //this.grdD0102Data[index].lodgDdNum = this.grdD0102Data[index].lodgDdNum == 0 ? 1 : this.grdD0102Data[index].lodgDdNum;
          // this.grdD0102Data[index].rmchrAmt = this.copyLodgD0102[index].rmchrAmt * this.grdD0102Data[index].lodgDdNum;
          this.grdD0102Data[index].rmchrAmt = 
            GafUtil.toInteger(this.grdD0102Data[index].nstLodgAmt ?? (this.copyLodgD0102[index].rmchrAmt > 0 ? GafUtil.toInteger(this.copyLodgD0102[index].rmchrAmt) / GafUtil.toInteger(this.copyLodgD0102[index].lodgDdNum) : 0)) 
            * GafUtil.toInteger(this.grdD0102Data[index].lodgDdNum);
        }
        
        // 교통수단 확인
        if(this.grdD0102Data[index].trfcMensCd === '7') {
          this.grdD0102Data[index].trfcAmt = 0;
        }else {
          this.grdD0102Data[index].trfcAmt = this.copyGrdD0102[index].trfcAmt;
        }

        // 시내출장 아닐때
        if(this.grdD0102Data[index].stpnCd !== this.grdD0102Data[index].arpnCd) {
          // 식비
          const vsitInstMealInclNum = this.saveParam.vsitInstMealInclNum ?? 0;  //제공식사
          this.grdD0101Data.mealCnt = this.saveParam.bztrpTotDdNum*3-vsitInstMealInclNum;
          this.grdD0101Data.mealAmt = (this.grdD0101Data.mealCnt)*GafUtil.MEAL_PAY;
        }

        // 일비계산
        this.calAtplTrfcAmtAll(); 
        this.calcTotAmt(); 
      }

    }


  }


  calDdMealAmt() {  // 하루 식비 계산

    // 출장기간 확인
    const ddNum = GafUtil.toInteger(this.saveParam.bztrpTotDdNum);
    const ddCount = ddNum *3; // n식
    const ddMaxAmt = ddCount * GafUtil.MEAL_PAY;  // 일일 최대 금액

    // 공제 확인
    const vsitInstMealInclNum = GafUtil.toInteger(this.saveParam.vsitInstMealInclNum); // 방문기관 식사제공
    const visitAmt = GafUtil.MEAL_PAY * vsitInstMealInclNum; // 공제 금액
    
    if(CommonUtil.isNotEmpty(this.grdD0101Data)) {
      this.grdD0101Data.mealCnt = ddCount - vsitInstMealInclNum;
      this.grdD0101Data.mealAmt = ddMaxAmt - visitAmt;
    }

  }

  calMealMax() {
    const ddMaxNum = GafUtil.toInteger(this.saveParam.bztrpTotDdNum) * 3 - GafUtil.toInteger(this.saveParam.vsitInstMealInclNum);
    const ddMaxAmt = GafUtil.MEAL_PAY * ddMaxNum;

    return {'ddMaxNum':ddMaxNum, 'ddMaxAmt':ddMaxAmt};
  }

  createdD0102(): void {
    this.grdD0102Height = 150;
  }

  // 배차신청 팝업 오픈
  fn_veclRqst() {

    const allocRqstNo = this.saveParam.allocRqstNo;
    
    this.commonHttpService.get('/gaf/gaf0501/getChkAlloc.do',{}).pipe(takeUntil(this.destroy)).subscribe({
      next: (response: any) => {
        if(response.body.success) {
          this.btnPopup(allocRqstNo);
        }else{
          this.commonMessageService.showSaveMsg(this.toastObj, response);
        }
        //this.fnGetGrdR01();
      },
      error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      },
      complete: () => {
        
      }
    });

  }

  // 신규 팝업
  btnPopup(allocRqstNo: string = '') {

    this.saveParam.allocRqstNo = allocRqstNo;
    const obj = { url : '/popup/gaf/gaf050101', width: 1400, height: 800, target: 'gaf050101', param: {allocRqstNo} };

    const popup = CommonUtil.openWindowPopup(obj);
    if (popup) {
      this.unlistener = this.renderer2.listen(popup, 'message', (e) => {
        if (e.origin === location.origin && CommonUtil.isNotEmpty(e.data.allocRqstNo)) {  // 배차신청번호
          // TODO 출장 테이블에 배차신청 pk update 해주기
          const allocRqstNo = e.data.allocRqstNo;
          this.saveParam.allocRqstNo = allocRqstNo;
          this.fnAllocUpdate();

        } else if(e.origin === location.origin && e.data === 'delete') {
          this.commonMessageService.showMsg(this.toastObj, { message: message.com_succ_delete});
          this.saveParam.allocRqstNo = '';
          this.fnAllocUpdate();

        }
      });
    }
  }

  /** 배차신청 pk 저장 */
  fnAllocUpdate() {
    this.commonHttpService.post('/gaf/gaf0708/01/updateAlloc.do', this.saveParam).pipe(takeUntil(this.destroy)).subscribe({
      next: (response:any) => {
        //this.commonMessageService.showSaveMsg(this.toastObj, response);
      }
      ,error: (error: any) => {
        this.commonMessageService.showSaveMsg(this.toastObj, error);
      }
    })

  }



  // 출장신청번호 존재, sn이 없고, 외부강의 y 일때 -> 저장
  fn_autoSaveForMv(index:any) {
    if(CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo) && CommonUtil.isEmpty(this.grdD0102Data[index].sn) && 
       this.grdD0102Data[index].extrlLctrYn === 'Y') {
        this.grdD0102Data[index].bztrpRqstNo = this.saveParam.bztrpRqstNo;
        const param = this.grdD0102Data[index];

        this.commonHttpService.post('/gaf/gaf0708/01/savemvlist.do', param).pipe(takeUntil(this.destroy)).subscribe({
          next: (response : any) => {
            if(CommonUtil.isNotEmpty(response)) {
              this.grdD0102Data[index].sn = response.body.results.sn;
            }
          },error: (error: any) => {
            //this.commonMessageService.showSaveMsg(this.toastObj, error);
          },complete: () => {
            this.grdD0102Data[index].crud = 'U';
          }
        })
        //todo 저장
        
    }
  }
  
  // 일단 킵;;
  // 이미 저장하여 nst 정보가 없을 때 (출장신청번호 존재, sn이 있을 때) -> 교통수단, 숙박비에 필요 (기숙사숙박여부, 숙박일수)
  fn_getNstInfoForMv(index:any) {
    if(CommonUtil.isNotEmpty(this.saveParam.bztrpRqstNo) && CommonUtil.isNotEmpty(this.grdD0102Data[index].sn)) {
      // nst조회
      const param = {
        startCityCode : this.grdD0102Data[index].stpnCd,
        endCityCode : this.grdD0102Data[index].arpnCd
      }

    let respObj: any;

    this.commonHttpService.get('/gaf/com/getnstpath.do', param).pipe(takeUntil(this.destroy)).subscribe({
        next: (response : any) => {
          if(CommonUtil.isNotEmpty(response.body)) {
            respObj = response.body;
          } else {
            this.commonMessageService.showSaveMsg(this.toastObj, response); // Exception 메시지 처리
          }
        },
        error: () => { 
          this.commonMessageService.showMsg(
            this.toastObj,
            {message:'NST에서 해당 경로의 운임비를 조회하지 못 하였습니다. <br/> 직접 입력해주세요.',
            type:'W'}
          );
        },
        complete: () => {
          
          if(this.grdD0102Data[index].chaeDivCd === 'A') { // 왕복
            if(this.grdD0101Data.scpsGrdCd == '1' || this.grdD0101Data.scpsGrdCd == '0') {  // 신분등급코드 책임급, 소장급
              this.grdD0102Data[index].trfcAmt = respObj.sppayment*2;  // 특실요금
            }else {
              this.grdD0102Data[index].trfcAmt = respObj.payment*2;    // 요금
            }
          }else if(this.grdD0102Data[index].chaeDivCd === 'B'){ // 편도
            if(this.grdD0101Data.scpsGrdCd == '1' || this.grdD0101Data.scpsGrdCd == '0') {  // 신분등급코드 책임급, 소장급
              this.grdD0102Data[index].trfcAmt = respObj.sppayment; // 특실요금
            }else {
              this.grdD0102Data[index].trfcAmt = respObj.payment;   // 요금
            }
          }

          //this.rowData.chaeDivCd = 'A'; // 요금구분
          this.grdD0102Data[index].rmchrAmt = respObj.rmchrAmt;   //숙박비
          
        }
      });

    }
  }

  fnCalDate(index:any) {

    const bgnDt = this.grdD0102Data[index]?.mvBginDt;
    const endDt = this.grdD0102Data[index]?.mvEndDt;

    if(CommonUtil.isEmpty(bgnDt) || CommonUtil.isEmpty(endDt)) {
      CommonUtil.commonMsg(this.toastObj,
        '시작일자 또는 종료일자를 입려해주세요.',
        'W'
      );
      return;
    }

    const bgnDate: Date = new Date(CommonDate.getFormattedDate(bgnDt)); // 시작일 Date 객체
    const endDate: Date = new Date(CommonDate.getFormattedDate(endDt)); // 종료일 Date 객체

    const oneDay: number = 1000 * 60 * 60 * 24;

    const bztrpTotDdNum: number = (endDate.getTime() - bgnDate.getTime() + oneDay) / oneDay;
    this.totDay = bztrpTotDdNum; // 외부인&출장일수3일 이상일 경우 식비 직접 수정 처리때문에 추가 2022.07.11
    const bztrpTotLodgNum: number = bztrpTotDdNum - 1;

    return bztrpTotDdNum;  //n일

  }

  /*-----------------  Button Handler End  -----------------*/
}


/**
 * 기간 Validator
 * @param control
 * @returns
 */
export const bztrpDtRangeValidator: ValidatorFn = (
  control: AbstractControl
): ValidationErrors | null => {
  const bgnDt = control.get('bztrpBginDt');
  const endDt = control.get('bztrpEndDt');

/*   const bgnDate = new Date(this.commonDateService.getFormattedDate(bgnDt?.value)); // 시작일 Date 객체
  const endDate = new Date(this.commonDateService.getFormattedDate(endDt?.value)); // 종료일 Date 객체 */

  return  null; 
};






profile
ㅎㅇㅎㅇ

0개의 댓글