Commit 7ff59ecb by Ooh-Ao

kpi

parent fec4de97
......@@ -22,14 +22,15 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
MatCheckboxModule,
MatButtonModule,
MatIconModule,
MatTabsModule,
BaseConfigComponent
MatTabsModule
],
template: `
<app-base-config>
<!-- Basic Configuration Tab -->
<div class="config-section">
<h3 class="text-blue-600">Basic Configuration</h3>
<div class="config-container">
<mat-tab-group class="config-tabs">
<!-- Basic Configuration Tab -->
<mat-tab label="Basic">
<div class="config-section">
<h3 class="text-blue-600">Basic Configuration</h3>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
......@@ -141,11 +142,13 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
</mat-form-field>
</div>
</div>
</div>
</div>
</mat-tab>
<!-- Style Tab -->
<div class="config-section">
<h3 class="text-blue-600">Style Configuration</h3>
<!-- Style Tab -->
<mat-tab label="Style">
<div class="config-section">
<h3 class="text-blue-600">Style Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
......@@ -221,11 +224,13 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-hint>Drop shadow effect</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Icon Tab -->
<div class="config-section">
<h3 class="text-blue-600">Icon Configuration</h3>
<!-- Icon Tab -->
<mat-tab label="Icon">
<div class="config-section">
<h3 class="text-blue-600">Icon Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
......@@ -276,11 +281,13 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-hint>Icon color</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Filter Tab -->
<div class="config-section">
<h3 class="text-blue-600">Filter Configuration</h3>
<!-- Filter Tab -->
<mat-tab label="Filter">
<div class="config-section">
<h3 class="text-blue-600">Filter Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableFilter" name="enableFilter">
......@@ -325,11 +332,13 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-hint>Label for the filter</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Trend Tab -->
<div class="config-section">
<h3 class="text-blue-600">Trend Configuration</h3>
<!-- Trend Tab -->
<mat-tab label="Trend">
<div class="config-section">
<h3 class="text-blue-600">Trend Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.showTrend" name="showTrend">
......@@ -376,11 +385,13 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-hint>Threshold for significant trend</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Animation Tab -->
<div class="config-section">
<h3 class="text-blue-600">Animation Configuration</h3>
<!-- Animation Tab -->
<mat-tab label="Animation">
<div class="config-section">
<h3 class="text-blue-600">Animation Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableAnimations" name="enableAnimations">
......@@ -436,11 +447,13 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
Auto Refresh Animation
</mat-checkbox>
</div>
</div>
</div>
</mat-tab>
<!-- Condition Tab -->
<div class="config-section">
<h3 class="text-blue-600">Conditional Formatting</h3>
<!-- Condition Tab -->
<mat-tab label="Condition">
<div class="config-section">
<h3 class="text-blue-600">Conditional Formatting</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableConditionalFormatting" name="enableConditionalFormatting">
......@@ -492,21 +505,52 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
</mat-form-field>
</div>
</div>
</div>
</app-base-config>
</div>
</mat-tab>
</mat-tab-group>
</div>
`,
styles: [`
.config-container {
padding: 16px;
}
.config-section {
margin-bottom: 24px;
}
.config-tabs {
margin-top: 16px;
}
.config-tabs .mat-tab-body-content {
padding: 16px 0;
}
`]
})
export class SimpleKpiConfigComponent extends BaseConfigComponent implements OnInit {
override sizeOptions = [
{ id: 'small', label: 'Small', description: '200x150px' },
{ id: 'medium', label: 'Medium', description: '300x200px' },
{ id: 'large', label: 'Large', description: '400x300px' },
{ id: 'custom', label: 'Custom', description: 'Custom size' }
];
override ngOnInit() {
this.initializeDefaultConfig();
this.initializeColorDefaults();
}
override initializeDefaultConfig() {
if (!this.currentConfig.title) this.currentConfig.title = 'KPI Widget';
if (!this.currentConfig.valueField) this.currentConfig.valueField = 'value';
if (!this.currentConfig.labelField) this.currentConfig.labelField = 'label';
if (!this.currentConfig.aggregation) this.currentConfig.aggregation = 'sum';
if (!this.currentConfig.unit) this.currentConfig.unit = '';
if (!this.currentConfig.icon) this.currentConfig.icon = 'info';
if (this.currentConfig.decimalPlaces === undefined) this.currentConfig.decimalPlaces = 0;
if (!this.currentConfig.sizeOption) this.currentConfig.sizeOption = 'medium';
if (!this.currentConfig.width) this.currentConfig.width = '300px';
if (!this.currentConfig.height) this.currentConfig.height = '200px';
}
private initializeColorDefaults() {
if (!this.currentConfig.backgroundColor) this.currentConfig.backgroundColor = '#3366FF';
if (!this.currentConfig.textColor) this.currentConfig.textColor = '#FFFFFF';
......@@ -540,4 +584,19 @@ export class SimpleKpiConfigComponent extends BaseConfigComponent implements OnI
if (!this.currentConfig.conditionOperator) this.currentConfig.conditionOperator = 'greater_than';
if (!this.currentConfig.conditionValue) this.currentConfig.conditionValue = '';
}
override setSizeOption(optionId: string) {
this.currentConfig.sizeOption = optionId;
if (optionId === 'small') {
this.currentConfig.width = '200px';
this.currentConfig.height = '150px';
} else if (optionId === 'medium') {
this.currentConfig.width = '300px';
this.currentConfig.height = '200px';
} else if (optionId === 'large') {
this.currentConfig.width = '400px';
this.currentConfig.height = '300px';
}
this.configChange.emit(this.currentConfig);
}
}
......@@ -18,13 +18,13 @@
<style *ngIf="hasCustomCSS()" [innerHTML]="customCSS"></style>
<!-- Header -->
<div class="widget-header" [style.background]="backgroundColor">
<div class="widget-header" [style.background]="backgroundColor" [style.box-shadow]="getShadowStyles()">
<div class="header-content">
<div class="header-left">
<!-- {{icon}}
<i class="bi bi-{{icon}}"></i> -->
<i *ngIf="icon" [style.color]="iconColor" class="bi bi-{{icon}} header-icon"></i>
<!-- Icon with position support -->
<i *ngIf="icon && iconPosition === 'left'" [ngStyle]="getIconStyles()" class="bi bi-{{icon}} header-icon"></i>
<h4 class="widget-title" [style.color]="textColor">{{ title }}</h4>
<i *ngIf="icon && iconPosition === 'right'" [ngStyle]="getIconStyles()" class="bi bi-{{icon}} header-icon"></i>
</div>
<div *ngIf="showTrend && trendValue" class="trend-indicator" [ngStyle]="getTrendStyles()">
{{ trendValue }}
......@@ -50,13 +50,31 @@
<!-- Content -->
<div *ngIf="!isLoading && !hasError && hasRequiredRole()" class="widget-content">
<div class="kpi-value" [style.color]="accentColor">
<!-- Icon at top position -->
<div *ngIf="icon && iconPosition === 'top'" class="icon-top" [ngStyle]="getIconStyles()">
<i class="bi bi-{{icon}}"></i>
</div>
<!-- KPI Value with conditional formatting -->
<div class="kpi-value" [ngStyle]="getValueStyles()">
{{ value }}
</div>
<!-- Label from data field -->
<div *ngIf="label" class="kpi-label" [ngStyle]="getLabelStyles()">
{{ label }}
</div>
<!-- Unit display -->
<div *ngIf="unit" class="kpi-unit" [style.color]="textColor">
{{ unit }}
</div>
<!-- Icon at bottom position -->
<div *ngIf="icon && iconPosition === 'bottom'" class="icon-bottom" [ngStyle]="getIconStyles()">
<i class="bi bi-{{icon}}"></i>
</div>
<!-- Data Source Info (Debug Mode) -->
<div *ngIf="dataSource !== 'static'" class="data-source-info" [style.color]="textColor">
<small>{{ getDataSourceInfo() }}</small>
......
......@@ -174,6 +174,41 @@
opacity: 0.8;
}
.kpi-label {
font-size: 1rem;
font-weight: 500;
margin: 0;
opacity: 0.9;
text-align: center;
}
/* Icon positioning */
.icon-top {
display: flex;
justify-content: center;
margin-bottom: 0.5rem;
i {
display: block;
}
}
.icon-bottom {
display: flex;
justify-content: center;
margin-top: 0.5rem;
i {
display: block;
}
}
.header-left {
.header-icon {
flex-shrink: 0;
}
}
/* Responsive Design */
@media (max-width: 768px) {
.widget-header {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment