Commit 0617e985 by Natthaphat

เพิ่มเมนู เปิด-ปิด การใช้รายงาน Excel

parent 115771a8
...@@ -123,6 +123,11 @@ export const admin: Routes = [ ...@@ -123,6 +123,11 @@ export const admin: Routes = [
loadComponent: () => loadComponent: () =>
import('./myportal/datasource-table/datasource-table.component').then((m) => m.DatasourceTableComponent), import('./myportal/datasource-table/datasource-table.component').then((m) => m.DatasourceTableComponent),
}, },
{
path: 'excel-report-toggle',
loadComponent: () =>
import('./myportal/set-excel-reports/excel-report-toggle/excel-report-toggle.component').then((m) => m.ExcelReportToggleComponent),
},
//////////////emp///////////////// //////////////emp/////////////////
{ {
path: 'emp/department', path: 'emp/department',
......
...@@ -217,6 +217,14 @@ ...@@ -217,6 +217,14 @@
</div> </div>
<div class="box-footer"> <div class="box-footer">
<div class="flex items-center flex-wrap overflow-auto" *ngIf="template.filter.length > 0"> <div class="flex items-center flex-wrap overflow-auto" *ngIf="template.filter.length > 0">
<div class="d-flex justify-content-end p-2">
<select class="custom-select m-r-5 border-color-gray-full-focus" style="width: auto"
[(ngModel)]="pageSize" (ngModelChange)="page">
<option *ngFor="let item of [10,50,100]" [ngValue]="item">
{{"รายการต่อหน้า"}}: {{item}}
</option>
</select>
</div>
<div class="mb-2 sm:mb-0"> <div class="mb-2 sm:mb-0">
<div> <div>
{{'Showing' | translate}} {{template.filter.length}} {{'entries' {{'Showing' | translate}} {{template.filter.length}} {{'entries'
...@@ -801,7 +809,7 @@ ...@@ -801,7 +809,7 @@
ngbDatepicker #d1="ngbDatepicker" [(ngModel)]="select[item.key]" ngbDatepicker #d1="ngbDatepicker" [(ngModel)]="select[item.key]"
readonly (click)="d1.toggle()" readonly (click)="d1.toggle()"
(ngModelChange)="formatNgbDate(item.key, select[item.key])" (ngModelChange)="formatNgbDate(item.key, select[item.key])"
#c1="ngModel" (change)="validateDate(c1)"> #c1="ngModel" (change)="validateDate(c1)" container="body">
<!-- Calendar Button --> <!-- Calendar Button -->
<button type="button" <button type="button"
...@@ -943,7 +951,7 @@ ...@@ -943,7 +951,7 @@
<div class="flex items-center flex-wrap overflow-auto" *ngIf="valueDetailFilter().length > 0"> <div class="flex items-center flex-wrap overflow-auto" *ngIf="valueDetailFilter().length > 0">
<div class="d-flex justify-content-end p-2"> <div class="d-flex justify-content-end p-2">
<select class="custom-select m-r-5 border-color-gray-full-focus" style="width: auto" <select class="custom-select m-r-5 border-color-gray-full-focus" style="width: auto"
[(ngModel)]="pageSizeModal" (ngModelChange)="pageModal=1"> [(ngModel)]="pageSizeModal" (ngModelChange)="pageModal">
<option *ngFor="let item of [10,50,100]" [ngValue]="item"> <option *ngFor="let item of [10,50,100]" [ngValue]="item">
{{"Items per page"}}: {{item}} {{"Items per page"}}: {{item}}
</option> </option>
......
<app-page-header [title]="'เปิด-ปิด การใช้รายงาน Excel'" [activeTitle]="'ผู้ดูแลระบบ'"
[title1]="'เปิด-ปิด การใช้รายงาน Excel'"></app-page-header>
<div class="grid grid-cols-12 gap-6">
<div class="xl:col-span-12 col-span-12">
<div class="box">
<div class="box-header justify-between">
<div class="box-title">
รายการเอกสาร
</div>
<div class="flex flex-wrap gap-4">
<!-- Search By -->
<div class="d-flex flex-column" style="min-width: 200px;">
<label class="mb-1 font-medium text-sm">Search By</label>
<select class="form-control h-100" [(ngModel)]="searchBy">
<option style="color: red" [class.d-none]="searchBy==''" [value]="''">
{{searchBy!=''?'ยกเลิก':'--- เลือก ---'}}</option>
<option [value]="'templateId'">รหัสกลุ่มแม่แบบ</option>
<option [value]="'module'">โมดูล</option>
<option [value]="'tname'">ชื่อกลุ่มรายงาน (ภาษาไทย)</option>
<option [value]="'ename'">ชื่อกลุ่มรายงาน (ภาษาอังกฤษ)</option>
<option [value]="'tdesc'">รายละเอียด (ภาษาไทย)</option>
<option [value]="'edesc'">รายละเอียด (ภาษาอังกฤษ)</option>
</select>
</div>
<!-- Condition -->
<div class="d-flex flex-column" style="min-width: 200px;">
<label class="mb-1 font-medium text-sm">Condition</label>
<select class="form-control h-100" [(ngModel)]="condition">
<option style="color: red" [class.d-none]="condition==''" [value]="''">
{{condition!=''?'ยกเลิก':'--- เลือก ---'}}</option>
<option value="includes">คำในประโยค</option>
<option value="lt">น้อยกว่า</option>
<option value="gt">มากกว่า</option>
<option value="eq">เท่ากับ</option>
<option value="lte">น้อยกว่าเท่ากับ</option>
<option value="gte">มากกว่าเท่ากับ</option>
<option value="neq">ไม่เท่ากับ</option>
</select>
</div>
<!-- Key Value -->
<div class="d-flex flex-column" style="min-width: 200px;">
<label class="mb-1 font-medium text-sm">Key Value</label>
<input class="form-control h-100" type="text" placeholder="ค้นหา"
aria-label=".form-control-sm example" [(ngModel)]="searchValue">
</div>
<!-- Buttons -->
<div class="flex items-end gap-2">
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-primary-full"
style="margin-bottom: unset;" (click)="openTemplate.clear();templateListSearch()">
<i class="ri-search-line font-semibold align-middle"></i>ค้นหา
</a>
<!-- <a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-success-full"
style="margin-bottom: unset;" (click)="openAddGroupModal()">
<i class="ri-add-line font-semibold align-middle"></i>Add Group
</a> -->
</div>
</div>
</div>
<div class="box-body">
<div class="table-responsive">
<table class="table whitespace-nowrap min-w-full ti-custom-table-hover ">
<thead class="bg-info text-white">
<tr>
<th class="text-center" scope="col">ชื่อกลุ่มรายงาน(Thai)</th>
<th class="text-center" scope="col">ชื่อกลุ่มรายงาน (ภาษาอังกฤษ)</th>
<th class="text-center" scope="col" style="min-width: 200px">สร้างโดย</th>
<th class="text-center" scope="col" style="min-width:120px">วันที่สร้าง</th>
<th class="text-center" scope="col">สร้างเมื่อ</th>
<th class="text-center" scope="col" style="min-width: 120px;">โมดูล</th>
<th class="text-center" scope="col">Add file</th>
</tr>
</thead>
<tbody *ngIf="!template.filter.length">
<tr style="background-color:#ebf2f6">
<td colspan="7" class="text-center">ไม่พบข้อมูล</td>
</tr>
</tbody>
<tbody id="tableBody" *ngIf="isSearching || template.filter.length">
<tr *ngIf="isSearching">
<td colspan="7" class="loading">
<div class="spinner"></div>
<div class="spinner"></div>
<div class="spinner"></div>
<span>กำลังค้นหา...</span>
</td>
</tr>
<ng-container *ngIf="!isSearching">
<ng-container
*ngFor="let items of template.filter | slice: page * pageSize : (page+1) * pageSize ; let i = index">
<tr (mouseenter)="tableHover.set(items.templateId,!tableHover.get(items.templateId))"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background-color':tableHover.get(items.templateId)?'rgb(201 223 235)':'#ebf2f6'}">
<td colspan="6" class="font-16 font-medium">
{{items.tname}}<span *ngIf="items.tdesc">
-{{items.tdesc}}
</span>
</td>
<td class="text-center">
<ng-container *ngIf="items.templateFile.length">
<ng-container *ngIf="!openTemplate.get(items.templateId)">
<button type="button" title="เปิด" (click)="
openTemplate.set(items.templateId,true)"
(mouseenter)="buttonHover.set(items.templateId+'open',!buttonHover.get(items.templateId))"
(mouseleave)="buttonHover.clear()"
class="ti-btn ti-btn-wave !gap-0 !m-0 bg-info/10 text-info hover:bg-info hover:text-white hover:border-info">
<i class="ri-arrow-right-line"></i>
</button>
</ng-container>
<ng-container *ngIf="openTemplate.get(items.templateId)">
<button type="button" title="ปิด" (click)="
openTemplate.set(items.templateId,false)"
(mouseenter)="buttonHover.set(items.templateId+'close',!buttonHover.get(items.templateId))"
(mouseleave)="buttonHover.clear()"
class="ti-btn ti-btn-wave !gap-0 !m-0 bg-info/10 text-info hover:bg-info hover:text-white hover:border-info">
<i class="ri-arrow-down-line"></i>
</button>
</ng-container>
</ng-container>
</td>
</tr>
<ng-container *ngIf="openTemplate.get(items.templateId)">
<ng-container
*ngFor="let item of items.templateFile | slice: page * pageSize : (page+1) * pageSize ; let i = index">
<tr (mouseenter)="tableHover.set(item.fileName,!tableHover.get(item.fileName))"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background-color':tableHover.get(item.fileName)?'rgb(201 223 235)':'#ffffff'}">
<td style="white-space: normal !important;word-break: break-word;">
{{item.tdesc}}
</td>
<td style="white-space: normal !important;word-break: break-word;">
{{item.edesc}}</td>
<td class="text-center"
style="white-space: normal !important;word-break: break-word;">
<!-- {{item.createBy.thFullName}}</td> -->
<td class="text-center"
style="white-space: normal !important;word-break: break-word;">
{{formatISOToLocal(item.createDate).date}}</td>
<td class="text-center"
style="white-space: normal !important;word-break: break-word;">
{{formatISOToLocal(item.createDate).time}}</td>
<td class="text-center"
style="white-space: normal !important;word-break: break-word;">
{{item.module}}</td>
<td class="text-center">
<i *ngIf="item.menuActive=='0'"
class="fa fa-times text-danger cursor-pointer"
style="text-decoration: underline; font-size: medium;"
(click)="menuActiveTemplateFile(item)"></i>
<i *ngIf="item.menuActive=='1'"
class="fa fa-check text-success cursor-pointer"
style="text-decoration: underline; font-size: medium;"
(click)="menuActiveTemplateFile(item)"></i>
&nbsp;
<a aria-label="anchor" title="Print"
(mouseenter)="buttonHover.set(item.fileName+'print',!buttonHover.get(item.fileName))"
(mouseleave)="buttonHover.clear()"
class="ti-btn ti-btn-wave product-btn !gap-0 !m-0 bg-warning/10 text-warning hover:bg-warning hover:text-white hover:border-warning"
(click)="openPrintModal(item);">
<i class="ri-printer-line"></i></a>
</td>
</tr>
</ng-container>
</ng-container>
</ng-container>
</ng-container>
</tbody>
</table>
</div>
</div>
<div class="box-footer">
<div class="flex items-center flex-wrap overflow-auto" *ngIf="template.filter.length > 0">
<div class="d-flex justify-content-end p-2">
<select class="custom-select m-r-5 border-color-gray-full-focus" style="width: auto"
[(ngModel)]="pageSize" (ngModelChange)="page">
<option *ngFor="let item of [10,50,100]" [ngValue]="item">
{{"รายการต่อหน้า"}}: {{item}}
</option>
</select>
</div>
<div class="mb-2 sm:mb-0">
<div>
{{'Showing' | translate}} {{template.filter.length}} {{'entries'
| translate}} <i class="bi bi-arrow-right ms-2 font-semibold"></i>
</div>
</div>
<div class="ms-auto">
<nav aria-label="Page navigation">
<ul class="ti-pagination mb-0">
<li *ngIf="page > 0" class="page-item {{page==0 ? 'disabled' : ''}}"><a
class="page-link px-3 py-[0.375rem] cursor-pointer"
(click)="page = page - 1; updatePagedItems()">{{'Previous' | translate}}</a>
</li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="page > 0" (click)="page = page - 1; updatePagedItems()">{{page}}</a>
</li>
<li class="page-item"><a class="page-link active px-3 py-[0.375rem]"
href="javascript:void(0);">{{page + 1}}</a>
</li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="(page + 1) * pageSize < template.filter.length"
(click)="page = page + 1; updatePagedItems()">{{page + 2}}</a></li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="(page + 2) * pageSize < template.filter.length"
(click)="page = page + 2; updatePagedItems()">{{page + 3}}</a></li>
<li *ngIf="(page + 1) * pageSize < template.filter.length" class="page-item"><a
class="page-link px-3 py-[0.375rem] cursor-pointer"
(click)="page = page + 1; updatePagedItems()">{{'Next' | translate}}</a>
</li>
</ul>
</nav>
</div>
</div>
<div class="flex justify-end items-center flex-wrap gap-4 mt-3">
<div><i class="fa fa-times text-danger"></i> = used on menu</div>
<div><i class="fa fa-check text-success"></i> = unused on menu</div>
<!-- <div><i class="ri-file-download-line text-info"></i> = download files</div> -->
<div><i class="ri-printer-line text-warning"></i> = print report</div>
</div>
</div>
</div>
</div>
</div>
<ng-template #printModal let-modal>
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out">
<div class="ti-modal-content">
<div class="ti-modal-header flex justify-between items-center p-5">
<h6 class="ti-modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">
Excel Report
</h6>
<button type="button" class="hs-dropdown-toggle !text-[1rem] !font-semibold !text-defaulttextcolor"
(click)="closeModalprintModal()" #closeModal>
<span class="sr-only">{{'Close' | translate}}</span>
<i class="ri-close-line"></i>
</button>
</div>
<div class="ti-modal-body px-4 mt-3">
<div class="row">
<div class="d-flex col-12 justify-content-center" *ngIf="loading||loadingExcel">
<div *ngFor="let item of [1,2,3]" class="spinner-grow text-info mx-1" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<ng-container *ngIf="!loading&&!loadingExcel">
<ng-container *ngFor="let item of variableSheet; let i=index">
<div class="flex items-center mb-4">
<!-- Label -->
<label class="w-1/4 text-right pr-4 font-semibold text-sm">
{{ item.label }}
</label>
<!-- Input -->
<div class="w-3/4">
<ng-container [ngSwitch]="item.type">
<!-- Text -->
<input *ngSwitchCase="'text'" type="text" class="form-input w-full"
[(ngModel)]="item.value" />
<!-- List -->
<select *ngSwitchCase="'list'" class="form-select w-full"
[(ngModel)]="item.value">
<option *ngFor="let list of item.option" [value]="list.value">
{{ list.text }}
</option>
</select>
<!-- Radio -->
<div *ngSwitchCase="'radio'" class="flex flex-wrap gap-4">
<label *ngFor="let radioItem of item.option"
class="inline-flex items-center">
<input type="radio" class="form-radio mr-2"
[name]="'group-' + item.label" [id]="radioItem.text+radioItem.value"
[value]="radioItem.value" [(ngModel)]="item.value" />
{{ radioItem.text }}
</label>
</div>
<!-- Help -->
<div *ngSwitchCase="'help'" class="flex items-stretch">
<input type="text" readonly class="form-input w-1/2 bg-white cursor-pointer"
[value]="item.value.tdesc" (click)="openModalData(item)" />
<button
class="bg-primary hover:bg-primary text-white px-3 flex items-center justify-center rounded-none border"
type="button" (click)="openModalData(item)">
<i class="ri-search-line font-semibold align-middle"></i>
</button>
<button type="button"
class="bg-red hover:bg-red text-white text-sm ml-5 w-10 h-10 flex items-center justify-center rounded-full"
(click)="item.value={id:'',tdesc:'',edesc:''}">
<i class="fa fa-times text-xs"></i>
</button>
</div>
<!-- Calendar -->
<div *ngSwitchCase="'calendar'" class="flex items-stretch">
<!-- Input -->
<input class="form-input w-1/2 bg-white cursor-pointer rounded-r-none"
style="border-color: #e9edf6;" placeholder="dd.mm.yyyy" name="dp1"
ngbDatepicker #d1="ngbDatepicker" [(ngModel)]="select[item.key]"
readonly (click)="d1.toggle()"
(ngModelChange)="formatNgbDate(item.key, select[item.key])"
#c1="ngModel" (change)="validateDate(c1)" container="body">
<!-- Calendar Button -->
<button type="button"
class="bg-white hover:bg-primary text-primary hover:text-white px-3 flex items-center justify-center rounded-none border"
style="border-color: #154c9c;" (click)="d1.toggle()">
<i class="ri-calendar-2-line"></i>
</button>
<!-- Clear Button -->
<button type="button"
class="bg-red hover:bg-red text-white text-sm ml-5 w-10 h-10 flex items-center justify-center rounded-full"
(click)="select[item.key]=null ;formatNgbDate(item.key)">
<i class="fa fa-times text-xs"></i>
</button>
</div>
</ng-container>
</div>
</div>
</ng-container>
<!-- <div *ngIf="variableSheet.length&&!loadingExcel"
class="col-12 justify-content-center align-content-center d-flex" style="margin-bottom: 1rem;">
<button type="submit" class="btn btn-info waves-effect waves-light btn-w-100"
(click)="dowloadExcelReport()">
{{"Print" }}
</button>
</div>
<div *ngIf="loadingExcel" class="col-12 justify-content-center align-content-center d-flex"
style="margin-bottom: 1rem;">
<div *ngFor="let item of [1,2,3]" class="spinner-grow text-info mx-1" role="status">
<span class="sr-only">Loading...</span>
</div>
</div> -->
<div *ngIf="!variableSheet.length"
class="col-12 justify-content-center align-content-center d-flex"
style="margin-bottom: 1rem;margin-top: 1rem;">
<div
class="col-3 justify-content-center text-center font-weight-bold control-label col-form-label font-14">
{{'No Data Found' }}
</div>
</div>
<div class="row col-12 flex justify-center"
*ngIf="variableSheet.length&&(excelReport.isDataGrid=='1'||excelReport.isPivot=='1')">
<div class="col-12 d-flex justify-content-center align-content-center">
<button type="button" *ngIf="excelReport.isDataGrid=='1'"
class="ti-btn ti-btn-primary-full" (click)="getExcelData('grid')">Datagrid</button>
<ng-container *ngIf="excelReport.isDataGrid=='1'&&excelReport.isPivot=='1'">
&nbsp;
</ng-container>
<button type="button" *ngIf="excelReport.isPivot=='1'"
class="ti-btn ti-btn-primary-full" (click)="getExcelData('pivot')">Pivot</button>
</div>
</div>
</ng-container>
</div>
</div>
<div class="border-t mt-3">
<div class="ti-modal-footer flex justify-end gap-1 mb-3 mt-3 mr-3">
<ng-container *ngIf="variableSheet.length">
<button type="submit" class="ti-btn ti-btn-info-full waves-effect waves-light btn-w-100"
[disabled]="loadingExcel" (click)="dowloadExcelReport()">
{{"Print" }}
</button>
</ng-container>
<button type="button" class="ti-btn bg-danger text-white !font-medium"
(click)="closeModalprintModal()">
ปิด
</button>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template #modalData let-modal>
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out">
<div class="ti-modal-content">
<div class="ti-modal-header flex justify-between items-center p-5">
<h6 class="ti-modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">
{{modalDetail.text.cardHead }}
</h6>
<button type="button" class="hs-dropdown-toggle !text-[1rem] !font-semibold !text-defaulttextcolor"
(click)="closeModalmodalData()" #closeModal>
<span class="sr-only">{{'Close' | translate}}</span>
<i class="ri-close-line"></i>
</button>
</div>
<div class="ti-modal-body px-4 mt-3">
<div class="d-flex mb-1">
<input type="text" placeholder="{{'systemcode.search' }} {{modalDetail.text.search[0]}}"
class=" form-control w-75 border-color-gray-full-focus" [(ngModel)]='searchModal'>
</div>
<div class="table-responsive">
<table class="table table-hover table-striped-myhr table-sm mb-0 no-wrap v-middle "
style="width: 100%">
<thead class="bg-info ">
<tr class="text-white font-weight-normal">
<th class="font-weight-normal text-center" scope="col"
*ngFor="let item of modalDetail.text.tableHead">
{{item}}
</th>
</tr>
</thead>
<tbody *ngIf="!valueDetailFilter().length">
<tr>
<td colspan="9" class="font-weight-normal text-center">
{{"No Data Found" }}
</td>
</tr>
</tbody>
<tbody *ngIf="valueDetailFilter().length">
<tr class="cursor-pointer"
*ngFor="let item of valueDetailFilter() | slice: pageModal * pageSizeModal : (pageModal+1) * pageSizeModal; let i=index"
(click)="selectData(item);closeModalmodalData()"
(mouseenter)="tableHover.set(item.id,!tableHover.get(item.id))"
(mouseleave)="tableHover.clear()"
[ngStyle]="{'background-color':tableHover.get(item.id)?'rgb(201 223 235)':'#ffffff'}">
<td class="align-middle text-center">
{{item.id}}
</td>
<td class="align-middle text-center">
{{item.tdesc}}
</td>
<td class="align-middle text-center">
{{item.edesc}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="box-footer !border-t-0">
<div class="flex items-center flex-wrap overflow-auto" *ngIf="valueDetailFilter().length > 0">
<div class="d-flex justify-content-end p-2">
<select class="custom-select m-r-5 border-color-gray-full-focus" style="width: auto"
[(ngModel)]="pageSizeModal" (ngModelChange)="pageModal=1">
<option *ngFor="let item of [10,50,100]" [ngValue]="item">
{{"รายการต่อหน้า"}}: {{item}}
</option>
</select>
</div>
<div class="mb-2 sm:mb-0">
<div>
{{'Showing' | translate}} {{valueDetailFilter().length}} {{'entries'
| translate}} <i class="bi bi-arrow-right ms-2 font-semibold"></i>
</div>
</div>
<div class="ms-auto">
<nav aria-label="Page navigation">
<ul class="ti-pagination mb-0">
<li *ngIf="pageModal>0" class="page-item {{pageModal==0 ? 'disabled' : ''}}"><a
class="page-link px-3 py-[0.375rem] cursor-pointer"
(click)="pageModal = pageModal-1;updatePagedItems()">{{'Previous' |
translate}}</a></li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="pageModal-1>0"
(click)="pageModal = pageModal-2;updatePagedItems()">{{pageModal-1}}</a>
</li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="pageModal>0 && ((pageModal-1)*10 < (searchText == '' ? valueDetailFilter().length : valueDetailFilter().length))"
(click)="pageModal = pageModal-1;updatePagedItems()">{{pageModal}}</a></li>
<li class="page-item"><a class="page-link active px-3 py-[0.375rem]"
href="javascript:void(0);">{{pageModal +1}}</a>
</li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="(pageModal+1)*10 < (searchText == '' ? valueDetailFilter().length : valueDetailFilter().length)"
(click)="pageModal = pageModal+1;updatePagedItems()">{{pageModal +2}}</a></li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="(pageModal+2)*10 < (searchText == '' ? valueDetailFilter().length : valueDetailFilter().length)"
(click)="pageModal = pageModal+2;updatePagedItems()">{{pageModal +3}}</a></li>
<li *ngIf="(pageModal+1)*10 < (searchText == '' ? valueDetailFilter().length : valueDetailFilter().length)"
class="page-item"><a class="page-link px-3 py-[0.375rem] cursor-pointer"
(click)="pageModal = pageModal+1;updatePagedItems()">{{'Next' |
translate}}</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="border-t">
<div class="ti-modal-footer flex justify-end gap-3 mb-3 mt-3 mr-3">
<button type="button" class="ti-btn bg-danger text-white !font-medium"
(click)="closeModalmodalData()">
ปิด
</button>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template #gridModal let-modal>
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out">
<div class="ti-modal-content">
<div class="ti-modal-header flex justify-between items-center p-5">
<h6 class="ti-modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">
GridData
</h6>
<button type="button" class="hs-dropdown-toggle !text-[1rem] !font-semibold !text-defaulttextcolor"
(click)="closeModalgridModal()" #closeModal>
<span class="sr-only">{{'Close' | translate}}</span>
<i class="ri-close-line"></i>
</button>
</div>
<div class="ti-modal-body px-4 mt-3">
<app-datagrid-syncfution [searchSettings]="searchSettings" [dataSource]="dataList" [columns]="columns"
[gridLayout]="setPerspective" [sendLayout]="gridLayout.stimulate" (layout)="gridLayout.data=$event">
</app-datagrid-syncfution>
</div>
<div class="border-t">
<div class="ti-modal-footer flex justify-end gap-3 mb-3 mt-3 mr-3">
<button *ngIf="!loadingExcel" type="button" class="ti-btn ti-btn-info-full"
(click)="gridLayout.stimulate=!gridLayout.stimulate;savePerspective('grid')">
{{"Save Perspective"}}
</button>
<div *ngIf="loadingExcel" class="row" style="width: 120px;">
<div *ngFor="let item of [1,2,3]" class="spinner-grow text-info mx-1" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<button type="button" class="ti-btn ti-btn-danger-full text-white !font-medium"
(click)="closeModalgridModal()">
ปิด
</button>
</div>
</div>
</div>
</div>
</ng-template>
<ng-template #pivotModal let-modal>
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out">
<div class="ti-modal-content">
<div class="ti-modal-header flex justify-between items-center p-5">
<h6 class="ti-modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">
Pivot
</h6>
<button type="button" class="hs-dropdown-toggle !text-[1rem] !font-semibold !text-defaulttextcolor"
(click)="closeModalpivotModal()" #closeModal>
<span class="sr-only">{{'Close' | translate}}</span>
<i class="ri-close-line"></i>
</button>
</div>
<div class="ti-modal-body px-4 mt-3">
<app-pivot-syncfution [dataSource]="dataList" [columns]="pivotColumns"
[templateId]="excelReport.templateId" [fileName]="excelReport.fileName"
[pivotLayout]="setPerspective" [sendLayout]="pivotLayout.stimulate"
(layout)="pivotLayout.data=$event">
</app-pivot-syncfution>
</div>
<div class="border-t mt-3">
<div class="ti-modal-footer flex justify-end gap-3 mb-3 mt-3 mr-3">
<button *ngIf="!loadingExcel" type="button" class="ti-btn ti-btn-info-full"
(click)="pivotLayout.stimulate=!pivotLayout.stimulate;savePerspective('pivot')">
{{"Save Perspective"}}
</button>
<div *ngIf="loadingExcel" class="row" style="width: 120px;">
<div *ngFor="let item of [1,2,3]" class="spinner-grow text-info mx-1" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<button type="button" class="ti-btn ti-btn-danger-full text-white !font-medium"
(click)="closeModalpivotModal()">
ปิด
</button>
</div>
</div>
</div>
</div>
</ng-template>
\ No newline at end of file
.ti-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
border-bottom-width: 1px;
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-left: 1rem;
padding-right: 1rem;
}
::ng-deep [ngbDatepickerDayView].today {
background-color: #e0f2fe !important;
}
::ng-deep [ngbDatepickerDayView].bg-primary {
background-color: rgb(var(--primary)) !important;
color: #ffffff !important;
}
/* ให้ datepicker popup ทะลุ modal ได้ */
::ng-deep ngb-datepicker,
::ng-deep .ngb-datepicker-container {
z-index: 2000 !important;
}
/* เผื่อ modal มี overflow ซ่อนอยู่ */
::ng-deep .ti-modal-content {
overflow: visible !important;
}
import { ChangeDetectorRef, Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { NgbDate, NgbDatepickerModule, NgbModal, NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap';
import * as FileSaver from 'file-saver';
import { IDataOptions } from '@syncfusion/ej2-angular-pivotview';
import { forkJoin, Subscription } from 'rxjs';
import { ColumnModel } from '@syncfusion/ej2-grids';
import { MyTemplateFileModel, MyTemplateModel, TemplateFileModel, TemplateModel } from '../../../../models/template.model';
import { ModuleModel } from '../../../../models/module.model';
import { ExcelReportService } from '../../../../services/excel-report.service';
import { CustomCubeService } from '../../../../services/custom-cube.service';
import { ConfirmModalComponent } from '../../../../../confirm-modal/confirm-modal.component';
import { AlertModalComponent } from '../../../../../alert-modal/alert-modal.component';
import { CommonModule } from '@angular/common';
import { SharedModule } from '../../../../../shared/shared.module';
import { TranslateModule } from '@ngx-translate/core';
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule, NgModel } from '@angular/forms';
import { FileUploadModule } from 'ng2-file-upload';
import { QuillModule } from 'ngx-quill';
import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { DatagridSyncfutionComponent } from '../../../../../datagrid-syncfution/datagrid-syncfution.component';
import { PivotSyncfutionComponent } from '../../../../../pivot-syncfution/pivot-syncfution.component';
import { SafeUrlPipe } from '../../../../../../pipe/safe-url.pipe';
export interface ModalDetail {
text: { cardHead: string, search: string[], tableHead: string[] }
}
interface ValueDetailItem {
id: string;
tdesc: string;
edesc: string;
}
@Component({
standalone: true,
imports: [
CommonModule,
SharedModule,
TranslateModule,
NgSelectModule,
FormsModule,
RouterModule,
FileUploadModule,
QuillModule,
MatDialogModule,
NgbPaginationModule,
DatagridSyncfutionComponent,
PivotSyncfutionComponent,
NgbDatepickerModule
],
selector: 'app-excel-report-toggle',
templateUrl: './excel-report-toggle.component.html',
styleUrls: ['./excel-report-toggle.component.scss']
})
export class ExcelReportToggleComponent implements OnInit {
template: { data: TemplateModel[], filter: TemplateModel[], loading: boolean } = { data: [], filter: [], loading: false }
templateFile: TemplateFileModel = new MyTemplateFileModel()
module: { data: ModuleModel[], loading: boolean } = { data: [], loading: false }
pagedItems: TemplateModel[] = [];
pageIndex: number = 0;
itemsPerPage: number = 10;
page = 0
pageSize = 10
pageModal = 0
pageSizeModal = 10
searchBy = ''
condition = ''
searchValue = ''
openTemplate: Map<string, boolean> = new Map<string, boolean>()
bodyTemplate: {
status: 'add' | 'edit',
data: {
templateId: string,
tname: string,
ename: string,
tdesc: string,
edesc: string,
module: string
}
} = {
status: 'add',
data: {
templateId: '',
tname: '',
ename: '',
tdesc: '',
edesc: '',
module: ''
}
}
excelPortalSearch: {
groupId: string,
tags: string,
search: string
} = {
groupId: '',
tags: '',
search: ''
}
tableHover: Map<string, boolean> = new Map<string, boolean>()
buttonHover: Map<string, boolean> = new Map<string, boolean>()
changeDate = new Date();
select: any = {}
excelReport?: any
variableSheet: any = []
loading = false
loadingExcel = false
valueDetail: ValueDetailItem[] = [];
modalDetail: ModalDetail = {
text: {
cardHead: '',
search: [],
tableHead: []
}
}
keySelect = ""
searchModal = ""
getTemplateFileSubscription?: Subscription
searchSettings = {
fields: [],
operator: 'contains',
ignoreCase: false
};
columns: ColumnModel[] = []
pivotColumns: any[] = []
dataList: any[] = []
gridLayout: { stimulate: boolean, data: string } = { stimulate: false, data: '' }
pivotLayout: { stimulate: boolean, data: string } = { stimulate: false, data: '' }
setPerspective = ''
isSearching = false;
modalRefprintModal: any;
modalRefmodalData: any;
modalRefgridModal: MatDialogRef<any>;
modalRefpivotModal: MatDialogRef<any>;
searchText: string = '';
@ViewChild('printModal') printModal!: TemplateRef<any>;
@ViewChild('modalData') modalData!: TemplateRef<any>;
@ViewChild('gridModal') gridModal!: TemplateRef<any>;
@ViewChild('pivotModal') pivotModal!: TemplateRef<any>;
constructor(private excelReportService: ExcelReportService,
private modalService: NgbModal,
private customCubeService: CustomCubeService,
private cdr: ChangeDetectorRef,
private modal: MatDialog) {
}
ngOnInit(): void {
this.getExcelList()
}
get totalItems(): number {
return this.searchText == ''
? this.template.data.length
: this.template.filter.length;
}
get totalPages(): number {
return Math.ceil(this.totalItems / this.itemsPerPage);
}
get totalPagesArray(): number[] {
return Array(this.totalPages).fill(0);
}
goToPage(index: number): void {
if (index < 0 || index >= this.totalPages) return;
this.pageIndex = index;
this.updatePagedItems();
}
updatePagedItems() {
const data = this.searchText == '' ? this.template.data : this.template.filter;
const start = this.page * this.pageSize; // ถ้า page = 1 → เริ่มที่ index 10
const end = start + this.pageSize;
this.pagedItems = data.slice(start, end);
}
getExcelList() {
this.template.loading = true
this.excelReportService.getExcelList().subscribe(response => {
this.template.data = response.map(e => new MyTemplateModel(e))
this.template.filter = response.map(e => new MyTemplateModel(e))
this.template.loading = false
}, error => {
this.template.loading = false
})
}
templateListSearch() {
this.isSearching = true;
setTimeout(() => {
if (!this.searchBy || !this.condition || !this.searchValue) {
this.template.filter = this.template.data.map(e => new MyTemplateModel(e));
this.isSearching = false;
return;
}
const conditionMap: { [key: string]: (a: any, b: any) => boolean } = {
includes: (a, b) => (a || '').toString().toLowerCase().includes((b || '').toString().toLowerCase()),
lt: (a, b) => parseFloat(a) < parseFloat(b),
gt: (a, b) => parseFloat(a) > parseFloat(b),
eq: (a, b) => a == b,
lte: (a, b) => parseFloat(a) <= parseFloat(b),
gte: (a, b) => parseFloat(a) >= parseFloat(b),
neq: (a, b) => a != b,
};
const compareFn = conditionMap[this.condition];
if (!compareFn) {
this.template.filter = this.template.data.map(e => new MyTemplateModel(e));
this.isSearching = false;
return;
}
this.template.filter = this.template.data
.filter(item => {
const value = (item as any)[this.searchBy];
return compareFn(value, this.searchValue);
})
.map(e => new MyTemplateModel(e));
this.isSearching = false;
}, 1000); // delay mock loading
}
menuActiveTemplateFile(templateFile: TemplateFileModel) {
const modalConfirmRef = this.modalService.open(ConfirmModalComponent, {
centered: true,
backdrop: 'static',
})
modalConfirmRef.componentInstance.message = 'คุณต้องการ' + (templateFile.menuActive == '1' ? 'ปิด' : 'เปิด') + 'การใช้งานหรือไม่'
modalConfirmRef.result.then(result => {
templateFile.menuActive = templateFile.menuActive == '1' ? '0' : '1'
this.excelReportService.postTemplateFile(templateFile).subscribe(response => {
if (response.success) {
this.openAlertModal(response.message)
this.getExcelList()
} else {
this.openAlertModal(response.message)
}
}, error => {
this.openAlertModal(error.message)
})
}, reject => { })
}
formatISOToLocal(isoString: string) {
const date = new Date(isoString);
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0'); // เดือนเริ่มที่ 0
const year = date.getFullYear();
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return { date: `${day}-${month}-${year}`, time: `${hours}:${minutes}` };
}
openAlertModal(message?: string) {
const modalRef = this.modalService.open(AlertModalComponent, {
centered: true,
backdrop: 'static'
})
modalRef.componentInstance.message = message ? message : ""
modalRef.result.then(result => {
}, reason => {
})
}
openPrintModal(templateFile: TemplateFileModel) {
this.getTemplateFile(templateFile)
this.openModalprintModal()
}
getTemplateFile(templateFile: TemplateFileModel) {
this.loading = true
this.excelReport = undefined
this.variableSheet = []
this.valueDetail = []
this.getTemplateFileSubscription = this.excelReportService.getTemplateFile(templateFile.templateId, templateFile.fileName).subscribe(response => {
this.excelReport = response
this.getExcelColumn()
if (this.excelReport.param) {
Object.entries(this.excelReport.param.variableSheet).forEach(([key, value]) => {
const data = value as any
if (data.type == 'text') {
this.variableSheet.push({
...data, value: data.valueDefault || '', key: key
})
} else if (data.type == 'list') {
this.variableSheet.push({
...data, value: data.valueDefault || '', key: key, option: data.option.split('customize|')[1].split(',').map((x: any) => {
const [value, text] = x.split('#')
return { value: value || '', text: text || '' }
})
})
} else if (data.type == 'radio') {
this.variableSheet.push({
...data, value: data.valueDefault || '', key: key, option: data.option.split('customize|')[1].split(',').map((x: any) => {
const [value, text] = x.split('#')
return { value: value || '', text: text || '' }
})
})
} else if (data.type == 'help') {
this.variableSheet.push({ ...data, value: data.valueDefault ? { id: data.valueDefault, tdesc: data.valueDefault, edesc: data.valueDefault } : { id: "", tdesc: "", edesc: "" }, key: key })
} else if (data.type == 'calendar') {
this.variableSheet.push({ ...data, value: data.valueDefault || '', key: key })
const [d, m, y] = data.valueDefault ? data.valueDefault.split('-').map(Number) : [null, null, null]
this.select[key] = y ? new NgbDate(y, m, d) : null
}
})
}
this.loading = false
this.cdr.detectChanges()
}, (err) => {
this.loading = false
})
}
openModalData(data: any) {
this.searchModal = ''
this.page = 0
this.pageSize = 10
this.valueDetail = data.valueDetail.map((x: any) => ({ id: x.id || '', tdesc: x.tdesc || '', edesc: x.edesc || '' }))
this.keySelect = data.key
this.modalDetail = {
text: {
cardHead: "Table " + data.table,
search: ["Table " + data.table],
tableHead: ['ID', 'detailTH', 'detailENG']
}
}
this.openModalmodalData()
}
valueDetailFilter(): ValueDetailItem[] {
return this.valueDetail.filter((item: any) =>
item.id.toLowerCase().includes(this.searchModal.toLowerCase()) ||
item.tdesc.toLowerCase().includes(this.searchModal.toLowerCase()) ||
item.edesc.toLowerCase().includes(this.searchModal.toLowerCase())
)
}
selectData(data: any) {
const item = this.variableSheet.find((i: any) => i.key === this.keySelect);
if (item) item.value = data;
}
formatNgbDate(key: string, date?: NgbDate) {
if (date) {
const day = String(date.day).padStart(2, '0');
const month = String(date.month).padStart(2, '0');
const year = date.year;
const item = this.variableSheet.find((i: any) => i.key === key);
if (item) item.value = `${day}-${month}-${year}`
} else {
const item = this.variableSheet.find((i: any) => i.key === key);
if (item) item.value = ''
}
}
validateDate(control: NgModel) {
if (!control.value) {
// ว่าง หรือวันที่ไม่ถูกต้อง
this.openAlertModal('กรุณาเลือกวันที่ให้ถูกต้อง');
}
}
dowloadExcelReport() {
this.loadingExcel = true
const fileName = this.excelReport.param.excelFile
const param = this.excelReport.param.variableName
const data = this.variableSheet.map((item: any) => {
if (item.type == 'help') {
return "__" + item.key + "=" + item.value.id
} else if (item.type == 'calendar' || item.type == 'list' || item.type == 'radio' || item.type == 'text') {
return "__" + item.key + "=" + item.value
}
return ""
}).join('|')
const body = {
fileName: fileName,
paramObj: data
}
this.excelReportService.printExcelReport(body).subscribe((res: any) => {
const blob = new Blob([res], { type: 'application/octet-stream' });
FileSaver.saveAs(blob, fileName);
this.loadingExcel = false
this.cdr.detectChanges()
}, (err) => {
this.loadingExcel = false
this.openAlertModal(err.message)
this.cdr.detectChanges()
})
}
openGridModal(targetModal: NgbModal, setPerspective: string) {
this.modalService.open(targetModal, {
centered: true,
backdrop: 'static',
windowClass: 'my-dialog-big-screen'
})
setTimeout(() => {
this.setPerspective = setPerspective
}, 10)
}
openPivotModal(targetModal: NgbModal, setPerspective: string) {
this.modalService.open(targetModal, {
centered: true,
backdrop: 'static',
windowClass: 'my-dialog-big-screen'
})
setTimeout(() => {
this.setPerspective = setPerspective
}, 10)
}
ngOnDestroy(): void {
this.getTemplateFileSubscription?.unsubscribe()
}
getExcelColumn() {
const body = {
templateId: this.excelReport.templateId,
fileName: this.excelReport.fileName
}
this.searchSettings = {
fields: [],
operator: 'contains',
ignoreCase: false
};
this.columns = []
this.pivotColumns = []
this.customCubeService.getExcelColumn(body).subscribe((response: any) => {
this.searchSettings = {
fields: response.map((e: any) => e.split(':')[0]),
operator: 'contains',
ignoreCase: false
};
response.forEach((e: any, i: number) => {
const [field, headerText] = e.split(':')
this.columns.push({
field: field,
headerText: headerText,
type: "string",
isPrimaryKey: i == 0,
})
this.pivotColumns.push({
name: field,
caption: headerText
})
});
}, error => {
})
}
getExcelData(type: 'grid' | 'pivot') {
this.loadingExcel = true
this.dataList = []
const body: any = {
templateId: this.excelReport.templateId,
fileName: this.excelReport.fileName
};
this.variableSheet.forEach((item: any, index: number) => {
const i = index + 1;
body[`key${i}`] = item.key;
if (item.type == 'help') {
body[`val${i}`] = item.value.id
} else if (item.type == 'calendar' || item.type == 'list' || item.type == 'radio' || item.type == 'text') {
body[`val${i}`] = item.value
}
});
forkJoin({
excelData: this.customCubeService.getExcelData(body),
excelPerspective: this.customCubeService.getExcelPerspective(body),
}).subscribe(response => {
this.dataList = response.excelData as any
this.loadingExcel = false
if (type == 'grid') {
this.modalRefgridModal = this.modal.open(this.gridModal, {
width: '1000px',
height: '700px',
data: {
gridData: (response.excelPerspective as any).dataGridStr,
dataList: this.dataList
},
disableClose: true,
autoFocus: false
});
} else if (type == 'pivot') {
this.modalRefpivotModal = this.modal.open(this.pivotModal, {
width: '1000px',
height: '580px',
data: {
pivotData: (response.excelPerspective as any).pivotStr,
dataList: this.dataList
},
disableClose: true,
autoFocus: false
});
}
this.cdr.detectChanges()
}, error => {
this.loadingExcel = false
})
}
savePerspective(type: 'grid' | 'pivot') {
if (type == 'grid') {
this.loadingExcel = true
setTimeout(() => {
const body = {
templateId: this.excelReport.templateId,
fileName: this.excelReport.fileName,
dataGridStr: this.gridLayout.data,
pivotStr: "",
}
this.customCubeService.saveExcelPerspective(body).subscribe(response => {
this.loadingExcel = false
this.openAlertModal(response.message)
}, error => {
this.loadingExcel = false
this.openAlertModal(error.message)
})
this.cdr.detectChanges();
}, 500);
} else if (type == 'pivot') {
this.loadingExcel = true
setTimeout(() => {
const body = {
templateId: this.excelReport.templateId,
fileName: this.excelReport.fileName,
dataGridStr: '',
pivotStr: this.pivotLayout.data,
}
this.customCubeService.saveExcelPerspective(body).subscribe(response => {
this.loadingExcel = false
this.openAlertModal(response.message)
}, error => {
this.loadingExcel = false
this.openAlertModal(error.message)
})
this.cdr.detectChanges();
}, 500);
}
}
openModalprintModal() {
this.modalRefprintModal = this.modal.open(this.printModal, {
width: '700px',
height: '300px'
})
}
closeModalprintModal() {
this.modalRefprintModal?.close()
}
openModalmodalData() {
this.modalRefmodalData = this.modal.open(this.modalData, {
width: '800px',
height: '580px'
})
}
closeModalmodalData() {
this.modalRefmodalData?.close()
}
closeModalgridModal() {
this.modalRefgridModal?.close()
}
closeModalpivotModal() {
this.modalRefpivotModal?.close()
}
}
\ No newline at end of file
...@@ -145,7 +145,7 @@ export class NavService implements OnDestroy { ...@@ -145,7 +145,7 @@ export class NavService implements OnDestroy {
type: 'sub', type: 'sub',
children: [ children: [
{ path: '/admin/excel-list', title: 'เพิ่มรายงาน Excel', type: 'link' }, { path: '/admin/excel-list', title: 'เพิ่มรายงาน Excel', type: 'link' },
{ path: '/admin/member-manage', title: 'เปิด-ปิด การใช้รายงาน Excel', type: 'link' } { path: '/admin/excel-report-toggle', title: 'เปิด-ปิด การใช้รายงาน Excel', type: 'link' }
], ],
}, },
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment