Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
myjob-manage
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angular
myjob-manage
Commits
e8b711e4
Commit
e8b711e4
authored
Jul 09, 2025
by
DESKTOP-E3GSHH7\myhr
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
หน้ารายงาน excel
parent
f956c40e
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1252 additions
and
34 deletions
+1252
-34
common.module.ts
src/app/DPU/common/common.module.ts
+5
-0
excel-report.component.css
...U/common/myportal/excel-report/excel-report.component.css
+0
-0
excel-report.component.html
.../common/myportal/excel-report/excel-report.component.html
+228
-0
excel-report.component.spec.ts
...mmon/myportal/excel-report/excel-report.component.spec.ts
+28
-0
excel-report.component.ts
...PU/common/myportal/excel-report/excel-report.component.ts
+410
-0
excel-report.service copy.ts
src/app/DPU/services/excel-report.service copy.ts
+84
-0
sidebar.component.ts
src/app/shared/components/sidebar/sidebar.component.ts
+493
-21
nav.service.ts
src/app/shared/services/nav.service.ts
+4
-13
No files found.
src/app/DPU/common/common.module.ts
View file @
e8b711e4
...
@@ -84,6 +84,11 @@ export const admin: Routes = [
...
@@ -84,6 +84,11 @@ export const admin: Routes = [
},
},
//////////////MyPortal/////////////////
//////////////MyPortal/////////////////
{
{
path
:
'excel-report'
,
loadComponent
:
()
=>
import
(
'./myportal/excel-report/excel-report.component'
).
then
((
m
)
=>
m
.
ExcelReportComponent
),
},
{
path
:
'excel-list'
,
path
:
'excel-list'
,
loadComponent
:
()
=>
loadComponent
:
()
=>
import
(
'./myportal/set-excel-reports/excel-list/excel-list.component'
).
then
((
m
)
=>
m
.
ExcelListComponent
),
import
(
'./myportal/set-excel-reports/excel-list/excel-list.component'
).
then
((
m
)
=>
m
.
ExcelListComponent
),
...
...
src/app/DPU/common/myportal/excel-report/excel-report.component.css
0 → 100644
View file @
e8b711e4
src/app/DPU/common/myportal/excel-report/excel-report.component.html
0 → 100644
View file @
e8b711e4
<app-page-header
[
title
]="'รายงาน
Excel
'"
[
activeTitle
]="'ผู้ดูแลระบบ'"
[
title1
]="'รายงาน
Excel
'"
></app-page-header>
<div
class=
"box"
>
<div
class=
"relative w-full max-w-4xl mx-auto my-8 font-sans"
>
<button
(
click
)="
toggleDropdown
()"
class=
"w-full bg-white bg-gradient-to-r from-blue-600 to-blue-800 text-white font-semibold py-4 px-6 rounded-xl shadow-lg hover:from-blue-700 hover:to-blue-900 focus:outline-none focus:ring-4 focus:ring-blue-300 transition-all duration-300 ease-in-out flex items-center justify-between"
>
<span
class=
"text-xl sm:text-2xl text-primary"
>
{{ selectedTemplate ? selectedTemplate.tdesc + ' (' + selectedTemplate.fileName + ')' : 'รายงาน Excel' }}
</span>
<svg
class=
"w-6 h-6 transform transition-transform duration-300 text-primary"
[
class
.
rotate-180
]="
isDropdownOpen
"
fill=
"none"
stroke=
"currentColor"
viewBox=
"0 0 24 24"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"2"
d=
"M19 9l-7 7-7-7"
></path>
</svg>
</button>
<div
*
ngIf=
"isDropdownOpen"
class=
"absolute z-10 w-full mt-2 bg-white border border-gray-200 rounded-md shadow-lg overflow-hidden max-h-60 overflow-y-auto"
>
<ul
class=
"py-1"
>
<li
*
ngFor=
"let template of excelReportTemplates"
(
click
)="
selectTemplate
(
template
)"
class=
"px-4 py-2 hover:bg-gray-100 cursor-pointer text-gray-800 text-lg"
>
{{ template.tdesc }} ({{ template.fileName }})
</li>
<li
*
ngIf=
"excelReportTemplates.length === 0 && !loadingTemplates"
class=
"px-4 py-2 text-gray-500 text-lg"
>
ไม่พบรายการ Template
</li>
<li
*
ngIf=
"loadingTemplates"
class=
"px-4 py-2 text-gray-500 text-lg"
>
กำลังโหลด...
</li>
</ul>
</div>
</div>
<div
*
ngIf=
"selectedTemplate && excelReport"
class=
"p-6 bg-gray-100 rounded-b-xl shadow-inner transition-all duration-300 ease-in-out"
[
class
.
max-h-0
]="!
selectedTemplate
"
[
class
.
max-h-screen
]="
selectedTemplate
"
>
<div
class=
"pt-6 border-t border-gray-200 bg-white p-3 rounded-xl"
>
<h2
class=
"text-2xl font-bold text-gray-800 mb-4"
>
รายงาน Excel: {{ selectedTemplate.tdesc }}
</h2>
<p
class=
"mb-4 text-gray-700"
>
ชื่อไฟล์: {{ selectedTemplate.fileName }}
</p>
<!-- <p class="mb-4 text-gray-700">รหัส Template: {{ selectedTemplate.templateId }}</p> -->
<div
*
ngIf=
"variableSheet.length > 0"
class=
"grid grid-cols-1 md:grid-cols-2 gap-4 items-end mb-4 mt-4"
>
<ng-container
*
ngFor=
"let sheetVar of variableSheet"
>
<div
[
ngSwitch
]="
sheetVar
.
type
"
>
<label
[
for
]="
sheetVar
.
key
"
class=
"block text-gray-700 text-sm font-medium mb-1"
>
{{ sheetVar.label
}}
</label>
<ng-container
*
ngSwitchCase=
"'text'"
>
<input
type=
"text"
[
id
]="
sheetVar
.
key
"
[(
ngModel
)]="
sheetVar
.
value
"
[
placeholder
]="
sheetVar
.
tname
"
class=
"mt-1 block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
</ng-container>
<ng-container
*
ngSwitchCase=
"'calendar'"
>
<input
type=
"date"
[
id
]="
sheetVar
.
key
"
[(
ngModel
)]="
sheetVar
.
displayValue
"
(
ngModelChange
)="
formatNgbDate
(
sheetVar
.
key
,
$
event
)"
class=
"mt-1 block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
</ng-container>
<ng-container
*
ngSwitchCase=
"'list'"
>
<select
[
id
]="
sheetVar
.
key
"
[(
ngModel
)]="
sheetVar
.
value
"
class=
"mt-1 block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
>
<option
*
ngFor=
"let opt of sheetVar.option"
[
value
]="
opt
.
value
"
>
{{ opt.text }}
</option>
</select>
</ng-container>
<ng-container
*
ngSwitchCase=
"'radio'"
>
<div
class=
"flex flex-wrap gap-4 mt-1"
>
<label
*
ngFor=
"let opt of sheetVar.option"
class=
"inline-flex items-center"
>
<input
type=
"radio"
[
name
]="
sheetVar
.
key
"
[
value
]="
opt
.
value
"
[(
ngModel
)]="
sheetVar
.
value
"
class=
"form-radio text-blue-600"
/>
<span
class=
"ml-2 text-gray-700"
>
{{ opt.text }}
</span>
</label>
</div>
</ng-container>
<ng-container
*
ngSwitchCase=
"'help'"
>
<div
class=
"relative"
>
<input
type=
"text"
[
id
]="
sheetVar
.
key
"
[(
ngModel
)]="
sheetVar
.
value
.
tdesc
"
class=
"mt-1 block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
<div
class=
"absolute inset-y-0 right-0 pr-3 flex items-center"
>
<button
type=
"button"
(
click
)="
selectData
(
sheetVar
.
key
)"
class=
"p-1 rounded-full bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
>
<svg
class=
"h-5 w-5 text-black"
fill=
"none"
stroke=
"currentColor"
viewBox=
"0 0 24 24"
(
click
)="
openModal
(
sheetVar
,
detailModal
);
$
event
.
stopPropagation
();"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
stroke-linecap=
"round"
stroke-linejoin=
"round"
stroke-width=
"2"
d=
"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</button>
</div>
</div>
</ng-container>
</div>
</ng-container>
</div>
<div
class=
"flex justify-end gap-3 mt-6"
>
<!-- <button (click)="dowloadExcelReport()"
class="bg-primary py-3 px-6 bg-green-600 text-white font-semibold rounded-lg shadow-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition duration-300 ease-in-out transform hover:scale-105">
Download Excel
</button> -->
<button
(
click
)="
printExcelReport
()"
class=
"bg-primary py-3 px-6 bg-blue-600 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-300 ease-in-out transform hover:scale-105"
>
Print Excel
</button>
</div>
</div>
</div>
</div>
<ng-template
#
detailModal
>
<h2
mat-dialog-title
clas
>
<div
class=
"text-primary"
>
รายชื่อพนักงาน
</div>
</h2>
<mat-dialog-content>
<div
class=
"box"
>
<div
class=
"box-header justify-between"
>
<div
class=
"box-title"
>
รายการทั้งหมด
</div>
<div
class=
"flex flex-wrap gap-2"
>
<div>
<input
class=
"form-control form-control"
type=
"text"
placeholder=
"Search..."
aria-label=
".form-control-sm example"
[(
ngModel
)]="
searchModal
"
(
ngModelChange
)="
updateModalPagedItems
()"
>
</div>
</div>
</div>
<div
class=
"box-body"
>
<div
class=
"table-responsive"
>
<table
class=
"table whitespace-nowrap min-w-full ti-custom-table-hover"
>
<thead>
<tr
class=
"border-b border-defaultborder bg-primary"
>
<th
scope=
"col"
*
ngFor=
"let head of modalDetail.text.tableHead"
class=
"text-start text-white"
>
{{ head }}
</th>
</tr>
</thead>
<tbody>
@if (modalFilterList.length > 0) {
@for (item of modalFilterList; track item.id) {
<tr
class=
"border border-defaultborder dark:border-defaultborder/10 cursor-pointer hover:bg-gray-100"
(
click
)="
selectData
(
item
)"
>
<td>
{{ item.id }}
</td>
<td>
{{ item.tdesc }}
</td>
<td>
{{ item.edesc }}
</td>
</tr>
}
} @else {
<tr>
<td
[
attr
.
colspan
]="
modalDetail
.
text
.
tableHead
.
length
"
class=
"text-center py-4 text-gray-500"
>
ไม่พบข้อมูล
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
<!-- <input type="text" [(ngModel)]="searchModal" placeholder="Search..."
(ngModelChange)="updateModalPagedItems()"
class="mt-1 block w-full pl-3 pr-10 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm mb-4" /> -->
<!-- <div class="box-body">
<div class="table-responsive">
<table class="table whitespace-nowrap min-w-full ti-custom-table-hover">
<thead>
<tr class="border-b border-defaultborder bg-primary">
<th scope="col" *ngFor="let head of modalDetail.text.tableHead" class="text-start text-white">{{ head }}
</th>
</tr>
</thead>
<tbody>
@if (modalFilterList.length > 0) {
@for (item of modalFilterList; track item.id) {
<tr class="border border-defaultborder dark:border-defaultborder/10 cursor-pointer hover:bg-gray-100"
(click)="selectData(item)">
<td>{{ item.id }}</td>
<td>{{ item.tdesc }}</td>
<td>{{ item.edesc }}</td>
</tr>
}
} @else {
<tr>
<td [attr.colspan]="modalDetail.text.tableHead.length" class="text-center py-4 text-gray-500">
ไม่พบข้อมูล
</td>
</tr>
}
</tbody>
</table>
</div>
</div> -->
<div
class=
"box-footer"
>
<div
class=
"mb-2 sm:mb-0"
>
<div>
{{'Showing' | translate}} {{ (modalPageIndex * modalPageSize) + 1 }} {{'to' | translate}} {{
Math.min((modalPageIndex + 1) * modalPageSize, totalModalItemsCount) }} {{'of' | translate}} {{
totalModalItemsCount }} {{'entries' | translate}}
<i
class=
"bi bi-arrow-right ms-2 font-semibold"
></i>
</div>
</div>
<div
class=
"flex items-center flex-wrap overflow-auto mt-3"
*
ngIf=
"totalModalItemsCount > 0"
>
<div
class=
"ms-auto"
>
<nav
aria-label=
"Page navigation"
>
<ul
class=
"ti-pagination mb-0"
>
<li
class=
"page-item"
[
class
.
disabled
]="
modalPageIndex =
==
0
"
>
<a
class=
"page-link px-3 py-[0.375rem] cursor-pointer"
(
click
)="
onModalPageChange
(
modalPageIndex
-
1
)"
>
{{'Previous' | translate}}
</a>
</li>
@for (pageNumber of totalPagesArrayInModal; track pageNumber) {
<li
class=
"page-item"
[
class
.
active
]="
modalPageIndex =
==
(
pageNumber
-
1
)"
>
<a
class=
"page-link px-3 py-[0.375rem] cursor-pointer"
(
click
)="
onModalPageChange
(
pageNumber
-
1
)"
>
{{ pageNumber }}
</a>
</li>
}
<li
class=
"page-item"
[
class
.
disabled
]="
modalPageIndex =
==
(
totalPagesArrayInModal
.
length
-
1
)"
>
<a
class=
"page-link px-3 py-[0.375rem] cursor-pointer"
(
click
)="
onModalPageChange
(
modalPageIndex
+
1
)"
>
{{'Next' | translate}}
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions
style=
"justify-content: end; padding: 16px 20px;"
>
<button
type=
"button"
class=
"hs-dropdown-toggle ti-btn ti-btn-light align-middle"
mat-button
(
click
)="
closeDialog
()"
>
Close
</button>
</mat-dialog-actions>
</ng-template>
\ No newline at end of file
src/app/DPU/common/myportal/excel-report/excel-report.component.spec.ts
0 → 100644
View file @
e8b711e4
/* tslint:disable:no-unused-variable */
import
{
async
,
ComponentFixture
,
TestBed
}
from
'@angular/core/testing'
;
import
{
By
}
from
'@angular/platform-browser'
;
import
{
DebugElement
}
from
'@angular/core'
;
import
{
ExcelReportComponent
}
from
'./excel-report.component'
;
describe
(
'ExcelReportComponent'
,
()
=>
{
let
component
:
ExcelReportComponent
;
let
fixture
:
ComponentFixture
<
ExcelReportComponent
>
;
beforeEach
(
async
(()
=>
{
TestBed
.
configureTestingModule
({
declarations
:
[
ExcelReportComponent
]
})
.
compileComponents
();
}));
beforeEach
(()
=>
{
fixture
=
TestBed
.
createComponent
(
ExcelReportComponent
);
component
=
fixture
.
componentInstance
;
fixture
.
detectChanges
();
});
it
(
'should create'
,
()
=>
{
expect
(
component
).
toBeTruthy
();
});
});
src/app/DPU/common/myportal/excel-report/excel-report.component.ts
0 → 100644
View file @
e8b711e4
import
{
ChangeDetectorRef
,
Component
,
OnInit
}
from
'@angular/core'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
FormsModule
}
from
'@angular/forms'
;
import
{
ActivatedRoute
,
RouterModule
}
from
'@angular/router'
;
import
{
NgSelectModule
}
from
'@ng-select/ng-select'
;
import
{
SharedModule
}
from
'../../../../shared/shared.module'
;
import
{
ExcelReportService
}
from
'../../../services/excel-report.service'
;
import
{
NgbDate
}
from
'@ng-bootstrap/ng-bootstrap'
;
import
FileSaver
from
'file-saver'
;
import
{
TemplateFileMiniModel
}
from
'../../../models/template-file-mini.model'
;
import
{
MatDialog
,
MatDialogModule
}
from
'@angular/material/dialog'
;
import
{
TranslateModule
,
TranslateService
}
from
'@ngx-translate/core'
;
export
interface
ValueDetailItem
{
id
:
string
;
tdesc
:
string
;
edesc
:
string
;
}
export
interface
ModalDetail
{
text
:
{
cardHead
:
string
,
search
:
string
[],
tableHead
:
string
[]
}
}
@
Component
({
selector
:
'app-excel-report'
,
standalone
:
true
,
imports
:
[
CommonModule
,
FormsModule
,
RouterModule
,
NgSelectModule
,
SharedModule
,
MatDialogModule
,
TranslateModule
,
],
templateUrl
:
'./excel-report.component.html'
,
styleUrls
:
[
'./excel-report.component.css'
]
})
export
class
ExcelReportComponent
implements
OnInit
{
isDropdownOpen
:
boolean
=
false
;
excelReportStartDate
:
string
=
'2025-07-09'
;
employeeId
:
string
=
''
;
// ลบ pageIndex และ _searchTerm ถ้าไม่ได้ใช้สำหรับส่วนอื่นนอก Modal
// pageIndex = 0;
// _searchTerm = "";
dialogRef
:
any
// ตัวแปรสำหรับ Pagination ของ Modal
modalPageIndex
=
0
;
// เริ่มที่ index 0 เหมือนต้นฉบับ
modalPageSize
=
10
;
// 10 รายการต่อหน้า
Math
=
Math
;
// เพื่อให้ template เข้าถึง Math ได้
readonly
maxPageButtons
=
15
;
changeDate
=
new
Date
();
select
:
any
=
{}
excelReport
?:
any
variableSheet
:
any
=
[]
loading
=
false
loadingExcel
=
false
valueDetail
:
ValueDetailItem
[]
=
[]
// ข้อมูลทั้งหมดที่ได้จาก API สำหรับ Modal
modalFilterList
:
ValueDetailItem
[]
=
[];
// <--- เพิ่มตัวแปรนี้: ข้อมูลที่ถูกแบ่งหน้าแล้วสำหรับแสดงในตาราง Modal
modalDetail
:
ModalDetail
=
{
text
:
{
cardHead
:
''
,
search
:
[],
tableHead
:
[]
}
}
keySelect
=
""
searchModal
=
""
// ใช้เป็น searchTerm สำหรับ Modal
// ลบ page และ pageSize ถ้าไม่ได้ใช้สำหรับส่วนอื่นนอก Modal
// page = 1
// pageSize = 10
// ** Updated properties for dropdown **
excelReportTemplates
:
TemplateFileMiniModel
[]
=
[];
loadingTemplates
:
boolean
=
false
;
selectedTemplate
:
TemplateFileMiniModel
|
null
=
null
;
constructor
(
private
route
:
ActivatedRoute
,
private
excelReportService
:
ExcelReportService
,
private
cdr
:
ChangeDetectorRef
,
private
dialog
:
MatDialog
,
public
translate
:
TranslateService
,
// ต้อง inject TranslateService เพื่อให้ translate pipe ทำงาน
)
{
}
ngOnInit
():
void
{
// Existing route parameter handling (if needed for direct links)
this
.
route
.
paramMap
.
subscribe
(
params
=>
{
const
rawId
=
params
.
get
(
'id'
);
if
(
rawId
)
{
const
[
id
,
queryString
]
=
rawId
.
split
(
'?'
);
const
searchParams
=
new
URLSearchParams
(
queryString
);
// Changed to searchParams for clarity
const
template
=
searchParams
.
get
(
'template'
);
const
name
=
searchParams
.
get
(
'name'
);
// If you want to pre-select a template based on URL params:
if
(
template
&&
name
)
{
// This assumes the list of templates is already loaded or will be loaded
// You might need to adjust this to wait for excelReportTemplates to be populated
this
.
excelReportService
.
getTemplateFileLists
().
subscribe
(
templates
=>
{
this
.
excelReportTemplates
=
templates
;
const
preselected
=
templates
.
find
(
t
=>
t
.
templateId
===
template
&&
t
.
fileName
===
name
);
if
(
preselected
)
{
this
.
selectedTemplate
=
preselected
;
this
.
getDataExcelReport
(
preselected
.
templateId
,
preselected
.
fileName
);
}
}
);
}
}
});
// Load templates for the dropdown when the component initializes
this
.
loadExcelReportTemplates
();
}
openModal
(
data
:
any
,
modal
:
any
)
{
this
.
searchModal
=
''
;
// รีเซ็ต search
this
.
modalPageIndex
=
0
;
// รีเซ็ต index หน้าเมื่อเปิด Modal
this
.
valueDetail
=
data
.
valueDetail
.
map
((
x
:
any
)
=>
({
id
:
x
.
id
||
''
,
tdesc
:
x
.
tdesc
||
''
,
edesc
:
x
.
edesc
||
''
}))
as
ValueDetailItem
[];
this
.
keySelect
=
data
.
key
;
this
.
modalDetail
=
{
text
:
{
cardHead
:
"Table "
+
data
.
table
,
search
:
[
"Table "
+
data
.
table
],
tableHead
:
[
'ID'
,
'detailTH'
,
'detailENG'
]
}
}
this
.
updateModalPagedItems
();
// <--- เรียก updateModalPagedItems() หลังจากโหลดข้อมูล Modal ครั้งแรก
this
.
dialogRef
=
this
.
dialog
.
open
(
modal
,{
width
:
'1100px'
,
height
:
'650px'
});
}
closeDialog
()
{
console
.
log
(
'closeDialog() called.'
);
if
(
this
.
dialogRef
)
{
this
.
dialogRef
.
close
();
this
.
dialogRef
=
undefined
;
console
.
log
(
'Modal closed and dialogRef cleared.'
);
}
else
{
console
.
log
(
'closeDialog() called, but dialogRef is undefined.'
);
}
}
// ลบ updatePagedItems() ออกไป ถ้าไม่ได้ใช้สำหรับส่วนอื่นนอก Modal
// updatePagedItems() {
// const startIndex = this.pageIndex * 10;
// const endIndex = startIndex + 10;
// this.filterList = this.itemsList.slice(startIndex, endIndex);
// }
loadExcelReportTemplates
():
void
{
this
.
loadingTemplates
=
true
;
this
.
excelReportService
.
getTemplateFileLists
().
subscribe
({
next
:
(
data
)
=>
{
this
.
excelReportTemplates
=
data
;
this
.
loadingTemplates
=
false
;
this
.
cdr
.
detectChanges
();
// ลบการเรียก updatePagedItems() ออกจากตรงนี้ด้วย ถ้าไม่ได้ใช้กับส่วนหลัก
// this.updatePagedItems();
},
error
:
(
err
)
=>
{
console
.
error
(
'Failed to load Excel report templates for dropdown'
,
err
);
this
.
loadingTemplates
=
false
;
this
.
excelReportTemplates
=
[];
this
.
cdr
.
detectChanges
();
}
});
}
toggleDropdown
():
void
{
this
.
isDropdownOpen
=
!
this
.
isDropdownOpen
;
}
selectTemplate
(
template
:
TemplateFileMiniModel
):
void
{
this
.
selectedTemplate
=
template
;
this
.
isDropdownOpen
=
false
;
this
.
cdr
.
detectChanges
();
this
.
getDataExcelReport
(
this
.
selectedTemplate
.
templateId
,
this
.
selectedTemplate
.
fileName
);
}
getDataExcelReport
(
templateId
:
string
,
fileName
:
string
)
{
this
.
loading
=
true
this
.
excelReport
=
undefined
this
.
variableSheet
=
[]
this
.
valueDetail
=
[]
this
.
excelReportService
.
getTemplateFile
(
templateId
,
fileName
).
subscribe
((
res
:
any
)
=>
{
console
.
log
(
'response'
,
res
);
this
.
excelReport
=
res
;
if
(
this
.
excelReport
&&
this
.
excelReport
.
param
&&
this
.
excelReport
.
param
.
variableSheet
)
{
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'
)
{
let
initialValueForInput
:
string
=
''
;
// ค่าสำหรับ input type="date" (YYYY-MM-DD)
let
initialValueForModel
:
string
=
''
;
// ค่าสำหรับ sheetVar.value (DD-MM-YYYY, ตามที่คุณต้องการส่งกลับไป)
let
initialNgbDate
:
NgbDate
|
null
=
null
;
if
(
data
.
valueDefault
)
{
// ถ้ามี valueDefault ให้ใช้ค่าจาก API
initialValueForModel
=
data
.
valueDefault
;
const
[
d
,
m
,
y
]
=
data
.
valueDefault
.
split
(
'-'
).
map
(
Number
);
initialNgbDate
=
new
NgbDate
(
y
,
m
,
d
);
initialValueForInput
=
`
${
y
}
-
${
String
(
m
).
padStart
(
2
,
'0'
)}
-
${
String
(
d
).
padStart
(
2
,
'0'
)}
`
;
}
else
{
// ถ้าไม่มี valueDefault ให้กำหนดเป็นวันที่ปัจจุบัน
const
today
=
new
Date
();
const
day
=
String
(
today
.
getDate
()).
padStart
(
2
,
'0'
);
const
month
=
String
(
today
.
getMonth
()
+
1
).
padStart
(
2
,
'0'
);
const
year
=
today
.
getFullYear
();
initialValueForModel
=
`
${
day
}
-
${
month
}
-
${
year
}
`
;
initialValueForInput
=
`
${
year
}
-
${
month
}
-
${
day
}
`
;
initialNgbDate
=
new
NgbDate
(
year
,
today
.
getMonth
()
+
1
,
today
.
getDate
());
}
this
.
variableSheet
.
push
({
...
data
,
value
:
initialValueForModel
,
key
:
key
,
displayValue
:
initialValueForInput
});
this
.
select
[
key
]
=
initialNgbDate
;
}
})
}
this
.
loading
=
false
this
.
cdr
.
detectChanges
()
},
error
=>
{
console
.
error
(
"Error fetching detailed excel report:"
,
error
);
this
.
loading
=
false
// Handle error, maybe show a message to the user
this
.
cdr
.
detectChanges
()
})
}
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
=
''
}
}
valueDetailFilter
():
ValueDetailItem
[]
{
return
this
.
valueDetail
.
filter
((
item
:
ValueDetailItem
)
=>
item
.
id
.
toLowerCase
().
includes
(
this
.
searchModal
.
toLowerCase
())
||
item
.
tdesc
.
toLowerCase
().
includes
(
this
.
searchModal
.
toLowerCase
())
||
item
.
edesc
.
toLowerCase
().
includes
(
this
.
searchModal
.
toLowerCase
())
)
}
// >>>>>> เมธอดสำหรับแบ่งหน้าใน Modal (คล้าย updatePagedItems ของต้นฉบับ)
updateModalPagedItems
()
{
const
filteredData
=
this
.
valueDetailFilter
();
// ใช้ข้อมูลที่กรองแล้ว
const
startIndex
=
this
.
modalPageIndex
*
this
.
modalPageSize
;
const
endIndex
=
startIndex
+
this
.
modalPageSize
;
this
.
modalFilterList
=
filteredData
.
slice
(
startIndex
,
endIndex
);
}
// >>>>>> Getter สำหรับจำนวนรายการทั้งหมดหลังจาก filter (คล้าย itemsList.length / filterList.length)
get
totalModalItemsCount
():
number
{
return
this
.
valueDetailFilter
().
length
;
}
// >>>>>> Getter สำหรับ Array ของเลขหน้า (คล้าย Math.ceil(total / pageSize) ของต้นฉบับ)
get
totalPagesArrayInModal
():
number
[]
{
const
totalPages
=
Math
.
ceil
(
this
.
totalModalItemsCount
/
this
.
modalPageSize
);
const
pageButtons
:
number
[]
=
[];
// กำหนดขอบเขตของปุ่มที่จะแสดง
let
startPage
:
number
,
endPage
:
number
;
if
(
totalPages
<=
this
.
maxPageButtons
)
{
// ถ้าจำนวนหน้าน้อยกว่าหรือเท่ากับจำนวนปุ่มสูงสุดที่กำหนดไว้ ให้แสดงทั้งหมด
startPage
=
1
;
endPage
=
totalPages
;
}
else
{
// ถ้าจำนวนหน้ามากกว่าจำนวนปุ่มสูงสุด
const
halfButtons
=
Math
.
floor
(
this
.
maxPageButtons
/
2
);
if
(
this
.
modalPageIndex
<
halfButtons
)
{
// อยู่ใกล้จุดเริ่มต้น
startPage
=
1
;
endPage
=
this
.
maxPageButtons
;
}
else
if
(
this
.
modalPageIndex
>=
totalPages
-
halfButtons
)
{
// อยู่ใกล้จุดสิ้นสุด
startPage
=
totalPages
-
this
.
maxPageButtons
+
1
;
endPage
=
totalPages
;
}
else
{
// อยู่กลางๆ
startPage
=
this
.
modalPageIndex
-
halfButtons
+
1
;
endPage
=
this
.
modalPageIndex
+
halfButtons
;
}
}
// สร้าง Array ของเลขหน้าตามขอบเขตที่คำนวณได้
for
(
let
i
=
startPage
;
i
<=
endPage
;
i
++
)
{
pageButtons
.
push
(
i
);
}
return
pageButtons
;
}
// ... (เมธอดอื่นๆ ที่เหลือเหมือนเดิม)
selectData
(
data
:
any
)
{
const
item
=
this
.
variableSheet
.
find
((
i
:
any
)
=>
i
.
key
===
this
.
keySelect
);
if
(
item
)
item
.
value
=
data
;
this
.
closeDialog
();
}
dowloadExcelReport
()
{
this
.
loadingExcel
=
true
if
(
!
this
.
excelReport
||
!
this
.
excelReport
.
param
||
!
this
.
excelReport
.
param
.
excelFile
)
{
console
.
error
(
"No excel report selected or missing excelFile parameter."
);
this
.
loadingExcel
=
false
;
return
;
}
const
fileName
=
this
.
excelReport
.
param
.
excelFile
this
.
excelReportService
.
downloadTemplateFile
(
fileName
).
subscribe
((
res
:
any
)
=>
{
const
blob
=
new
Blob
([
res
],
{
type
:
'application/octet-stream'
});
FileSaver
.
saveAs
(
blob
,
fileName
);
this
.
loadingExcel
=
false
this
.
cdr
.
detectChanges
()
},
(
err
)
=>
{
console
.
error
(
"Error downloading excel report:"
,
err
);
this
.
loadingExcel
=
false
this
.
cdr
.
detectChanges
()
})
}
printExcelReport
():
void
{
if
(
!
this
.
selectedTemplate
||
!
this
.
excelReport
||
!
this
.
excelReport
.
param
)
{
alert
(
'Please select an Excel report template first.'
);
return
;
}
this
.
loadingExcel
=
true
;
// Use loadingExcel for print as well
const
fileName
=
this
.
excelReport
.
param
.
excelFile
;
const
paramObj
:
{
[
key
:
string
]:
string
}
=
{};
// Object to hold parameters
this
.
variableSheet
.
forEach
((
item
:
any
)
=>
{
if
(
item
.
type
===
'help'
)
{
paramObj
[
"__"
+
item
.
key
]
=
item
.
value
.
id
||
''
;
}
else
if
(
item
.
type
===
'calendar'
||
item
.
type
===
'list'
||
item
.
type
===
'radio'
||
item
.
type
===
'text'
)
{
paramObj
[
"__"
+
item
.
key
]
=
item
.
value
||
''
;
}
});
// Convert paramObj to string based on backend expectation, typically JSON.stringify
// Or if backend expects a pipe-separated string, adjust accordingly.
const
paramString
=
JSON
.
stringify
(
paramObj
);
// Common format
// const paramString = Object.entries(paramObj).map(([key, value]) => `${key}=${value}`).join('|'); // If backend expects old format
this
.
excelReportService
.
printExcelReport
({
fileName
:
fileName
,
paramObj
:
paramString
}).
subscribe
(
(
res
:
any
)
=>
{
const
blob
=
new
Blob
([
res
],
{
type
:
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
// Correct MIME type for .xlsx
FileSaver
.
saveAs
(
blob
,
fileName
);
this
.
loadingExcel
=
false
;
this
.
cdr
.
detectChanges
();
},
(
err
)
=>
{
console
.
error
(
'Error printing Excel report:'
,
err
);
this
.
loadingExcel
=
false
;
this
.
cdr
.
detectChanges
();
}
);
}
// >>>>>> เมธอดสำหรับเปลี่ยนหน้าใน Modal (คล้าย onCheckboxChange)
onModalPageChange
(
newPageIndex
:
number
):
void
{
this
.
modalPageIndex
=
newPageIndex
;
this
.
updateModalPagedItems
();
// เรียก updateModalPagedItems() เมื่อเปลี่ยนหน้า
}
}
src/app/DPU/services/excel-report.service copy.ts
0 → 100644
View file @
e8b711e4
import
{
Injectable
}
from
'@angular/core'
;
import
{
HttpClient
,
HttpHeaders
}
from
'@angular/common/http'
;
import
{
TranslateService
}
from
'@ngx-translate/core'
;
import
{
Observable
}
from
'rxjs'
;
import
{
environment
}
from
'../../../environments/environment'
;
import
{
TemplateFileModel
,
TemplateModel
}
from
'../models/template.model'
;
import
{
ModuleModel
}
from
'../models/module.model'
;
import
{
ExcelPortalGroupModel
,
ExcelPortalModel
,
ExcelPortalTagsModel
}
from
'../models/excel-portal.model'
;
import
{
AlertModel
}
from
'../models/alert.model'
;
import
{
TemplateFileMiniModel
}
from
'../models/template-file-mini.model'
;
@
Injectable
({
providedIn
:
'root'
})
export
class
ExcelReportService
{
constructor
(
private
http
:
HttpClient
,
private
translateService
:
TranslateService
)
{
}
getExcelList
():
Observable
<
TemplateModel
[]
>
{
return
this
.
http
.
get
<
TemplateModel
[]
>
(
environment
.
url
+
"template/lists?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
)
}
getModuleList
():
Observable
<
ModuleModel
[]
>
{
return
this
.
http
.
get
<
ModuleModel
[]
>
(
environment
.
url
+
"template/lists/module?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
)
}
getExcelPortalList
():
Observable
<
ExcelPortalModel
[]
>
{
return
this
.
http
.
get
<
ExcelPortalModel
[]
>
(
environment
.
url
+
"excel-center/content/lists"
)
}
getExcelPortalgGroupList
():
Observable
<
ExcelPortalGroupModel
[]
>
{
return
this
.
http
.
get
<
ExcelPortalGroupModel
[]
>
(
environment
.
url
+
"portal-group/lists"
)
}
getExcelPortalTagsList
():
Observable
<
ExcelPortalTagsModel
[]
>
{
return
this
.
http
.
get
<
ExcelPortalTagsModel
[]
>
(
environment
.
url
+
"tag/lists"
)
}
postTemplate
(
body
:
{
templateId
:
string
,
tname
:
string
,
ename
:
string
,
tdesc
:
string
,
edesc
:
string
,
module
:
string
})
{
return
this
.
http
.
post
(
environment
.
url
+
"template?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,
body
)
}
deleteTemplate
(
body
:
TemplateModel
):
Observable
<
AlertModel
>
{
let
option
=
{
headers
:
new
HttpHeaders
({
"Content-Type"
:
"application/json"
,
}),
body
:
body
}
return
this
.
http
.
delete
<
AlertModel
>
(
environment
.
url
+
"template?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,
option
)
}
postTemplateFile
(
body
:
TemplateFileModel
):
Observable
<
AlertModel
>
{
return
this
.
http
.
post
<
AlertModel
>
(
environment
.
url
+
"template-file?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,
body
)
}
deleteTemplateFile
(
body
:
TemplateFileModel
):
Observable
<
AlertModel
>
{
let
option
=
{
headers
:
new
HttpHeaders
({
"Content-Type"
:
"application/json"
,
}),
body
:
body
}
return
this
.
http
.
delete
<
AlertModel
>
(
environment
.
url
+
"template-file?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,
option
)
}
downloadTemplateFile
(
fileName
:
string
)
{
return
this
.
http
.
get
(
environment
.
url
+
"template-file/download/excel/"
+
fileName
+
"?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,
{
responseType
:
'blob'
})
}
printExcelReport
(
body
:
{
fileName
:
string
,
paramObj
:
string
})
{
return
this
.
http
.
post
(
environment
.
url
+
"template-file/export-to-excel?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,
body
,
{
responseType
:
'blob'
})
}
getTemplateFile
(
templateid
:
string
,
filename
:
string
):
Observable
<
AlertModel
>
{
return
this
.
http
.
get
<
AlertModel
>
(
environment
.
url
+
"template-file/"
+
templateid
+
"/"
+
filename
+
"?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,)
}
getTemplateFileLists
():
Observable
<
TemplateFileMiniModel
[]
>
{
return
this
.
http
.
get
<
TemplateFileMiniModel
[]
>
(
environment
.
url
+
"template-file/menuitem/mini/lists?companyid=eb2f4f30-edaf-11ee-a69a-c7680edc0e47"
,)
}
}
\ No newline at end of file
src/app/shared/components/sidebar/sidebar.component.ts
View file @
e8b711e4
...
@@ -6,12 +6,15 @@ import { NavigationEnd, Router } from '@angular/router';
...
@@ -6,12 +6,15 @@ import { NavigationEnd, Router } from '@angular/router';
import
{
checkHoriMenu
,
switcherArrowFn
}
from
'./sidebar'
;
import
{
checkHoriMenu
,
switcherArrowFn
}
from
'./sidebar'
;
import
{
TokenService
}
from
'../../services/token.service'
;
import
{
TokenService
}
from
'../../services/token.service'
;
import
{
CompanyModel
}
from
'../../../DPU/models/company.model'
;
import
{
CompanyModel
}
from
'../../../DPU/models/company.model'
;
import
{
MyTemplateFileMiniModel
,
TemplateFileMiniModel
}
from
'../../../DPU/models/template-file-mini.model'
;
import
{
ExcelReportService
}
from
'../../../DPU/services/excel-report.service'
;
@
Component
({
@
Component
({
selector
:
'app-sidebar'
,
selector
:
'app-sidebar'
,
templateUrl
:
'./sidebar.component.html'
,
templateUrl
:
'./sidebar.component.html'
,
styleUrl
:
'./sidebar.component.scss'
styleUrl
:
'./sidebar.component.scss'
})
})
export
class
SidebarComponent
{
export
class
SidebarComponent
{
localStorage
:
any
;
localStorage
:
any
;
// Addding sticky-pin
// Addding sticky-pin
...
@@ -68,20 +71,22 @@ export class SidebarComponent {
...
@@ -68,20 +71,22 @@ export class SidebarComponent {
isInstallerRoute
:
boolean
=
false
;
isInstallerRoute
:
boolean
=
false
;
previousUrl
:
string
=
''
;
previousUrl
:
string
=
''
;
currentUrl
:
string
=
''
;
currentUrl
:
string
=
''
;
submenuExcel
:
TemplateFileMiniModel
[]
=
[];
// เพิ่ม property สำหรับเก็บข้อมูลรายงาน Excel
constructor
(
constructor
(
private
navServices
:
NavService
,
private
navServices
:
NavService
,
private
sanitizer
:
DomSanitizer
,
private
sanitizer
:
DomSanitizer
,
public
router
:
Router
,
public
router
:
Router
,
public
renderer
:
Renderer2
,
public
renderer
:
Renderer2
,
private
elementRef
:
ElementRef
,
private
elementRef
:
ElementRef
,
public
tokenService
:
TokenService
public
tokenService
:
TokenService
,
private
excelReportService
:
ExcelReportService
// Inject ExcelReportService
)
{
)
{
// this.companyModel = new CompanyModel(this.tokenService.getSelectCompany())
this
.
screenWidth
=
window
.
innerWidth
;
this
.
screenWidth
=
window
.
innerWidth
;
}
}
ngOnInit
()
{
ngOnInit
()
{
let
bodyElement
:
any
=
document
.
querySelector
(
'.main-content'
);
let
bodyElement
:
any
=
document
.
querySelector
(
'.main-content'
);
bodyElement
.
onclick
=
()
=>
{
bodyElement
.
onclick
=
()
=>
{
...
@@ -102,9 +107,10 @@ export class SidebarComponent {
...
@@ -102,9 +107,10 @@ export class SidebarComponent {
this
.
currentUrl
=
this
.
router
.
url
this
.
currentUrl
=
this
.
router
.
url
this
.
isCommonRoute
=
this
.
currentUrl
.
includes
(
'/admin'
);
this
.
isCommonRoute
=
this
.
currentUrl
.
includes
(
'/admin'
);
this
.
isInstallerRoute
=
this
.
currentUrl
.
includes
(
'/company'
);
this
.
isInstallerRoute
=
this
.
currentUrl
.
includes
(
'/company'
);
this
.
menuitemsSubscribe$
=
this
.
navServices
.
items
.
subscribe
((
items
)
=>
{
this
.
changeMenu
()
// ดึงข้อมูล Excel Report ก่อน แล้วค่อยอัปเดตเมนู
});
this
.
fetchExcelReportsAndAddToMenu
();
this
.
ParentActive
();
this
.
ParentActive
();
this
.
checkUrlChanges
();
this
.
checkUrlChanges
();
...
@@ -113,7 +119,6 @@ export class SidebarComponent {
...
@@ -113,7 +119,6 @@ export class SidebarComponent {
if
(
WindowResize
)
{
if
(
WindowResize
)
{
this
.
windowSubscribe$
=
WindowResize
.
subscribe
(()
=>
{
this
.
windowSubscribe$
=
WindowResize
.
subscribe
(()
=>
{
// to check and adjst the menu on screen size change
// to check and adjst the menu on screen size change
checkHoriMenu
();
checkHoriMenu
();
});
});
}
}
...
@@ -121,7 +126,6 @@ export class SidebarComponent {
...
@@ -121,7 +126,6 @@ export class SidebarComponent {
checkHoriMenu
();
checkHoriMenu
();
if
(
document
.
documentElement
.
getAttribute
(
'data-nav-layout'
)
==
'horizontal'
&&
window
.
innerWidth
>
992
)
{
if
(
document
.
documentElement
.
getAttribute
(
'data-nav-layout'
)
==
'horizontal'
&&
window
.
innerWidth
>
992
)
{
this
.
closeNavActive
()
this
.
closeNavActive
()
}
}
}
}
...
@@ -136,7 +140,6 @@ export class SidebarComponent {
...
@@ -136,7 +140,6 @@ export class SidebarComponent {
}
}
checkUrlChanges
():
void
{
checkUrlChanges
():
void
{
this
.
router
.
events
.
subscribe
((
event
)
=>
{
this
.
router
.
events
.
subscribe
((
event
)
=>
{
if
(
event
instanceof
NavigationEnd
)
{
if
(
event
instanceof
NavigationEnd
)
{
this
.
ParentActive
();
this
.
ParentActive
();
...
@@ -163,22 +166,60 @@ export class SidebarComponent {
...
@@ -163,22 +166,60 @@ export class SidebarComponent {
// Log to console for verification
// Log to console for verification
console
.
log
(
'Current URL:'
,
this
.
currentUrl
);
console
.
log
(
'Current URL:'
,
this
.
currentUrl
);
console
.
log
(
'Previous URL:'
,
this
.
previousUrl
);
console
.
log
(
'Previous URL:'
,
this
.
previousUrl
);
this
.
changeMenu
()
this
.
changeMenu
()
// เรียก changeMenu อีกครั้งเมื่อ URL เปลี่ยน
}
}
});
});
}
}
// เมธอดสำหรับดึงข้อมูล Excel Report และเพิ่มเข้าเมนู
fetchExcelReportsAndAddToMenu
()
{
this
.
excelReportService
.
getTemplateFileLists
().
subscribe
(
response
=>
{
this
.
submenuExcel
=
response
.
map
(
e
=>
new
MyTemplateFileMiniModel
(
e
));
this
.
changeMenu
();
// เรียก changeMenu เพื่ออัปเดตเมนูหลังจากดึงข้อมูล Excel ได้
},
error
=>
{
console
.
error
(
'Error fetching Excel template files:'
,
error
);
this
.
changeMenu
();
// เรียก changeMenu แม้จะมีข้อผิดพลาดเพื่อโหลดเมนูพื้นฐาน
});
}
changeMenu
()
{
changeMenu
()
{
// กำหนดเมนูพื้นฐาน (Common หรือ Installer)
if
(
this
.
isInstallerRoute
)
{
if
(
this
.
isInstallerRoute
)
{
this
.
menuitemsSubscribe$
=
this
.
navServices
.
items
.
subscribe
((
items
)
=>
{
this
.
menuItems
=
this
.
navServices
.
getCompanyMenu
();
this
.
menuItems
=
this
.
navServices
.
getCompanyMenu
();
});
}
else
{
}
else
{
this
.
menuitemsSubscribe$
=
this
.
navServices
.
items
.
subscribe
((
items
)
=>
{
this
.
menuItems
=
this
.
navServices
.
getCommonMenu
();
this
.
menuItems
=
this
.
navServices
.
getCommonMenu
();
});
}
}
this
.
ParentActive
()
// เพิ่มรายการรายงาน Excel เข้าไปในเมนู หากมีข้อมูลและยังไม่ได้เพิ่ม
if
(
this
.
submenuExcel
.
length
>
0
)
{
const
excelMenuExists
=
this
.
menuItems
.
some
(
item
=>
item
.
title
===
'รายงาน Excel'
);
if
(
!
excelMenuExists
)
{
const
excelSubmenuItems
:
Menu
[]
=
this
.
submenuExcel
.
map
(
e2
=>
({
path
:
'/apps/excel-export/'
+
e2
.
itemId
+
"?template="
+
e2
.
templateId
+
"&name="
+
e2
.
fileName
,
title
:
e2
.
itemId
+
'.'
+
e2
.
tdesc
,
icon
:
''
,
// ไม่มีไอคอนสำหรับเมนูย่อย
type
:
'link'
,
// กำหนดเป็น 'link' สำหรับการนำทางโดยตรง
active
:
false
,
selected
:
false
,
children
:
[]
}));
const
excelMenuItem
:
Menu
=
{
path
:
''
,
// ไม่มี path โดยตรงสำหรับเมนูหลัก
title
:
'รายงาน Excel'
,
icon
:
'file-earmark-excel'
,
// ไอคอนสำหรับรายงาน Excel (ตัวอย่าง: Boxicons)
type
:
'sub'
,
// กำหนดเป็น 'sub' เนื่องจากมีเมนูย่อย
active
:
false
,
selected
:
false
,
children
:
excelSubmenuItems
};
// เพิ่มรายการเมนู Excel เข้าไปใน menuItems ที่มีอยู่
this
.
menuItems
.
push
(
excelMenuItem
);
}
}
this
.
ParentActive
();
// ประเมินสถานะ active อีกครั้งหลังจากเมนูมีการเปลี่ยนแปลง
}
}
...
@@ -270,17 +311,29 @@ export class SidebarComponent {
...
@@ -270,17 +311,29 @@ export class SidebarComponent {
}
}
ParentActive
()
{
ParentActive
()
{
this
.
menuItems
.
map
((
element
:
any
)
=>
{
this
.
menuItems
.
map
((
element
:
any
)
=>
{
if
(
element
.
children
)
{
if
(
element
.
children
)
{
element
.
active
=
false
;
element
.
active
=
false
;
element
.
selected
=
false
;
element
.
selected
=
false
;
element
.
children
.
map
((
ele
:
any
)
=>
{
element
.
children
.
map
((
ele
:
any
)
=>
{
// ตรวจสอบ path ที่ตรงกับ currentUrl
if
(
ele
.
path
==
this
.
currentUrl
)
{
if
(
ele
.
path
==
this
.
currentUrl
)
{
element
.
active
=
true
;
element
.
active
=
true
;
element
.
selected
=
true
;
element
.
selected
=
true
;
}
}
// ตรวจสอบ path สำหรับ Excel Report ที่มี query parameters
if
(
ele
.
path
&&
this
.
currentUrl
.
startsWith
(
ele
.
path
.
split
(
'?'
)[
0
]))
{
const
currentUrlBase
=
this
.
currentUrl
.
split
(
'?'
)[
0
];
const
elePathBase
=
ele
.
path
.
split
(
'?'
)[
0
];
if
(
currentUrlBase
===
elePathBase
)
{
element
.
active
=
true
;
element
.
selected
=
true
;
ele
.
active
=
true
;
// ทำให้เมนูย่อย active ด้วย
ele
.
selected
=
true
;
// ทำให้เมนูย่อย selected ด้วย
}
}
if
(
ele
.
children
)
{
if
(
ele
.
children
)
{
ele
.
active
=
false
;
ele
.
active
=
false
;
ele
.
children
.
map
((
child1
:
any
)
=>
{
ele
.
children
.
map
((
child1
:
any
)
=>
{
...
@@ -290,6 +343,19 @@ export class SidebarComponent {
...
@@ -290,6 +343,19 @@ export class SidebarComponent {
ele
.
active
=
true
;
ele
.
active
=
true
;
ele
.
selected
=
true
;
ele
.
selected
=
true
;
}
}
// ตรวจสอบ path สำหรับ Excel Report ที่มี query parameters ในระดับที่ 3
if
(
child1
.
path
&&
this
.
currentUrl
.
startsWith
(
child1
.
path
.
split
(
'?'
)[
0
]))
{
const
currentUrlBase
=
this
.
currentUrl
.
split
(
'?'
)[
0
];
const
child1PathBase
=
child1
.
path
.
split
(
'?'
)[
0
];
if
(
currentUrlBase
===
child1PathBase
)
{
element
.
active
=
true
;
element
.
selected
=
true
;
ele
.
active
=
true
;
ele
.
selected
=
true
;
child1
.
active
=
true
;
// ทำให้เมนูย่อย active ด้วย
child1
.
selected
=
true
;
// ทำให้เมนูย่อย selected ด้วย
}
}
});
});
}
}
});
});
...
@@ -312,8 +378,8 @@ export class SidebarComponent {
...
@@ -312,8 +378,8 @@ export class SidebarComponent {
return
this
.
sanitizer
.
bypassSecurityTrustHtml
(
svgContent
);
return
this
.
sanitizer
.
bypassSecurityTrustHtml
(
svgContent
);
}
}
ngOnDestroy
()
{
ngOnDestroy
()
{
this
.
menuitemsSubscribe$
.
unsubscribe
();
this
.
menuitemsSubscribe$
?.
unsubscribe
();
// ใช้ ?. เพื่อป้องกัน error ถ้ายังไม่ได้ subscribe
this
.
windowSubscribe$
.
unsubscribe
();
this
.
windowSubscribe$
?.
unsubscribe
();
// ใช้ ?. เพื่อป้องกัน error ถ้ายังไม่ได้ subscribe
this
.
elementRef
.
nativeElement
.
ownerDocument
.
documentElement
,
this
.
elementRef
.
nativeElement
.
ownerDocument
.
documentElement
,
'data-nav-layout'
,
'data-nav-layout'
,
'vertical'
;
'vertical'
;
...
@@ -400,3 +466,409 @@ export class SidebarComponent {
...
@@ -400,3 +466,409 @@ export class SidebarComponent {
}
}
}
}
}
}
//อันเก่า
// import { Component, ViewChild, ElementRef, Renderer2, HostListener, ChangeDetectionStrategy } from '@angular/core';
// import { Menu, NavService } from '../../services/nav.service';
// import { Subscription, fromEvent } from 'rxjs';
// import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
// import { NavigationEnd, Router } from '@angular/router';
// import { checkHoriMenu, switcherArrowFn } from './sidebar';
// import { TokenService } from '../../services/token.service';
// import { CompanyModel } from '../../../DPU/models/company.model';
// @Component({
// selector: 'app-sidebar',
// templateUrl: './sidebar.component.html',
// styleUrl: './sidebar.component.scss'
// })
// export class SidebarComponent {
// localStorage: any;
// // Addding sticky-pin
// scrolled = false;
// screenWidth: number;
// eventTriggered: boolean = false;
// public localdata = localStorage;
// // options = { autoHide: false, scrollbarMinSize: 100 };
// @HostListener('window:scroll', [])
// onWindowScroll() {
// const navScrollElement =
// this.elementRef.nativeElement.querySelector('.nav-scroll');
// this.scrolled = window.scrollY > 10;
// const sections = document.querySelectorAll('.side-menu__item');
// const scrollPos =
// window.scrollY ||
// this.elementRef.nativeElement.ownerDocument.documentElement.scrollTop ||
// document.body.scrollTop;
// sections.forEach((ele, i) => {
// const currLink = sections[i];
// const val: any = currLink.getAttribute('value');
// const refElement: any = document.querySelector('#' + val);
// // Add a null check here before accessing properties of refElement
// if (refElement !== null) {
// const scrollTopMinus = scrollPos + 73;
// if (
// refElement.offsetTop <= scrollTopMinus &&
// refElement.offsetTop + refElement.offsetHeight > scrollTopMinus
// ) {
// if (navScrollElement) {
// this.renderer.removeClass(navScrollElement, 'active');
// }
// currLink.classList.add('active');
// } else {
// currLink.classList.remove('active');
// }
// }
// });
// }
// //////
// public windowSubscribe$!: Subscription;
// options = { autoHide: false, scrollbarMinSize: 100 };
// icon!: SafeHtml;
// public menuItems!: Menu[];
// public menuitemsSubscribe$!: Subscription;
// companyModel: CompanyModel = new CompanyModel()
// isCommonRoute: boolean = false;
// isInstallerRoute: boolean = false;
// previousUrl: string = '';
// currentUrl: string = '';
// constructor(
// private navServices: NavService,
// private sanitizer: DomSanitizer,
// public router: Router,
// public renderer: Renderer2,
// private elementRef: ElementRef,
// public tokenService: TokenService
// ) {
// // this.companyModel = new CompanyModel(this.tokenService.getSelectCompany())
// this.screenWidth = window.innerWidth;
// }
// ngOnInit() {
// let bodyElement: any = document.querySelector('.main-content');
// bodyElement.onclick = () => {
// if (
// localStorage.getItem('ynex-menu-style') == 'icon-click' ||
// localStorage.getItem('ynex-menu-style') == 'menu-click' ||
// localStorage.getItem('ynex-menu-style') == 'icon-hover' ||
// localStorage.getItem('valexlayout') == 'horizontal'
// ) {
// document
// .querySelectorAll('.main-menu .slide-menu.child1')
// .forEach((ele: any) => {
// ele.style.display = 'none';
// });
// }
// };
// this.menuResizeFn();
// this.currentUrl = this.router.url
// this.isCommonRoute = this.currentUrl.includes('/admin');
// this.isInstallerRoute = this.currentUrl.includes('/company');
// this.menuitemsSubscribe$ = this.navServices.items.subscribe((items) => {
// this.changeMenu()
// });
// this.ParentActive();
// this.checkUrlChanges();
// const WindowResize = fromEvent(window, 'resize');
// // subscribing the Observable
// if (WindowResize) {
// this.windowSubscribe$ = WindowResize.subscribe(() => {
// // to check and adjst the menu on screen size change
// checkHoriMenu();
// });
// }
// switcherArrowFn();
// checkHoriMenu();
// if (document.documentElement.getAttribute('data-nav-layout') == 'horizontal' && window.innerWidth > 992) {
// this.closeNavActive()
// }
// }
// checkInitialUrl(): void {
// this.isCommonRoute = this.currentUrl.includes('/admin');
// this.isInstallerRoute = this.currentUrl.includes('/company');
// this.checkUrlChanges()
// // Log to console for verification
// console.log('Initial URL:', this.currentUrl);
// console.log('Is Common Route:', this.isCommonRoute);
// console.log('Is Installer Route:', this.isInstallerRoute);
// }
// checkUrlChanges(): void {
// this.router.events.subscribe((event) => {
// if (event instanceof NavigationEnd) {
// this.ParentActive();
// }
// });
// this.router.events.subscribe((event) => {
// if (event instanceof NavigationEnd) {
// this.previousUrl = this.currentUrl; // Save the previous URL
// this.currentUrl = event.url; // Update to the new URL
// // Check if there's a change between /installer and /admin
// if (
// (this.previousUrl.includes('/company') && this.currentUrl.includes('/admin')) ||
// (this.previousUrl.includes('/admin') && this.currentUrl.includes('/company'))
// ) {
// console.log('URL changed between /installer and /admin.');
// // Implement any logic needed when changing between /installer and /admin
// }
// // Update the boolean values
// this.isCommonRoute = this.currentUrl.includes('/admin');
// this.isInstallerRoute = this.currentUrl.includes('/company');
// // Log to console for verification
// console.log('Current URL:', this.currentUrl);
// console.log('Previous URL:', this.previousUrl);
// this.changeMenu()
// }
// });
// }
// changeMenu() {
// if (this.isInstallerRoute) {
// this.menuitemsSubscribe$ = this.navServices.items.subscribe((items) => {
// this.menuItems = this.navServices.getCompanyMenu();
// });
// } else {
// this.menuitemsSubscribe$ = this.navServices.items.subscribe((items) => {
// this.menuItems = this.navServices.getCommonMenu();
// });
// }
// this.ParentActive()
// }
// //Active Nav State
// setNavActive(item: any) {
// this.menuItems?.filter((menuItem) => {
// if (menuItem !== item) {
// menuItem.active = false;
// this.navServices.collapseSidebar = false;
// }
// if (menuItem.children && menuItem.children.includes(item)) {
// menuItem.active = true;
// menuItem.selected = true;
// }
// if (menuItem.children) {
// menuItem.children?.filter((submenuItems) => {
// if (submenuItems.children && submenuItems.children.includes(item)) {
// menuItem.active = true;
// submenuItems.active = true;
// menuItem.selected = true;
// submenuItems.selected = true;
// }
// if (submenuItems.children) {
// submenuItems.children?.forEach((subsubmenuItems) => {
// if (
// subsubmenuItems.children &&
// subsubmenuItems.children.includes(item)
// ) {
// menuItem.active = true;
// submenuItems.active = true;
// subsubmenuItems.active = true;
// menuItem.selected = true;
// submenuItems.selected = true;
// subsubmenuItems.selected = true;
// }
// });
// }
// });
// }
// });
// }
// // Toggle menu
// toggleNavActive(item: any) {
// if (localStorage.getItem('ynex-sidemenu-styles') == 'icontext') {
// document.querySelector('html')?.setAttribute('icon-text', 'open')
// } else {
// document.querySelector('html')?.removeAttribute('icon-text')
// }
// if (localStorage.getItem('ynex-sidemenu-styles') == 'doublemenu') {
// if (item.active) return;
// } else {
// }
// if (!item.active) {
// this.menuItems?.forEach((a: any) => {
// if (this.menuItems.includes(item)) {
// a.active = false;
// }
// a?.children?.forEach((b: any) => {
// if (a.children.includes(item)) {
// b.active = false;
// } else {
// b.active = false;
// }
// b?.children?.forEach((c: any) => {
// if (b.children.includes(item)) {
// c.active = false;
// }
// });
// });
// });
// }
// item.active = !item.active;
// }
// // Close Nav menu
// closeNavActive() {
// this.menuItems?.forEach((a: any) => {
// if (this.menuItems) {
// a.active = false;
// }
// a?.children?.forEach((b: any) => {
// if (a.children) {
// b.active = false;
// }
// });
// });
// }
// ParentActive() {
// this.menuItems.map((element: any) => {
// if (element.children) {
// element.active = false;
// element.selected = false;
// element.children.map((ele: any) => {
// if (ele.path == this.currentUrl) {
// element.active = true;
// element.selected = true;
// }
// if (ele.children) {
// ele.active = false;
// ele.children.map((child1: any) => {
// if (child1.path == this.currentUrl) {
// element.active = true;
// element.selected = true;
// ele.active = true;
// ele.selected = true;
// }
// });
// }
// });
// }
// });
// }
// @ViewChild('iconContainer', { static: true }) iconContainer!: ElementRef;
// getSanitizedSVG(svgContent: string, menu: any): SafeHtml {
// const svg = this.renderer.createElement(
// 'svg',
// 'http://www.w3.org/2000/svg'
// );
// svg.innerHTML = svgContent;
// svg.classList.add('side-menu__icon');
// this.renderer.listen(svg, 'click', () => {
// this.toggleNavActive(menu);
// });
// // return svg;
// return this.sanitizer.bypassSecurityTrustHtml(svgContent);
// }
// ngOnDestroy() {
// this.menuitemsSubscribe$.unsubscribe();
// this.windowSubscribe$.unsubscribe();
// this.elementRef.nativeElement.ownerDocument.documentElement,
// 'data-nav-layout',
// 'vertical';
// const WindowResize = fromEvent(window, 'resize');
// // subscribing the Observable
// if (WindowResize) {
// this.windowSubscribe$ = WindowResize.subscribe(() => {
// // to check and adjst the menu on screen size change
// checkHoriMenu();
// });
// }
// }
// menuOpen() {
// const mainContent = document.querySelector('.main-content') as HTMLElement;
// if (localStorage['Ynexverticalstyles'] === 'icontext' && localStorage['iconText'] !== 'open') {
// // Assuming you have a service or method to update the theme
// this.updateTheme({ ...this.getCurrentTheme(), iconText: 'open' });
// mainContent?.addEventListener('click', (_event) => {
// // Assuming you have a service or method to update the theme
// this.updateTheme({ ...this.getCurrentTheme(), iconText: '' });
// });
// }
// if (localStorage['Ynexverticalstyles'] === 'doublemenu' && this.getCurrentTheme().dataToggled !== 'double-menu-open') {
// // Assuming you have a service or method to update the theme
// this.updateTheme({ ...this.getCurrentTheme(), dataToggled: 'double-menu-open' });
// }
// }
// // Replace this method with your actual method or service call to update the theme
// updateTheme(updatedTheme: any) {
// // Implement the logic to update the theme in your application
// // This might involve a service or a method that dispatches an action to update the theme state
// console.log('Update Theme:', updatedTheme);
// }
// // Replace this method with your actual method or service call to get the current theme
// getCurrentTheme(): any {
// // Implement the logic to get the current theme from your application state or service
// // Return the current theme object
// return {};
// }
// @HostListener('window:resize', ['$event'])
// onResize(event: any): void {
// this.menuResizeFn();
// this.screenWidth = window.innerWidth;
// // Check if the event hasn't been triggered and the screen width is less than or equal to your breakpoint
// if (!this.eventTriggered && this.screenWidth <= 992) {
// document.documentElement?.setAttribute('data-toggled', 'close')
// // Trigger your event or perform any action here
// this.eventTriggered = true; // Set the flag to true to prevent further triggering
// } else if (this.screenWidth > 992) {
// // Reset the flag when the screen width goes beyond the breakpoint
// this.eventTriggered = false;
// }
// }
// WindowPreSize: number[] = [window.innerWidth];
// menuResizeFn(): void {
// this.WindowPreSize.push(window.innerWidth);
// if (this.WindowPreSize.length > 2) {
// this.WindowPreSize.shift();
// }
// if (this.WindowPreSize.length > 1) {
// const html = document.documentElement;
// if (this.WindowPreSize[this.WindowPreSize.length - 1] < 992 && this.WindowPreSize[this.WindowPreSize.length - 2] >= 992) {
// // less than 992
// html.setAttribute('data-toggled', 'close');
// }
// if (this.WindowPreSize[this.WindowPreSize.length - 1] >= 992 && this.WindowPreSize[this.WindowPreSize.length - 2] < 992) {
// // greater than 992
// html.removeAttribute('data-toggled');
// document.querySelector('#responsive-overlay')?.classList.remove('active');
// }
// }
// }
// }
src/app/shared/services/nav.service.ts
View file @
e8b711e4
...
@@ -149,19 +149,10 @@ export class NavService implements OnDestroy {
...
@@ -149,19 +149,10 @@ export class NavService implements OnDestroy {
type
:
'link'
,
type
:
'link'
,
},
},
{
{
icon
:
'buildings'
,
icon
:
'receipt'
,
path
:
'/admin/company-departments'
,
path
:
'/admin/excel-report'
,
title
:
'ทะเบียนบริษัท'
,
title
:
'รายงาน Excel'
,
type
:
'sub'
,
type
:
'link'
,
children
:
[
{
path
:
'/admin/career-cluster'
,
title
:
'จัดการกลุ่มอาชีพ'
,
type
:
'link'
},
{
path
:
'/admin/position'
,
title
:
'จัดการตำแหน่ง'
,
type
:
'link'
},
{
path
:
'/admin/job-types'
,
title
:
'จัดการประเภทงาน'
,
type
:
'link'
},
{
path
:
'/admin/category-company'
,
title
:
'จัดการประเภทธุรกิจ'
,
type
:
'link'
},
{
path
:
'/admin/degree-manage'
,
title
:
'จัดการระดับการศึกษา'
,
type
:
'link'
},
{
path
:
'/admin/country-registration'
,
title
:
'จัดการประเทศ'
,
type
:
'link'
},
{
path
:
'/admin/provinces'
,
title
:
'จัดการจังหวัด'
,
type
:
'link'
},
],
},
},
// { headTitle: 'User Management' },
// { headTitle: 'User Management' },
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment