Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
portal-apps-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
portal-apps-manage
Commits
c21d15b2
Commit
c21d15b2
authored
Sep 16, 2025
by
Ooh-Ao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pivot
parent
f0065caa
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
979 additions
and
106 deletions
+979
-106
widget-config-registry.service.ts
.../widget-config/services/widget-config-registry.service.ts
+84
-3
syncfusion-pivot-config.component.ts
...cfusion-pivot-config/syncfusion-pivot-config.component.ts
+348
-27
syncfusion-pivot-widget.component.html
...usion-pivot-widget/syncfusion-pivot-widget.component.html
+64
-24
syncfusion-pivot-widget.component.scss
...usion-pivot-widget/syncfusion-pivot-widget.component.scss
+261
-18
syncfusion-pivot-widget.component.ts
...cfusion-pivot-widget/syncfusion-pivot-widget.component.ts
+222
-34
No files found.
src/app/portal-manage/dashboard-management/widget-config/services/widget-config-registry.service.ts
View file @
c21d15b2
...
@@ -1118,23 +1118,104 @@ export class WidgetConfigRegistryService {
...
@@ -1118,23 +1118,104 @@ export class WidgetConfigRegistryService {
// ========================================
// ========================================
'SyncfusionPivotWidgetComponent'
:
{
'SyncfusionPivotWidgetComponent'
:
{
...
baseConfig
,
...
baseConfig
,
// Basic Configuration
expandAll
:
false
,
expandAll
:
false
,
displayOptionView
:
'Both'
,
displayOptionView
:
'Both'
,
chartType
:
'Column'
,
dataSource
:
'static'
,
apiEndpoint
:
''
,
// Pivot Features
showToolbar
:
true
,
showToolbar
:
true
,
showFieldList
:
true
,
showFieldList
:
true
,
showGroupingBar
:
true
,
showPager
:
true
,
allowCalculatedField
:
false
,
allowConditionalFormatting
:
false
,
allowNumberFormatting
:
true
,
allowFieldDragDrop
:
true
,
allowSubTotal
:
true
,
allowGrandTotal
:
true
,
allowDrillThrough
:
false
,
allowSorting
:
true
,
allowExcelExport
:
true
,
allowPdfExport
:
true
,
allowCsvExport
:
true
,
allowPrint
:
true
,
aggregationType
:
'sum'
,
numberFormat
:
'N'
,
// Pivot Fields
rows
:
[],
rows
:
[],
columns
:
[],
columns
:
[],
values
:
[],
values
:
[],
filters
:
[],
filters
:
[],
enableDrillThrough
:
true
,
enableSorting
:
true
,
// Enhanced UI Configuration
dataCount
:
0
,
lastUpdated
:
new
Date
(),
shadow
:
'medium'
,
isLoading
:
false
,
hasError
:
false
,
errorMessage
:
''
,
isEmpty
:
false
,
// Enhanced Interaction Configuration
enableKeyboard
:
true
,
enableFocus
:
true
,
hoverEffect
:
true
,
clickEffect
:
true
,
enableTooltip
:
true
,
enableSelection
:
true
,
enableExport
:
true
,
enableRefresh
:
true
,
clickAction
:
'none'
,
customClickHandler
:
''
,
// Enhanced Layout Configuration
fullWidth
:
false
,
fullHeight
:
false
,
widthUnit
:
'px'
,
heightUnit
:
'px'
,
sizeOption
:
'medium'
,
aspectRatio
:
'auto'
,
// Enhanced Data Configuration
enableFiltering
:
true
,
enableFiltering
:
true
,
enableSorting
:
true
,
enableGrouping
:
true
,
enableGrouping
:
true
,
enablePaging
:
true
,
pageSize
:
10
,
currentPage
:
1
,
totalPages
:
1
,
// Enhanced Security Configuration
requireHttps
:
false
,
allowedRoles
:
''
,
dataEncryption
:
false
,
auditLog
:
false
,
rateLimit
:
0
,
// Enhanced Animation Configuration
enableAnimations
:
true
,
animationType
:
'fade'
,
animationDuration
:
300
,
animationDelay
:
0
,
// Enhanced Style Configuration
customCSS
:
''
,
theme
:
'light'
,
fontSize
:
14
,
fontWeight
:
'normal'
,
fontFamily
:
'system-ui, -apple-system, sans-serif'
,
padding
:
16
,
margin
:
8
,
// Additional Pivot Configuration
showGrandTotals
:
true
,
showGrandTotals
:
true
,
showSubTotals
:
true
,
showSubTotals
:
true
,
showRowTotals
:
true
,
showRowTotals
:
true
,
showColumnTotals
:
true
,
showColumnTotals
:
true
,
enableExport
:
true
,
exportFormats
:
[
'excel'
,
'pdf'
,
'csv'
]
exportFormats
:
[
'excel'
,
'pdf'
,
'csv'
]
},
},
...
...
src/app/portal-manage/dashboard-management/widgets/configs/syncfusion-pivot-config/syncfusion-pivot-config.component.ts
View file @
c21d15b2
import
{
Component
,
Input
,
Output
,
EventEmitter
,
OnInit
}
from
'@angular/core'
;
import
{
Component
,
Input
,
Output
,
EventEmitter
,
OnInit
,
AfterViewInit
,
ChangeDetectorRef
}
from
'@angular/core'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
FormsModule
}
from
'@angular/forms'
;
import
{
FormsModule
}
from
'@angular/forms'
;
import
{
MatFormFieldModule
}
from
'@angular/material/form-field'
;
import
{
MatFormFieldModule
}
from
'@angular/material/form-field'
;
...
@@ -31,7 +31,10 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -31,7 +31,10 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<!-- Basic Configuration Tab -->
<!-- Basic Configuration Tab -->
<mat-tab label="Basic">
<mat-tab label="Basic">
<div class="config-section">
<div class="config-section">
<h3 class="section-title text-blue-600">Basic Configuration</h3>
<h3 class="section-title text-blue-600">
<i class="bi bi-gear-fill mr-2"></i>
Basic Configuration
</h3>
<mat-form-field appearance="fill" class="w-full">
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
<mat-label>Title</mat-label>
...
@@ -87,7 +90,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -87,7 +90,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<h3 class="section-title text-blue-600">Size Configuration</h3>
<h3 class="section-title text-blue-600">Size Configuration</h3>
<div class="size-config">
<div class="size-config">
<div
<div
*ngFor="let option of sizeOptions"
*ngFor="let option of sizeOptions
; trackBy: trackBySizeOption
"
class="size-option"
class="size-option"
[class.selected]="currentConfig.sizeOption === option.id"
[class.selected]="currentConfig.sizeOption === option.id"
(click)="setSizeOption(option.id)">
(click)="setSizeOption(option.id)">
...
@@ -231,7 +234,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -231,7 +234,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-icon>add</mat-icon> Add Row
<mat-icon>add</mat-icon> Add Row
</button>
</button>
</div>
</div>
<div *ngFor="let row of currentConfig.rows; let i = index" class="field-config-item">
<div *ngFor="let row of currentConfig.rows; let i = index
; trackBy: trackByRowIndex
" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-form-field appearance="fill">
<mat-label>Row Field</mat-label>
<mat-label>Row Field</mat-label>
...
@@ -268,7 +271,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -268,7 +271,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-icon>add</mat-icon> Add Column
<mat-icon>add</mat-icon> Add Column
</button>
</button>
</div>
</div>
<div *ngFor="let col of currentConfig.columns; let i = index" class="field-config-item">
<div *ngFor="let col of currentConfig.columns; let i = index
; trackBy: trackByColumnIndex
" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-form-field appearance="fill">
<mat-label>Column Field</mat-label>
<mat-label>Column Field</mat-label>
...
@@ -305,7 +308,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -305,7 +308,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-icon>add</mat-icon> Add Value
<mat-icon>add</mat-icon> Add Value
</button>
</button>
</div>
</div>
<div *ngFor="let val of currentConfig.values; let i = index" class="field-config-item">
<div *ngFor="let val of currentConfig.values; let i = index
; trackBy: trackByValueIndex
" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-form-field appearance="fill">
<mat-label>Value Field</mat-label>
<mat-label>Value Field</mat-label>
...
@@ -352,7 +355,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -352,7 +355,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-icon>add</mat-icon> Add Filter
<mat-icon>add</mat-icon> Add Filter
</button>
</button>
</div>
</div>
<div *ngFor="let fil of currentConfig.filters; let i = index" class="field-config-item">
<div *ngFor="let fil of currentConfig.filters; let i = index
; trackBy: trackByFilterIndex
" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-form-field appearance="fill">
<mat-label>Filter Field</mat-label>
<mat-label>Filter Field</mat-label>
...
@@ -432,10 +435,191 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -432,10 +435,191 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
</div>
</div>
</mat-tab>
</mat-tab>
<!-- Enhanced UI Tab -->
<mat-tab label="UI">
<div class="config-section">
<h3 class="section-title text-indigo-600">
<i class="bi bi-palette-fill mr-2"></i>
Enhanced UI Configuration
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Shadow</mat-label>
<mat-select [(ngModel)]="currentConfig.shadow" name="shadow">
<mat-option value="none">None</mat-option>
<mat-option value="small">Small</mat-option>
<mat-option value="medium">Medium</mat-option>
<mat-option value="large">Large</mat-option>
</mat-select>
<mat-hint>Widget shadow effect</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Theme</mat-label>
<mat-select [(ngModel)]="currentConfig.theme" name="theme">
<mat-option value="light">Light</mat-option>
<mat-option value="dark">Dark</mat-option>
<mat-option value="auto">Auto</mat-option>
</mat-select>
<mat-hint>Color theme</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Font Size (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.fontSize" name="fontSize" min="10" max="24">
<mat-hint>Base font size</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Font Weight</mat-label>
<mat-select [(ngModel)]="currentConfig.fontWeight" name="fontWeight">
<mat-option value="normal">Normal</mat-option>
<mat-option value="bold">Bold</mat-option>
<mat-option value="lighter">Lighter</mat-option>
</mat-select>
<mat-hint>Font weight</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Font Family</mat-label>
<input matInput [(ngModel)]="currentConfig.fontFamily" name="fontFamily" placeholder="system-ui, sans-serif">
<mat-hint>Font family</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Padding (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.padding" name="padding" min="0" max="50">
<mat-hint>Internal padding</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Margin (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.margin" name="margin" min="0" max="50">
<mat-hint>External margin</mat-hint>
</mat-form-field>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Interaction Features</h4>
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<mat-checkbox [(ngModel)]="currentConfig.enableKeyboard" name="enableKeyboard">
Enable Keyboard
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.enableFocus" name="enableFocus">
Enable Focus
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.hoverEffect" name="hoverEffect">
Hover Effect
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.clickEffect" name="clickEffect">
Click Effect
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.enableTooltip" name="enableTooltip">
Enable Tooltip
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.enableSelection" name="enableSelection">
Enable Selection
</mat-checkbox>
</div>
</div>
</div>
</mat-tab>
<!-- Animation Tab -->
<mat-tab label="Animation">
<div class="config-section">
<h3 class="section-title text-pink-600">
<i class="bi bi-magic mr-2"></i>
Animation Configuration
</h3>
<div class="flex items-center space-x-4 mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableAnimations" name="enableAnimations">
Enable Animations
</mat-checkbox>
</div>
<div *ngIf="currentConfig.enableAnimations" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Animation Type</mat-label>
<mat-select [(ngModel)]="currentConfig.animationType" name="animationType">
<mat-option value="fade">Fade</mat-option>
<mat-option value="slide">Slide</mat-option>
<mat-option value="bounce">Bounce</mat-option>
<mat-option value="pulse">Pulse</mat-option>
<mat-option value="none">None</mat-option>
</mat-select>
<mat-hint>Animation type</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Animation Duration (ms)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.animationDuration" name="animationDuration" min="100" max="2000">
<mat-hint>Animation duration</mat-hint>
</mat-form-field>
</div>
<div *ngIf="currentConfig.enableAnimations" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Animation Delay (ms)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.animationDelay" name="animationDelay" min="0" max="1000">
<mat-hint>Animation delay</mat-hint>
</mat-form-field>
</div>
</div>
</mat-tab>
<!-- Security Tab -->
<mat-tab label="Security">
<div class="config-section">
<h3 class="section-title text-red-600">
<i class="bi bi-shield-fill mr-2"></i>
Security Configuration
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Allowed Roles</mat-label>
<input matInput [(ngModel)]="currentConfig.allowedRoles" name="allowedRoles" placeholder="admin,user,manager">
<mat-hint>Comma-separated roles</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Rate Limit (requests/hour)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rateLimit" name="rateLimit" min="0" max="10000">
<mat-hint>0 = No limit</mat-hint>
</mat-form-field>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Security Features</h4>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-checkbox [(ngModel)]="currentConfig.requireHttps" name="requireHttps">
Require HTTPS
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.dataEncryption" name="dataEncryption">
Data Encryption
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.auditLog" name="auditLog">
Audit Logging
</mat-checkbox>
</div>
</div>
</div>
</mat-tab>
<!-- Data Tab -->
<!-- Data Tab -->
<mat-tab label="Data">
<mat-tab label="Data">
<div class="config-section">
<div class="config-section">
<h3 class="section-title text-emerald-600">Data Management</h3>
<h3 class="section-title text-emerald-600">
<i class="bi bi-database-fill mr-2"></i>
Data Management
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-form-field appearance="fill">
...
@@ -475,50 +659,88 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -475,50 +659,88 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
`
,
`
,
styles
:
[
`
styles
:
[
`
.config-container {
.config-container {
padding: 2
0
px;
padding: 2
4
px;
background:
#f8fafc
;
background:
linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)
;
border-radius: 1
2
px;
border-radius: 1
6
px;
box-shadow: 0
4px 6px -1px rgba(0, 0, 0, 0.1
);
box-shadow: 0
10px 25px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05
);
}
}
.config-section {
.config-section {
margin-bottom: 32px;
margin-bottom: 32px;
padding: 2
4
px;
padding: 2
8
px;
background:
white
;
background:
linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)
;
border-radius:
8
px;
border-radius:
12
px;
border: 1px solid #e2e8f0;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
&:hover {
box-shadow: 0 10px 25px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
transform: translateY(-2px);
}
}
}
.section-title {
.section-title {
font-size: 1.25rem;
font-size: 1.375rem;
font-weight: 600;
font-weight: 700;
margin-bottom: 20px;
margin-bottom: 24px;
padding-bottom: 8px;
padding-bottom: 12px;
border-bottom: 2px solid #e2e8f0;
border-bottom: 3px solid #e2e8f0;
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: flex;
align-items: center;
gap: 8px;
i {
font-size: 1.25rem;
color: #3b82f6;
}
}
}
.config-tabs {
.config-tabs {
margin-top: 0;
margin-top: 0;
background: white;
border-radius: 16px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
overflow: hidden;
}
}
.config-tabs .mat-tab-body-content {
.config-tabs .mat-tab-body-content {
padding: 2
0
px 0;
padding: 2
4
px 0;
}
}
.config-tabs .mat-tab-header {
.config-tabs .mat-tab-header {
background:
white
;
background:
linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)
;
border-radius:
8px 8
px 0 0;
border-radius:
16px 16
px 0 0;
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);
}
}
.config-tabs .mat-tab-label {
.config-tabs .mat-tab-label {
min-width: 120px;
min-width: 140px;
font-weight: 500;
font-weight: 600;
font-size: 0.875rem;
padding: 16px 24px;
transition: all 0.3s ease;
color: #6b7280;
&:hover {
background: rgba(59, 130, 246, 0.1);
color: #3b82f6;
}
}
}
.config-tabs .mat-tab-label-active {
.config-tabs .mat-tab-label-active {
color: #3b82f6;
color: #3b82f6;
background: rgba(59, 130, 246, 0.1);
border-bottom: 3px solid #3b82f6;
}
.config-tabs .mat-ink-bar {
background: #3b82f6;
height: 3px;
}
}
.mat-form-field {
.mat-form-field {
...
@@ -666,12 +888,49 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
...
@@ -666,12 +888,49 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
.text-purple-600 { color: #9333ea; }
.text-purple-600 { color: #9333ea; }
.text-orange-600 { color: #ea580c; }
.text-orange-600 { color: #ea580c; }
.text-emerald-600 { color: #059669; }
.text-emerald-600 { color: #059669; }
.text-indigo-600 { color: #4f46e5; }
.text-pink-600 { color: #db2777; }
.text-red-600 { color: #dc2626; }
.text-cyan-600 { color: #0891b2; }
.text-yellow-600 { color: #ca8a04; }
`
]
`
]
})
})
export
class
SyncfusionPivotConfigComponent
extends
BaseConfigComponent
implements
OnInit
{
export
class
SyncfusionPivotConfigComponent
extends
BaseConfigComponent
implements
OnInit
,
AfterViewInit
{
constructor
(
override
cdr
:
ChangeDetectorRef
)
{
super
(
cdr
);
}
override
ngOnInit
():
void
{
override
ngOnInit
():
void
{
// Initialize basic config first
this
.
initializeDefaultConfig
();
this
.
initializeDefaultConfig
();
}
override
ngAfterViewInit
():
void
{
// Initialize other configs after view is ready
this
.
initializeColorDefaults
();
this
.
initializeColorDefaults
();
this
.
initializeAdvancedConfig
();
this
.
cdr
.
detectChanges
();
}
// TrackBy functions to prevent unnecessary re-renders
trackByRowIndex
(
index
:
number
,
item
:
any
):
number
{
return
index
;
}
trackByColumnIndex
(
index
:
number
,
item
:
any
):
number
{
return
index
;
}
trackByValueIndex
(
index
:
number
,
item
:
any
):
number
{
return
index
;
}
trackByFilterIndex
(
index
:
number
,
item
:
any
):
number
{
return
index
;
}
trackBySizeOption
(
index
:
number
,
item
:
any
):
string
{
return
item
.
id
;
}
}
override
initializeDefaultConfig
():
void
{
override
initializeDefaultConfig
():
void
{
...
@@ -734,6 +993,68 @@ export class SyncfusionPivotConfigComponent extends BaseConfigComponent implemen
...
@@ -734,6 +993,68 @@ export class SyncfusionPivotConfigComponent extends BaseConfigComponent implemen
if
(
!
this
.
currentConfig
.
borderColor
)
this
.
currentConfig
.
borderColor
=
'#E5E7EB'
;
if
(
!
this
.
currentConfig
.
borderColor
)
this
.
currentConfig
.
borderColor
=
'#E5E7EB'
;
}
}
private
initializeAdvancedConfig
()
{
// Enhanced UI configuration
if
(
this
.
currentConfig
.
dataCount
===
undefined
)
this
.
currentConfig
.
dataCount
=
0
;
if
(
!
this
.
currentConfig
.
lastUpdated
)
this
.
currentConfig
.
lastUpdated
=
new
Date
();
if
(
!
this
.
currentConfig
.
shadow
)
this
.
currentConfig
.
shadow
=
'medium'
;
if
(
this
.
currentConfig
.
isLoading
===
undefined
)
this
.
currentConfig
.
isLoading
=
false
;
if
(
this
.
currentConfig
.
hasError
===
undefined
)
this
.
currentConfig
.
hasError
=
false
;
if
(
!
this
.
currentConfig
.
errorMessage
)
this
.
currentConfig
.
errorMessage
=
''
;
if
(
this
.
currentConfig
.
isEmpty
===
undefined
)
this
.
currentConfig
.
isEmpty
=
false
;
// Enhanced interaction configuration
if
(
this
.
currentConfig
.
enableKeyboard
===
undefined
)
this
.
currentConfig
.
enableKeyboard
=
true
;
if
(
this
.
currentConfig
.
enableFocus
===
undefined
)
this
.
currentConfig
.
enableFocus
=
true
;
if
(
this
.
currentConfig
.
hoverEffect
===
undefined
)
this
.
currentConfig
.
hoverEffect
=
true
;
if
(
this
.
currentConfig
.
clickEffect
===
undefined
)
this
.
currentConfig
.
clickEffect
=
true
;
if
(
this
.
currentConfig
.
enableTooltip
===
undefined
)
this
.
currentConfig
.
enableTooltip
=
true
;
if
(
this
.
currentConfig
.
enableSelection
===
undefined
)
this
.
currentConfig
.
enableSelection
=
true
;
if
(
this
.
currentConfig
.
enableExport
===
undefined
)
this
.
currentConfig
.
enableExport
=
true
;
if
(
this
.
currentConfig
.
enableRefresh
===
undefined
)
this
.
currentConfig
.
enableRefresh
=
true
;
if
(
!
this
.
currentConfig
.
clickAction
)
this
.
currentConfig
.
clickAction
=
'none'
;
if
(
!
this
.
currentConfig
.
customClickHandler
)
this
.
currentConfig
.
customClickHandler
=
''
;
// Enhanced layout configuration
if
(
this
.
currentConfig
.
fullWidth
===
undefined
)
this
.
currentConfig
.
fullWidth
=
false
;
if
(
this
.
currentConfig
.
fullHeight
===
undefined
)
this
.
currentConfig
.
fullHeight
=
false
;
if
(
!
this
.
currentConfig
.
widthUnit
)
this
.
currentConfig
.
widthUnit
=
'px'
;
if
(
!
this
.
currentConfig
.
heightUnit
)
this
.
currentConfig
.
heightUnit
=
'px'
;
if
(
!
this
.
currentConfig
.
sizeOption
)
this
.
currentConfig
.
sizeOption
=
'medium'
;
if
(
!
this
.
currentConfig
.
aspectRatio
)
this
.
currentConfig
.
aspectRatio
=
'auto'
;
// Enhanced data configuration
if
(
this
.
currentConfig
.
enableFiltering
===
undefined
)
this
.
currentConfig
.
enableFiltering
=
true
;
if
(
this
.
currentConfig
.
enableSorting
===
undefined
)
this
.
currentConfig
.
enableSorting
=
true
;
if
(
this
.
currentConfig
.
enableGrouping
===
undefined
)
this
.
currentConfig
.
enableGrouping
=
true
;
if
(
this
.
currentConfig
.
enablePaging
===
undefined
)
this
.
currentConfig
.
enablePaging
=
true
;
if
(
!
this
.
currentConfig
.
pageSize
)
this
.
currentConfig
.
pageSize
=
10
;
if
(
!
this
.
currentConfig
.
currentPage
)
this
.
currentConfig
.
currentPage
=
1
;
if
(
!
this
.
currentConfig
.
totalPages
)
this
.
currentConfig
.
totalPages
=
1
;
// Enhanced security configuration
if
(
this
.
currentConfig
.
requireHttps
===
undefined
)
this
.
currentConfig
.
requireHttps
=
false
;
if
(
!
this
.
currentConfig
.
allowedRoles
)
this
.
currentConfig
.
allowedRoles
=
''
;
if
(
this
.
currentConfig
.
dataEncryption
===
undefined
)
this
.
currentConfig
.
dataEncryption
=
false
;
if
(
this
.
currentConfig
.
auditLog
===
undefined
)
this
.
currentConfig
.
auditLog
=
false
;
if
(
!
this
.
currentConfig
.
rateLimit
)
this
.
currentConfig
.
rateLimit
=
0
;
// Enhanced animation configuration
if
(
this
.
currentConfig
.
enableAnimations
===
undefined
)
this
.
currentConfig
.
enableAnimations
=
true
;
if
(
!
this
.
currentConfig
.
animationType
)
this
.
currentConfig
.
animationType
=
'fade'
;
if
(
!
this
.
currentConfig
.
animationDuration
)
this
.
currentConfig
.
animationDuration
=
300
;
if
(
!
this
.
currentConfig
.
animationDelay
)
this
.
currentConfig
.
animationDelay
=
0
;
// Enhanced style configuration
if
(
!
this
.
currentConfig
.
customCSS
)
this
.
currentConfig
.
customCSS
=
''
;
if
(
!
this
.
currentConfig
.
theme
)
this
.
currentConfig
.
theme
=
'light'
;
if
(
!
this
.
currentConfig
.
fontSize
)
this
.
currentConfig
.
fontSize
=
14
;
if
(
!
this
.
currentConfig
.
fontWeight
)
this
.
currentConfig
.
fontWeight
=
'normal'
;
if
(
!
this
.
currentConfig
.
fontFamily
)
this
.
currentConfig
.
fontFamily
=
'system-ui, -apple-system, sans-serif'
;
if
(
!
this
.
currentConfig
.
padding
)
this
.
currentConfig
.
padding
=
16
;
if
(
!
this
.
currentConfig
.
margin
)
this
.
currentConfig
.
margin
=
8
;
}
addPivotRow
()
{
addPivotRow
()
{
this
.
addArrayItem
(
'rows'
,
{
name
:
''
,
caption
:
''
,
visible
:
true
,
expanded
:
false
});
this
.
addArrayItem
(
'rows'
,
{
name
:
''
,
caption
:
''
,
visible
:
true
,
expanded
:
false
});
}
}
...
...
src/app/portal-manage/dashboard-management/widgets/syncfusion-pivot-widget/syncfusion-pivot-widget.component.html
View file @
c21d15b2
<div
<div
class=
"syncfusion-pivot-widget"
class=
"syncfusion-pivot-widget"
[
ngStyle
]="
getAllStyles
()"
[
ngStyle
]="
getAllStyles
()"
[
ngClass
]="['
custom-styled
',
getInteractionClasses
()]"
[
ngClass
]="['
custom-styled
',
getInteractionClasses
()
,
'
shadow-
'
+
shadow
]"
[
attr
.
data-widget-id
]="
widgetId
"
[
attr
.
data-widget-id
]="
widgetId
"
[
attr
.
data-source
]="
dataSource
"
[
attr
.
data-source
]="
dataSource
"
[
title
]="
enableTooltip
?
(
title
+
'
-
Pivot
Table
Widget
')
:
null
"
[
title
]="
enableTooltip
?
(
title
+
'
-
Pivot
Table
Widget
')
:
null
"
...
@@ -21,13 +21,24 @@
...
@@ -21,13 +21,24 @@
<div
class=
"header-content"
>
<div
class=
"header-content"
>
<div
class=
"header-left"
>
<div
class=
"header-left"
>
<h4
class=
"widget-title"
>
{{ title }}
</h4>
<h4
class=
"widget-title"
>
{{ title }}
</h4>
<div
class=
"data-count"
*
ngIf=
"dataCount > 0"
>
<i
class=
"bi bi-database"
></i>
<span>
{{ dataCount }} records
</span>
</div>
<div
class=
"last-updated"
*
ngIf=
"lastUpdated"
>
<i
class=
"bi bi-clock"
></i>
<span>
{{ lastUpdated | date:'short' }}
</span>
</div>
</div>
</div>
<div
class=
"header-actions"
>
<div
class=
"header-actions"
>
<div
*
ngIf=
"enableExport"
class=
"
export-button"
(
click
)="
exportData
($
event
)
"
>
<div
*
ngIf=
"enableExport"
class=
"
action-button export-button"
(
click
)="
exportData
($
event
)"
title=
"Export Data
"
>
<i
class=
"bi bi-download"
></i>
<i
class=
"bi bi-download"
></i>
</div>
</div>
<div
*
ngIf=
"enableRefresh && dataSource !== 'static'"
class=
"refresh-button"
(
click
)="
refreshData
($
event
)"
>
<div
*
ngIf=
"enableRefresh && dataSource !== 'static'"
class=
"action-button refresh-button"
(
click
)="
refreshData
($
event
)"
title=
"Refresh Data"
>
<i
class=
"bi bi-arrow-clockwise"
></i>
<i
class=
"bi bi-arrow-clockwise"
[
class
.
rotating
]="
isLoading
"
></i>
</div>
<div
*
ngIf=
"enableFiltering"
class=
"action-button filter-button"
(
click
)="
toggleFilter
($
event
)"
title=
"Toggle Filter"
>
<i
class=
"bi bi-funnel"
></i>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -35,6 +46,10 @@
...
@@ -35,6 +46,10 @@
<i
class=
"bi bi-info-circle"
></i>
<i
class=
"bi bi-info-circle"
></i>
<span>
{{ getDataSourceInfo() }}
</span>
<span>
{{ getDataSourceInfo() }}
</span>
</div>
</div>
<div
*
ngIf=
"requireHttps && !dataSource.includes('https')"
class=
"security-warning"
>
<i
class=
"bi bi-shield-exclamation"
></i>
<span>
HTTPS required for secure data transmission
</span>
</div>
</div>
</div>
<!-- Security Warning -->
<!-- Security Warning -->
...
@@ -47,32 +62,57 @@
...
@@ -47,32 +62,57 @@
<div
*
ngIf=
"hasRequiredRole()"
class=
"widget-body"
>
<div
*
ngIf=
"hasRequiredRole()"
class=
"widget-body"
>
<!-- Loading State -->
<!-- Loading State -->
<div
*
ngIf=
"isLoading"
class=
"flex justify-center items-center h-full"
>
<div
*
ngIf=
"isLoading"
class=
"loading-state"
>
<div
class=
"animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"
></div>
<div
class=
"loading-spinner"
>
<div
class=
"spinner"
></div>
</div>
<p
class=
"loading-text"
>
Loading pivot data...
</p>
</div>
</div>
<!-- Error State -->
<!-- Error State -->
<div
*
ngIf=
"hasError"
class=
"flex flex-col justify-center items-center h-full text-red-500"
>
<div
*
ngIf=
"hasError"
class=
"error-state"
>
<i
class=
"bi bi-exclamation-circle-fill text-4xl"
></i>
<div
class=
"error-icon"
>
<p
class=
"mt-2 font-semibold"
>
{{ errorMessage }}
</p>
<i
class=
"bi bi-exclamation-circle-fill"
></i>
</div>
<h3
class=
"error-title"
>
Error Loading Data
</h3>
<p
class=
"error-message"
>
{{ errorMessage }}
</p>
<button
class=
"retry-button"
(
click
)="
refreshData
($
event
)"
>
<i
class=
"bi bi-arrow-clockwise"
></i>
Retry
</button>
</div>
<!-- Empty State -->
<div
*
ngIf=
"isEmpty && !isLoading && !hasError"
class=
"empty-state"
>
<div
class=
"empty-icon"
>
<i
class=
"bi bi-table"
></i>
</div>
<h3
class=
"empty-title"
>
No Data Available
</h3>
<p
class=
"empty-message"
>
There is no data to display in the pivot table.
</p>
<button
class=
"refresh-button"
(
click
)="
refreshData
($
event
)"
>
<i
class=
"bi bi-arrow-clockwise"
></i>
Refresh
</button>
</div>
</div>
<!-- Pivot View -->
<!-- Pivot View -->
<ejs-pivotview
#
pivotview
*
ngIf=
"!isLoading && !hasError"
<div
*
ngIf=
"!isLoading && !hasError && !isEmpty"
class=
"pivot-container"
>
[
dataSourceSettings
]="
dataSourceSettings
"
<ejs-pivotview
#
pivotview
[
allowCalculatedField
]="
allowCalculatedField
"
[
dataSourceSettings
]="
dataSourceSettings
"
[
showFieldList
]="
showFieldList
"
[
allowCalculatedField
]="
allowCalculatedField
"
[
showToolbar
]="
showToolbar
"
[
showFieldList
]="
showFieldList
"
[
showGroupingBar
]="
showGroupingBar
"
[
showToolbar
]="
showToolbar
"
[
allowPdfExport
]="
allowPdfExport
&&
enableExport
"
[
showGroupingBar
]="
showGroupingBar
"
[
allowExcelExport
]="
allowExcelExport
&&
enableExport
"
[
allowPdfExport
]="
allowPdfExport
&&
enableExport
"
(
toolbarClick
)="
toolbarClick
($
event
)"
[
allowExcelExport
]="
allowExcelExport
&&
enableExport
"
[
toolbar
]="
toolbar
"
(
toolbarClick
)="
toolbarClick
($
event
)"
[
displayOption
]="
displayOption
"
[
toolbar
]="
toolbar
"
[
chartSettings
]="
chartSettings
"
[
displayOption
]="
displayOption
"
(
dataBound
)="
onDataBound
($
event
)"
[
chartSettings
]="
chartSettings
"
[
height
]="'
100
%'"
>
(
dataBound
)="
onDataBound
($
event
)"
</ejs-pivotview>
[
height
]="'
100
%'"
>
</ejs-pivotview>
</div>
</div>
</div>
</div>
</div>
src/app/portal-manage/dashboard-management/widgets/syncfusion-pivot-widget/syncfusion-pivot-widget.component.scss
View file @
c21d15b2
...
@@ -5,13 +5,36 @@
...
@@ -5,13 +5,36 @@
height
:
100%
;
height
:
100%
;
position
:
relative
;
position
:
relative
;
overflow
:
hidden
;
overflow
:
hidden
;
border-radius
:
12px
;
box-shadow
:
0
4px
6px
-1px
rgba
(
0
,
0
,
0
,
0
.1
)
,
0
2px
4px
-1px
rgba
(
0
,
0
,
0
,
0
.06
);
transition
:
all
0
.3s
ease
;
background
:
linear-gradient
(
135deg
,
#ffffff
0%
,
#f8fafc
100%
);
// Shadow variants
&
.shadow-none
{
box-shadow
:
none
;
}
&
.shadow-small
{
box-shadow
:
0
1px
3px
0
rgba
(
0
,
0
,
0
,
0
.1
)
,
0
1px
2px
0
rgba
(
0
,
0
,
0
,
0
.06
);
}
&
.shadow-medium
{
box-shadow
:
0
4px
6px
-1px
rgba
(
0
,
0
,
0
,
0
.1
)
,
0
2px
4px
-1px
rgba
(
0
,
0
,
0
,
0
.06
);
}
&
.shadow-large
{
box-shadow
:
0
10px
15px
-3px
rgba
(
0
,
0
,
0
,
0
.1
)
,
0
4px
6px
-2px
rgba
(
0
,
0
,
0
,
0
.05
);
}
// Widget Header
// Widget Header
.widget-header
{
.widget-header
{
flex-shrink
:
0
;
flex-shrink
:
0
;
padding
:
1
2px
16
px
;
padding
:
1
6px
20
px
;
border-bottom
:
1px
solid
rgba
(
229
,
231
,
235
,
0
.5
);
border-bottom
:
1px
solid
rgba
(
229
,
231
,
235
,
0
.5
);
position
:
relative
;
position
:
relative
;
background
:
linear-gradient
(
135deg
,
#f8fafc
0%
,
#e2e8f0
100%
);
border-radius
:
12px
12px
0
0
;
.header-content
{
.header-content
{
display
:
flex
;
display
:
flex
;
...
@@ -20,14 +43,41 @@
...
@@ -20,14 +43,41 @@
.header-left
{
.header-left
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
flex-direction
:
column
;
gap
:
8
px
;
gap
:
4
px
;
.widget-title
{
.widget-title
{
font-size
:
1
6
px
;
font-size
:
1
8
px
;
font-weight
:
6
00
;
font-weight
:
7
00
;
margin
:
0
;
margin
:
0
;
color
:
inherit
;
color
:
inherit
;
text-shadow
:
0
1px
2px
rgba
(
0
,
0
,
0
,
0
.1
);
}
.data-count
{
display
:
flex
;
align-items
:
center
;
gap
:
4px
;
font-size
:
12px
;
color
:
#6b7280
;
font-weight
:
500
;
i
{
font-size
:
10px
;
}
}
.last-updated
{
display
:
flex
;
align-items
:
center
;
gap
:
4px
;
font-size
:
11px
;
color
:
#9ca3af
;
font-weight
:
400
;
i
{
font-size
:
9px
;
}
}
}
}
}
...
@@ -35,32 +85,39 @@
...
@@ -35,32 +85,39 @@
display
:
flex
;
display
:
flex
;
gap
:
8px
;
gap
:
8px
;
.export-button
,
.action-button
{
.refresh-button
{
width
:
36px
;
width
:
32px
;
height
:
36px
;
height
:
32px
;
border-radius
:
8px
;
border-radius
:
6px
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
center
;
cursor
:
pointer
;
cursor
:
pointer
;
transition
:
all
0
.2s
ease
;
transition
:
all
0
.3s
ease
;
background
:
rgba
(
255
,
255
,
255
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
0
.8
);
color
:
inherit
;
color
:
#374151
;
opacity
:
0
.7
;
border
:
1px
solid
rgba
(
229
,
231
,
235
,
0
.5
);
box-shadow
:
0
1px
3px
rgba
(
0
,
0
,
0
,
0
.1
);
&
:hover
{
&
:hover
{
opacity
:
1
;
background
:
rgba
(
59
,
130
,
246
,
0
.1
);
background
:
rgba
(
255
,
255
,
255
,
0
.2
);
border-color
:
rgba
(
59
,
130
,
246
,
0
.3
);
transform
:
translateY
(
-1px
);
color
:
#3b82f6
;
transform
:
translateY
(
-2px
);
box-shadow
:
0
4px
8px
rgba
(
0
,
0
,
0
,
0
.15
);
}
}
&
:active
{
&
:active
{
transform
:
translateY
(
0
);
transform
:
translateY
(
0
);
box-shadow
:
0
1px
3px
rgba
(
0
,
0
,
0
,
0
.1
);
}
}
i
{
i
{
font-size
:
14px
;
font-size
:
16px
;
}
&
.rotating
i
{
animation
:
spin
1s
linear
infinite
;
}
}
}
}
}
}
...
@@ -120,6 +177,174 @@
...
@@ -120,6 +177,174 @@
display
:
flex
;
display
:
flex
;
flex-direction
:
column
;
flex-direction
:
column
;
overflow
:
hidden
;
overflow
:
hidden
;
position
:
relative
;
}
// Loading State
.loading-state
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
padding
:
40px
;
background
:
linear-gradient
(
135deg
,
#f8fafc
0%
,
#e2e8f0
100%
);
.loading-spinner
{
margin-bottom
:
16px
;
.spinner
{
width
:
40px
;
height
:
40px
;
border
:
4px
solid
#e2e8f0
;
border-top
:
4px
solid
#3b82f6
;
border-radius
:
50%
;
animation
:
spin
1s
linear
infinite
;
}
}
.loading-text
{
font-size
:
14px
;
color
:
#6b7280
;
font-weight
:
500
;
margin
:
0
;
}
}
// Error State
.error-state
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
padding
:
40px
;
background
:
linear-gradient
(
135deg
,
#fef2f2
0%
,
#fee2e2
100%
);
text-align
:
center
;
.error-icon
{
margin-bottom
:
16px
;
i
{
font-size
:
48px
;
color
:
#ef4444
;
}
}
.error-title
{
font-size
:
18px
;
font-weight
:
600
;
color
:
#dc2626
;
margin
:
0
0
8px
0
;
}
.error-message
{
font-size
:
14px
;
color
:
#7f1d1d
;
margin
:
0
0
20px
0
;
}
.retry-button
{
display
:
flex
;
align-items
:
center
;
gap
:
8px
;
padding
:
10px
20px
;
background
:
#ef4444
;
color
:
white
;
border
:
none
;
border-radius
:
8px
;
font-size
:
14px
;
font-weight
:
500
;
cursor
:
pointer
;
transition
:
all
0
.3s
ease
;
&
:hover
{
background
:
#dc2626
;
transform
:
translateY
(
-2px
);
box-shadow
:
0
4px
8px
rgba
(
239
,
68
,
68
,
0
.3
);
}
&
:active
{
transform
:
translateY
(
0
);
}
i
{
font-size
:
16px
;
}
}
}
// Empty State
.empty-state
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
padding
:
40px
;
background
:
linear-gradient
(
135deg
,
#f8fafc
0%
,
#e2e8f0
100%
);
text-align
:
center
;
.empty-icon
{
margin-bottom
:
16px
;
i
{
font-size
:
48px
;
color
:
#9ca3af
;
}
}
.empty-title
{
font-size
:
18px
;
font-weight
:
600
;
color
:
#374151
;
margin
:
0
0
8px
0
;
}
.empty-message
{
font-size
:
14px
;
color
:
#6b7280
;
margin
:
0
0
20px
0
;
}
.refresh-button
{
display
:
flex
;
align-items
:
center
;
gap
:
8px
;
padding
:
10px
20px
;
background
:
#3b82f6
;
color
:
white
;
border
:
none
;
border-radius
:
8px
;
font-size
:
14px
;
font-weight
:
500
;
cursor
:
pointer
;
transition
:
all
0
.3s
ease
;
&
:hover
{
background
:
#2563eb
;
transform
:
translateY
(
-2px
);
box-shadow
:
0
4px
8px
rgba
(
59
,
130
,
246
,
0
.3
);
}
&
:active
{
transform
:
translateY
(
0
);
}
i
{
font-size
:
16px
;
}
}
}
// Pivot Container
.pivot-container
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
background
:
white
;
border-radius
:
0
0
12px
12px
;
}
}
// Interaction States
// Interaction States
...
@@ -189,6 +414,15 @@
...
@@ -189,6 +414,15 @@
}
}
// Animation Keyframes
// Animation Keyframes
@keyframes
spin
{
0
%
{
transform
:
rotate
(
0deg
);
}
100
%
{
transform
:
rotate
(
360deg
);
}
}
@keyframes
fadeIn
{
@keyframes
fadeIn
{
from
{
from
{
opacity
:
0
;
opacity
:
0
;
...
@@ -238,6 +472,15 @@
...
@@ -238,6 +472,15 @@
}
}
}
}
@keyframes
shimmer
{
0
%
{
background-position
:
-200px
0
;
}
100
%
{
background-position
:
calc
(
200px
+
100%
)
0
;
}
}
// Aspect Ratio Constraints
// Aspect Ratio Constraints
&
.aspect-ratio-16-9
{
&
.aspect-ratio-16-9
{
aspect-ratio
:
16
/
9
;
aspect-ratio
:
16
/
9
;
...
...
src/app/portal-manage/dashboard-management/widgets/syncfusion-pivot-widget/syncfusion-pivot-widget.component.ts
View file @
c21d15b2
import
{
Component
,
ViewChild
,
OnDestroy
,
OnInit
,
AfterViewInit
}
from
'@angular/core'
;
import
{
Component
,
ViewChild
,
OnDestroy
,
OnInit
,
AfterViewInit
,
ChangeDetectorRef
}
from
'@angular/core'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
CommonModule
}
from
'@angular/common'
;
import
{
PivotViewModule
,
IDataSet
,
FieldListService
,
CalculatedFieldService
,
ToolbarService
,
GroupingBarService
,
ConditionalFormattingService
,
PivotViewComponent
,
PDFExportService
,
ExcelExportService
,
ToolbarItems
,
PivotChartService
,
DisplayOption
}
from
'@syncfusion/ej2-angular-pivotview'
;
import
{
PivotViewModule
,
IDataSet
,
FieldListService
,
CalculatedFieldService
,
ToolbarService
,
GroupingBarService
,
ConditionalFormattingService
,
PivotViewComponent
,
PDFExportService
,
ExcelExportService
,
ToolbarItems
,
PivotChartService
,
DisplayOption
}
from
'@syncfusion/ej2-angular-pivotview'
;
import
{
ChartSettingsModel
}
from
'@syncfusion/ej2-pivotview/src/pivotview/model/chartsettings-model'
;
import
{
ChartSettingsModel
}
from
'@syncfusion/ej2-pivotview/src/pivotview/model/chartsettings-model'
;
...
@@ -21,6 +21,74 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -21,6 +21,74 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
public
widgetId
:
string
;
public
widgetId
:
string
;
private
isPerspectiveApplied
=
false
;
private
isPerspectiveApplied
=
false
;
// Enhanced UI properties
public
dataCount
:
number
=
0
;
public
lastUpdated
:
Date
=
new
Date
();
public
shadow
:
string
=
'medium'
;
public
override
isLoading
:
boolean
=
false
;
public
override
hasError
:
boolean
=
false
;
public
override
errorMessage
:
string
=
''
;
public
isEmpty
:
boolean
=
false
;
// Enhanced interaction properties
public
enableKeyboard
:
boolean
=
true
;
public
enableFocus
:
boolean
=
true
;
public
hoverEffect
:
boolean
=
true
;
public
clickEffect
:
boolean
=
true
;
public
enableTooltip
:
boolean
=
true
;
public
enableSelection
:
boolean
=
true
;
public
enableExport
:
boolean
=
true
;
public
enableRefresh
:
boolean
=
true
;
public
clickAction
:
string
=
'none'
;
public
customClickHandler
:
string
=
''
;
// Enhanced layout properties
public
fullWidth
:
boolean
=
false
;
public
fullHeight
:
boolean
=
false
;
public
widthUnit
:
string
=
'px'
;
public
heightUnit
:
string
=
'px'
;
public
sizeOption
:
string
=
'medium'
;
public
aspectRatio
:
string
=
'auto'
;
// Enhanced data properties
public
enableFiltering
:
boolean
=
true
;
public
enableSorting
:
boolean
=
true
;
public
enableGrouping
:
boolean
=
true
;
public
enablePaging
:
boolean
=
true
;
public
pageSize
:
number
=
10
;
public
currentPage
:
number
=
1
;
public
totalPages
:
number
=
1
;
// Enhanced security properties
public
requireHttps
:
boolean
=
false
;
public
allowedRoles
:
string
=
''
;
public
dataEncryption
:
boolean
=
false
;
public
auditLog
:
boolean
=
false
;
public
rateLimit
:
number
=
0
;
// Enhanced style properties
public
customCSS
:
string
=
''
;
public
theme
:
string
=
'light'
;
public
fontSize
:
number
=
14
;
public
fontWeight
:
string
=
'normal'
;
public
fontFamily
:
string
=
'system-ui, -apple-system, sans-serif'
;
public
padding
:
number
=
16
;
public
margin
:
number
=
8
;
// Animation properties
public
enableAnimations
:
boolean
=
true
;
public
animationType
:
string
=
'fade'
;
public
animationDuration
:
number
=
300
;
public
animationDelay
:
number
=
0
;
// Original data storage
public
override
originalData
:
any
[]
=
[];
public
dataSourceSettings
:
{
public
dataSourceSettings
:
{
dataSource
:
DataManager
;
dataSource
:
DataManager
;
expandAll
:
boolean
;
expandAll
:
boolean
;
...
@@ -50,29 +118,11 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -50,29 +118,11 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
public
accentColor
:
string
=
'#3B82F6'
;
public
accentColor
:
string
=
'#3B82F6'
;
public
borderRadius
:
number
=
8
;
public
borderRadius
:
number
=
8
;
public
borderWidth
:
number
=
1
;
public
borderWidth
:
number
=
1
;
public
padding
:
number
=
16
;
public
margin
:
number
=
8
;
public
fontSize
:
number
=
14
;
public
fontWeight
:
string
=
'normal'
;
public
fontFamily
:
string
=
'system-ui, -apple-system, sans-serif'
;
public
customCSS
:
string
=
''
;
// Animation properties
public
enableAnimations
:
boolean
=
true
;
public
animationType
:
string
=
'fade'
;
public
animationDuration
:
number
=
300
;
public
animationDelay
:
number
=
0
;
public
hoverEffects
:
boolean
=
true
;
public
hoverEffects
:
boolean
=
true
;
// Interaction properties
// Interaction properties
public
enableTooltip
:
boolean
=
true
;
public
enableClick
:
boolean
=
true
;
public
enableClick
:
boolean
=
true
;
public
enableHover
:
boolean
=
true
;
public
enableHover
:
boolean
=
true
;
public
enableSelection
:
boolean
=
true
;
public
enableExport
:
boolean
=
true
;
public
enableRefresh
:
boolean
=
true
;
public
clickAction
:
string
=
'none'
;
public
customClickHandler
:
string
=
''
;
// Layout properties
// Layout properties
public
width
:
number
=
800
;
public
width
:
number
=
800
;
...
@@ -81,7 +131,6 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -81,7 +131,6 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
public
minHeight
:
number
=
400
;
public
minHeight
:
number
=
400
;
public
maxWidth
:
number
=
1400
;
public
maxWidth
:
number
=
1400
;
public
maxHeight
:
number
=
1000
;
public
maxHeight
:
number
=
1000
;
public
aspectRatio
:
string
=
'auto'
;
public
responsive
:
boolean
=
true
;
public
responsive
:
boolean
=
true
;
// Data properties
// Data properties
...
@@ -94,10 +143,6 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -94,10 +143,6 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
// Security properties
// Security properties
public
requireAuth
:
boolean
=
false
;
public
requireAuth
:
boolean
=
false
;
public
allowedRoles
:
string
=
''
;
public
dataEncryption
:
boolean
=
false
;
public
auditLog
:
boolean
=
false
;
public
rateLimit
:
number
=
0
;
// Pivot-specific properties from SyncfusionPivotConfigComponent
// Pivot-specific properties from SyncfusionPivotConfigComponent
public
displayOptionView
:
string
=
'Both'
;
public
displayOptionView
:
string
=
'Both'
;
...
@@ -126,12 +171,12 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -126,12 +171,12 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
// Pivot-specific properties (moved to above section)
// Pivot-specific properties (moved to above section)
public
showChart
:
boolean
=
true
;
public
showChart
:
boolean
=
true
;
public
showGrid
:
boolean
=
true
;
public
showGrid
:
boolean
=
true
;
public
enableGrouping
:
boolean
=
true
;
public
allowFiltering
:
boolean
=
true
;
public
allowFiltering
:
boolean
=
true
;
constructor
(
constructor
(
protected
override
dashboardStateService
:
DashboardStateService
,
protected
override
dashboardStateService
:
DashboardStateService
,
private
widgetStateService
:
WidgetStateService
private
widgetStateService
:
WidgetStateService
,
private
cdr
:
ChangeDetectorRef
)
{
)
{
super
(
dashboardStateService
);
super
(
dashboardStateService
);
}
}
...
@@ -175,6 +220,66 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -175,6 +220,66 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
chartSettings
:
this
.
chartSettings
,
chartSettings
:
this
.
chartSettings
,
};
};
// Enhanced UI configuration
this
.
dataCount
=
this
.
configObj
.
dataCount
||
0
;
this
.
lastUpdated
=
this
.
configObj
.
lastUpdated
||
new
Date
();
this
.
shadow
=
this
.
configObj
.
shadow
||
'medium'
;
this
.
isLoading
=
this
.
configObj
.
isLoading
||
false
;
this
.
hasError
=
this
.
configObj
.
hasError
||
false
;
this
.
errorMessage
=
this
.
configObj
.
errorMessage
||
''
;
this
.
isEmpty
=
this
.
configObj
.
isEmpty
||
false
;
// Enhanced interaction configuration
this
.
enableKeyboard
=
this
.
configObj
.
enableKeyboard
!==
undefined
?
this
.
configObj
.
enableKeyboard
:
true
;
this
.
enableFocus
=
this
.
configObj
.
enableFocus
!==
undefined
?
this
.
configObj
.
enableFocus
:
true
;
this
.
hoverEffect
=
this
.
configObj
.
hoverEffect
!==
undefined
?
this
.
configObj
.
hoverEffect
:
true
;
this
.
clickEffect
=
this
.
configObj
.
clickEffect
!==
undefined
?
this
.
configObj
.
clickEffect
:
true
;
this
.
enableTooltip
=
this
.
configObj
.
enableTooltip
!==
undefined
?
this
.
configObj
.
enableTooltip
:
true
;
this
.
enableSelection
=
this
.
configObj
.
enableSelection
!==
undefined
?
this
.
configObj
.
enableSelection
:
true
;
this
.
enableExport
=
this
.
configObj
.
enableExport
!==
undefined
?
this
.
configObj
.
enableExport
:
true
;
this
.
enableRefresh
=
this
.
configObj
.
enableRefresh
!==
undefined
?
this
.
configObj
.
enableRefresh
:
true
;
this
.
clickAction
=
this
.
configObj
.
clickAction
||
'none'
;
this
.
customClickHandler
=
this
.
configObj
.
customClickHandler
||
''
;
// Enhanced layout configuration
this
.
fullWidth
=
this
.
configObj
.
fullWidth
!==
undefined
?
this
.
configObj
.
fullWidth
:
false
;
this
.
fullHeight
=
this
.
configObj
.
fullHeight
!==
undefined
?
this
.
configObj
.
fullHeight
:
false
;
this
.
widthUnit
=
this
.
configObj
.
widthUnit
||
'px'
;
this
.
heightUnit
=
this
.
configObj
.
heightUnit
||
'px'
;
this
.
sizeOption
=
this
.
configObj
.
sizeOption
||
'medium'
;
this
.
aspectRatio
=
this
.
configObj
.
aspectRatio
||
'auto'
;
// Enhanced data configuration
this
.
enableFiltering
=
this
.
configObj
.
enableFiltering
!==
undefined
?
this
.
configObj
.
enableFiltering
:
true
;
this
.
enableSorting
=
this
.
configObj
.
enableSorting
!==
undefined
?
this
.
configObj
.
enableSorting
:
true
;
this
.
enableGrouping
=
this
.
configObj
.
enableGrouping
!==
undefined
?
this
.
configObj
.
enableGrouping
:
true
;
this
.
enablePaging
=
this
.
configObj
.
enablePaging
!==
undefined
?
this
.
configObj
.
enablePaging
:
true
;
this
.
pageSize
=
this
.
configObj
.
pageSize
||
10
;
this
.
currentPage
=
this
.
configObj
.
currentPage
||
1
;
this
.
totalPages
=
this
.
configObj
.
totalPages
||
1
;
// Enhanced security configuration
this
.
requireHttps
=
this
.
configObj
.
requireHttps
!==
undefined
?
this
.
configObj
.
requireHttps
:
false
;
this
.
allowedRoles
=
this
.
configObj
.
allowedRoles
||
''
;
this
.
dataEncryption
=
this
.
configObj
.
dataEncryption
!==
undefined
?
this
.
configObj
.
dataEncryption
:
false
;
this
.
auditLog
=
this
.
configObj
.
auditLog
!==
undefined
?
this
.
configObj
.
auditLog
:
false
;
this
.
rateLimit
=
this
.
configObj
.
rateLimit
||
0
;
// Enhanced animation configuration
this
.
enableAnimations
=
this
.
configObj
.
enableAnimations
!==
undefined
?
this
.
configObj
.
enableAnimations
:
true
;
this
.
animationType
=
this
.
configObj
.
animationType
||
'fade'
;
this
.
animationDuration
=
this
.
configObj
.
animationDuration
||
300
;
this
.
animationDelay
=
this
.
configObj
.
animationDelay
||
0
;
// Enhanced style configuration
this
.
customCSS
=
this
.
configObj
.
customCSS
||
''
;
this
.
theme
=
this
.
configObj
.
theme
||
'light'
;
this
.
fontSize
=
this
.
configObj
.
fontSize
||
14
;
this
.
fontWeight
=
this
.
configObj
.
fontWeight
||
'normal'
;
this
.
fontFamily
=
this
.
configObj
.
fontFamily
||
'system-ui, -apple-system, sans-serif'
;
this
.
padding
=
this
.
configObj
.
padding
||
16
;
this
.
margin
=
this
.
configObj
.
margin
||
8
;
// Pivot features configuration
// Pivot features configuration
this
.
showFieldList
=
this
.
configObj
.
showFieldList
!==
undefined
?
this
.
configObj
.
showFieldList
:
true
;
this
.
showFieldList
=
this
.
configObj
.
showFieldList
!==
undefined
?
this
.
configObj
.
showFieldList
:
true
;
this
.
showToolbar
=
this
.
configObj
.
showToolbar
!==
undefined
?
this
.
configObj
.
showToolbar
:
true
;
this
.
showToolbar
=
this
.
configObj
.
showToolbar
!==
undefined
?
this
.
configObj
.
showToolbar
:
true
;
...
@@ -319,14 +424,46 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -319,14 +424,46 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
}
}
onDataUpdate
(
data
:
IDataSet
[]):
void
{
onDataUpdate
(
data
:
IDataSet
[]):
void
{
const
transformedData
=
this
.
transformData
(
data
);
try
{
this
.
dataSourceSettings
=
{
// Store original data
...
this
.
dataSourceSettings
,
this
.
originalData
=
data
||
[];
dataSource
:
new
DataManager
(
transformedData
)
this
.
dataCount
=
this
.
originalData
.
length
;
};
this
.
lastUpdated
=
new
Date
();
if
(
this
.
pivotview
)
{
this
.
isEmpty
=
this
.
originalData
.
length
===
0
;
this
.
pivotview
.
dataSourceSettings
.
dataSource
=
new
DataManager
(
transformedData
);
// The refresh is implicitly handled by the dataBound event now
// Transform data if transform function is provided
let
transformedData
=
this
.
transformData
(
data
);
// Apply filtering if enabled
if
(
this
.
enableFiltering
)
{
transformedData
=
this
.
applyDataFilter
(
transformedData
);
}
// Apply conditional formatting if enabled
if
(
this
.
allowConditionalFormatting
)
{
transformedData
=
this
.
applyConditionalFormatting
(
transformedData
);
}
this
.
dataSourceSettings
=
{
...
this
.
dataSourceSettings
,
dataSource
:
new
DataManager
(
transformedData
)
};
if
(
this
.
pivotview
)
{
this
.
pivotview
.
dataSourceSettings
.
dataSource
=
new
DataManager
(
transformedData
);
// The refresh is implicitly handled by the dataBound event now
}
// Update loading and error states
this
.
isLoading
=
false
;
this
.
hasError
=
false
;
this
.
cdr
.
detectChanges
();
}
catch
(
error
)
{
console
.
error
(
'Error updating pivot data:'
,
error
);
this
.
hasError
=
true
;
this
.
errorMessage
=
'Failed to update data'
;
this
.
isLoading
=
false
;
this
.
cdr
.
detectChanges
();
}
}
}
}
...
@@ -684,6 +821,41 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -684,6 +821,41 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
}
}
}
}
// Method to apply data filtering
private
applyDataFilter
(
data
:
any
[]):
any
[]
{
if
(
!
this
.
enableFiltering
||
!
data
)
{
return
data
;
}
try
{
// Apply basic filtering logic here
// This can be extended based on specific filtering requirements
return
data
;
}
catch
(
error
)
{
console
.
error
(
'Error applying data filter:'
,
error
);
return
data
;
}
}
// Method to apply conditional formatting
private
applyConditionalFormatting
(
data
:
any
[]):
any
[]
{
if
(
!
this
.
allowConditionalFormatting
||
!
data
)
{
return
data
;
}
try
{
// Apply conditional formatting logic here
// This can be extended based on specific formatting requirements
return
data
;
}
catch
(
error
)
{
console
.
error
(
'Error applying conditional formatting:'
,
error
);
return
data
;
}
}
// Export data functionality
// Export data functionality
exportData
(
event
:
Event
):
void
{
exportData
(
event
:
Event
):
void
{
if
(
event
)
{
if
(
event
)
{
...
@@ -740,4 +912,20 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
...
@@ -740,4 +912,20 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
this
.
isLoading
=
false
;
this
.
isLoading
=
false
;
},
1000
);
},
1000
);
}
}
// Toggle filter functionality
toggleFilter
(
event
:
Event
):
void
{
if
(
event
)
{
event
.
stopPropagation
();
}
this
.
enableFiltering
=
!
this
.
enableFiltering
;
// Apply or remove filtering
if
(
this
.
originalData
&&
this
.
originalData
.
length
>
0
)
{
this
.
onDataUpdate
(
this
.
originalData
);
}
console
.
log
(
'Filter toggled:'
,
this
.
enableFiltering
);
}
}
}
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