diff --git a/ng-ttc-frontend/package-lock.json b/ng-ttc-frontend/package-lock.json
index 0961f76..bbd14cb 100644
--- a/ng-ttc-frontend/package-lock.json
+++ b/ng-ttc-frontend/package-lock.json
@@ -25,15 +25,14 @@
"@fortawesome/free-brands-svg-icons": "^7.1.0",
"@fortawesome/free-regular-svg-icons": "^7.1.0",
"@fortawesome/free-solid-svg-icons": "^7.1.0",
- "@tailwindcss/postcss": "^4.1.16",
+ "@tailwindcss/postcss": "^4.1.17",
"bootstrap": "^5.3.8",
"chart.js": "^4.5.1",
"dotenv": "^17.2.3",
"jwt-decode": "^4.0.0",
"ng2-charts": "^6.0.1",
- "postcss": "^8.5.6",
"rxjs": "~7.8.0",
- "tailwindcss": "^4.1.16",
+ "tailwindcss": "^4.1.17",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
@@ -54,7 +53,7 @@
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"ngx-toastr": "^19.1.0",
- "postcss": "^8.5.3",
+ "postcss": "^8.5.6",
"typescript": "~5.9.3"
}
},
@@ -8275,7 +8274,6 @@
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -12051,7 +12049,6 @@
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -13816,7 +13813,6 @@
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -19904,7 +19900,6 @@
"integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
"dev": true,
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.14.0",
@@ -20911,6 +20906,7 @@
"integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/bonjour": "^3.5.13",
"@types/connect-history-api-fallback": "^1.5.4",
diff --git a/ng-ttc-frontend/package.json b/ng-ttc-frontend/package.json
index c52bb52..2f00fd2 100644
--- a/ng-ttc-frontend/package.json
+++ b/ng-ttc-frontend/package.json
@@ -57,15 +57,14 @@
"@fortawesome/free-brands-svg-icons": "^7.1.0",
"@fortawesome/free-regular-svg-icons": "^7.1.0",
"@fortawesome/free-solid-svg-icons": "^7.1.0",
- "@tailwindcss/postcss": "^4.1.16",
+ "@tailwindcss/postcss": "^4.1.17",
"bootstrap": "^5.3.8",
"chart.js": "^4.5.1",
"dotenv": "^17.2.3",
"jwt-decode": "^4.0.0",
"ng2-charts": "^6.0.1",
- "postcss": "^8.5.6",
"rxjs": "~7.8.0",
- "tailwindcss": "^4.1.16",
+ "tailwindcss": "^4.1.17",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
@@ -86,7 +85,7 @@
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"ngx-toastr": "^19.1.0",
- "postcss": "^8.5.3",
+ "postcss": "^8.5.6",
"typescript": "~5.9.3"
}
}
diff --git a/ng-ttc-frontend/public/ballot_0.png b/ng-ttc-frontend/public/ballot_0.png
new file mode 100644
index 0000000..587321d
Binary files /dev/null and b/ng-ttc-frontend/public/ballot_0.png differ
diff --git a/ng-ttc-frontend/public/bell_0.png b/ng-ttc-frontend/public/bell_0.png
new file mode 100644
index 0000000..9033761
Binary files /dev/null and b/ng-ttc-frontend/public/bell_0.png differ
diff --git a/ng-ttc-frontend/public/calendar_0.png b/ng-ttc-frontend/public/calendar_0.png
new file mode 100644
index 0000000..9e8486b
Binary files /dev/null and b/ng-ttc-frontend/public/calendar_0.png differ
diff --git a/ng-ttc-frontend/public/chart-histogram_0.png b/ng-ttc-frontend/public/chart-histogram_0.png
new file mode 100644
index 0000000..e271693
Binary files /dev/null and b/ng-ttc-frontend/public/chart-histogram_0.png differ
diff --git a/ng-ttc-frontend/public/chart-simple.png b/ng-ttc-frontend/public/chart-simple.png
new file mode 100644
index 0000000..4f7bbc6
Binary files /dev/null and b/ng-ttc-frontend/public/chart-simple.png differ
diff --git a/ng-ttc-frontend/public/check_0.png b/ng-ttc-frontend/public/check_0.png
new file mode 100644
index 0000000..3e073fd
Binary files /dev/null and b/ng-ttc-frontend/public/check_0.png differ
diff --git a/ng-ttc-frontend/public/coins_0.png b/ng-ttc-frontend/public/coins_0.png
new file mode 100644
index 0000000..8307ac9
Binary files /dev/null and b/ng-ttc-frontend/public/coins_0.png differ
diff --git a/ng-ttc-frontend/public/exclamation_0.png b/ng-ttc-frontend/public/exclamation_0.png
new file mode 100644
index 0000000..d5c4a6b
Binary files /dev/null and b/ng-ttc-frontend/public/exclamation_0.png differ
diff --git a/ng-ttc-frontend/public/exit_0.png b/ng-ttc-frontend/public/exit_0.png
new file mode 100644
index 0000000..1e42767
Binary files /dev/null and b/ng-ttc-frontend/public/exit_0.png differ
diff --git a/ng-ttc-frontend/public/form_0.png b/ng-ttc-frontend/public/form_0.png
new file mode 100644
index 0000000..3bb344b
Binary files /dev/null and b/ng-ttc-frontend/public/form_0.png differ
diff --git a/ng-ttc-frontend/public/home (1)_0.png b/ng-ttc-frontend/public/home (1)_0.png
new file mode 100644
index 0000000..4c1f9c7
Binary files /dev/null and b/ng-ttc-frontend/public/home (1)_0.png differ
diff --git a/ng-ttc-frontend/public/home_0.png b/ng-ttc-frontend/public/home_0.png
new file mode 100644
index 0000000..dbae118
Binary files /dev/null and b/ng-ttc-frontend/public/home_0.png differ
diff --git a/ng-ttc-frontend/public/icons8-home-384.png b/ng-ttc-frontend/public/icons8-home-384.png
new file mode 100644
index 0000000..cd4af1e
Binary files /dev/null and b/ng-ttc-frontend/public/icons8-home-384.png differ
diff --git a/ng-ttc-frontend/public/interrogation.png b/ng-ttc-frontend/public/interrogation.png
new file mode 100644
index 0000000..dc91bca
Binary files /dev/null and b/ng-ttc-frontend/public/interrogation.png differ
diff --git a/ng-ttc-frontend/public/interrogation_0.png b/ng-ttc-frontend/public/interrogation_0.png
new file mode 100644
index 0000000..f9a8926
Binary files /dev/null and b/ng-ttc-frontend/public/interrogation_0.png differ
diff --git a/ng-ttc-frontend/public/locked-computer_0.png b/ng-ttc-frontend/public/locked-computer_0.png
new file mode 100644
index 0000000..ec69243
Binary files /dev/null and b/ng-ttc-frontend/public/locked-computer_0.png differ
diff --git a/ng-ttc-frontend/public/menu-burger_0.png b/ng-ttc-frontend/public/menu-burger_0.png
new file mode 100644
index 0000000..18afa1c
Binary files /dev/null and b/ng-ttc-frontend/public/menu-burger_0.png differ
diff --git a/ng-ttc-frontend/public/pencil_0.png b/ng-ttc-frontend/public/pencil_0.png
new file mode 100644
index 0000000..6d7cc83
Binary files /dev/null and b/ng-ttc-frontend/public/pencil_0.png differ
diff --git a/ng-ttc-frontend/public/plus-small_0.png b/ng-ttc-frontend/public/plus-small_0.png
new file mode 100644
index 0000000..524297a
Binary files /dev/null and b/ng-ttc-frontend/public/plus-small_0.png differ
diff --git a/ng-ttc-frontend/public/search_0.png b/ng-ttc-frontend/public/search_0.png
new file mode 100644
index 0000000..3950982
Binary files /dev/null and b/ng-ttc-frontend/public/search_0.png differ
diff --git a/ng-ttc-frontend/public/settings (1)_0.png b/ng-ttc-frontend/public/settings (1)_0.png
new file mode 100644
index 0000000..7a85563
Binary files /dev/null and b/ng-ttc-frontend/public/settings (1)_0.png differ
diff --git a/ng-ttc-frontend/public/stamp_0.png b/ng-ttc-frontend/public/stamp_0.png
new file mode 100644
index 0000000..eff1d87
Binary files /dev/null and b/ng-ttc-frontend/public/stamp_0.png differ
diff --git a/ng-ttc-frontend/public/user_0.png b/ng-ttc-frontend/public/user_0.png
new file mode 100644
index 0000000..9afed7b
Binary files /dev/null and b/ng-ttc-frontend/public/user_0.png differ
diff --git a/ng-ttc-frontend/src/app/app-routing.module.ts b/ng-ttc-frontend/src/app/app-routing.module.ts
index ee3b68c..533010d 100644
--- a/ng-ttc-frontend/src/app/app-routing.module.ts
+++ b/ng-ttc-frontend/src/app/app-routing.module.ts
@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SidebarContentComponent } from './content/sidebar-content/sidebar-content.component';
import { LicensePrivacyTermsComponent } from './component/license-privacy-terms/license-privacy-terms.component';
-// import { authGuard } from './services/auth.guard';
+import { authGuard } from './services/auth.guard';
const routes: Routes = [
@@ -14,7 +14,7 @@ const routes: Routes = [
path: 'main',
component: SidebarContentComponent,
canActivate: [
- // authGuard
+ authGuard
],
children: [
{
diff --git a/ng-ttc-frontend/src/app/app.module.ts b/ng-ttc-frontend/src/app/app.module.ts
index dcffdd5..c2d33fd 100644
--- a/ng-ttc-frontend/src/app/app.module.ts
+++ b/ng-ttc-frontend/src/app/app.module.ts
@@ -23,6 +23,7 @@ import { LicensePrivacyTermsComponent } from './component/license-privacy-terms/
import { provideCharts, withDefaultRegisterables } from 'ng2-charts';
+// import { BudgetAproval } from './component/budget-aproval/budget-aproval';
// import { AccDateFormatPipe } from './pipe/dtmtodatetime.pipe';
// import { DtmtodatetimePipe } from './dtmtodatetime.pipe';
@@ -33,6 +34,7 @@ import { provideCharts, withDefaultRegisterables } from 'ng2-charts';
SidebarContentComponent,
SidebarComponent,
LicensePrivacyTermsComponent,
+ // BudgetAproval,
// AccDateFormatPipe
// DtmtodatetimePipe,
// MainDashboardContentComponent,
diff --git a/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.css b/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.css
new file mode 100644
index 0000000..e69de29
diff --git a/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.html b/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.html
new file mode 100644
index 0000000..279e184
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.html
@@ -0,0 +1,197 @@
+
+
+
+
+
+ รายการงบประมาณของโครงการ: {{ project?.name }}
+
+
+
+ แสดงข้อมูล {{ budgetItems.length }} รายการ
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ยอดรวมทั้งหมด:
+
+ {{ getTotalAmount() | number:'1.0-2' }} บาท
+
+
+
+
diff --git a/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.ts b/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.ts
new file mode 100644
index 0000000..07f7c9c
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/budget-aproval/budget-aproval.ts
@@ -0,0 +1,109 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
+import { GeneralService } from '../../services/generalservice';
+import { IDropAct, IStateDrop, IStateResultResponse, IActData, IActSumData } from '../../interfaces/dashboard.interface'
+import { DashboardStateService } from '../../services/state/dashboard-state.service';
+import { Router } from '@angular/router';
+import { ActivatedRoute } from '@angular/router';
+
+@Component({
+ selector: 'app-budget-aproval',
+ standalone: false,
+ templateUrl: './budget-aproval.html',
+ styleUrl: './budget-aproval.css',
+})
+export class BudgetAproval {
+ projectCode: any;
+ project: any;
+ addItemForm!: FormGroup;
+
+ budgetItems = [
+ { code: 'ITEM001', name: 'เอกซ์เรย์', qty: 1, price: 1000 },
+ { code: 'ITEM002', name: 'กรอกคำสั่งซื้อ', qty: 1, price: 1500 },
+ { code: 'ITEM003', name: 'ตรวจพื้นฐาน', qty: 1, price: 1000 },
+ ];
+
+ budgetCategoriesDrop = {
+ expense: [
+ { dtlcod: 'BDG001', dtlnam: 'เงินรายได้' },
+ { dtlcod: 'BDG002', dtlnam: 'งบดำเนินงาน ปวส.' },
+ { dtlcod: 'BDG003', dtlnam: 'โครงการส่งเสริมพัฒนาทักษะวิชาชีพทักษะพื้นฐาน' },
+ { dtlcod: 'BDG004', dtlnam: 'ค่ากิจกรรมพัฒนาคุณภาพผู้เรียน' },
+ { dtlcod: 'BDG005', dtlnam: 'อุดหนุนส่งเสริมและพัฒนาผู้เรียนองค์การวิชาชีพแห่งประเทศไทย (อวท.)' },
+ { dtlcod: 'BDG006', dtlnam: 'งบดำเนินงาน ระยะสั้น' },
+ { dtlcod: 'BDG007', dtlnam: 'โครงการบูรณาการการพัฒนาทักษะทางวิชาชีพกับการเสริมสร้างคุณลักษณะอันพึงประสงค์ (FIX IT)' },
+ { dtlcod: 'BDG008', dtlnam: 'โครงการพัฒนาทักษะและสมรรถนะวิชาชีพกำลังคน (Up-skill, Re-skill)' },
+ { dtlcod: 'BDG009', dtlnam: 'งบดำเนินงาน ปวช.' },
+ { dtlcod: 'BDG010', dtlnam: 'โครงการขยายและยกระดับการจัดอาชีวศึกษาระบบทวิภาคีคุณภาพสูง' },
+ { dtlcod: 'BDG011', dtlnam: 'ปวช.(สอจ)' },
+ { dtlcod: 'BDG012', dtlnam: 'ค่าจัดการเรียนการสอน' },
+ { dtlcod: 'BDG013', dtlnam: 'งบดำเนินงาน 170000' },
+ { dtlcod: 'BDG014', dtlnam: 'โครงการพัฒนาทักษะและศักยภาพภาพการจัดการเรียนการสอนอาชีวศึกษา' },
+ { dtlcod: 'BDG015', dtlnam: 'ศึกษาธิการ' },
+ { dtlcod: 'BDG016', dtlnam: 'Up-skill' },
+ { dtlcod: 'BDG017', dtlnam: 'ติดตามผู้สำเร็จ' },
+ { dtlcod: 'BDG018', dtlnam: 'ทวิภาคี' },
+ { dtlcod: 'BDG019', dtlnam: 'พันธุกรรม' },
+ { dtlcod: 'BDG020', dtlnam: 'ปวส(สาธารณูประโภค)' },
+ { dtlcod: 'BDG021', dtlnam: 'ปวส(ค่าสาธารณูปโภค)' },
+ { dtlcod: 'BDG022', dtlnam: 'งบดำเนินงาน (ค่าสาธารณูปโภค)' },
+ { dtlcod: 'BDG023', dtlnam: 'ค่าหนังสือเรียน' },
+ { dtlcod: 'BDG024', dtlnam: 'โครงการอาชีวะต้านยาเสพติด' },
+ { dtlcod: 'BDG025', dtlnam: 'ค่าตอบแทนพนักงานราชการ' },
+ { dtlcod: 'BDG026', dtlnam: 'ค่าอุปกรณ์การเรียน' },
+ { dtlcod: 'BDG027', dtlnam: 'โครงการยกระดับและพัฒนาขีดความสามารถด้านภาษาและทักษะดิจิทัลเพื่อพัฒนากำลังคนให้มีสมรรถนะสูง' },
+ { dtlcod: 'BDG028', dtlnam: 'โครงการอนุรักษ์พันธุกรรมพืชอันเนื่องมาจากพระราชดำริ' },
+ { dtlcod: 'BDG029', dtlnam: 'ปวช.(สอจ.)' },
+ { dtlcod: 'BDG030', dtlnam: 'โครงการพัฒนาศักยภาพผู้เรียนอาชีวศึกษาในการเป็นผู้ประกอบการ (บ่มเพาะ)' },
+ { dtlcod: 'BDG031', dtlnam: 'โครงการพัฒนาและยกระดับการติดตามผู้สำเร็จการศึกษาอาชีวศึกษา' },
+ { dtlcod: 'BDG032', dtlnam: 'โครงการเสริมสร้างคุณธรรม จริยธรรมและธรรมาภิบาลในสถานศึกษา' },
+ { dtlcod: 'BDG033', dtlnam: 'โครงการจัดการอาชีวศึกษาเพื่อสนองพระราชดำริ' },
+ { dtlcod: 'BDG034', dtlnam: 'เงินรายได้ ป.ตรี' },
+ { dtlcod: 'BDG035', dtlnam: 'งบดำเนินงาน 235200' }
+ ]
+};
+
+
+ngOnInit(): void {
+ this.setupForm();
+}
+
+setupForm() {
+ this.addItemForm = new FormGroup({
+ category: new FormControl('', [Validators.required]),
+ name: new FormControl('', [Validators.required]),
+ qty: new FormControl(1, [Validators.required, Validators.min(1)]),
+ price: new FormControl(0, [Validators.required, Validators.min(1)])
+ });
+}
+
+addBudgetItem() {
+ if (this.addItemForm.invalid) {
+ this.addItemForm.markAllAsTouched();
+ return;
+ }
+
+ const formValue = this.addItemForm.value;
+
+ this.budgetItems.push({
+ code: 'NEW' + (this.budgetItems.length + 1).toString().padStart(3, '0'),
+ name: formValue.name,
+ qty: formValue.qty,
+ price: formValue.price,
+ // category: formValue.category
+ });
+
+ // reset form
+ this.addItemForm.reset({
+ category: '',
+ name: '',
+ qty: 1,
+ price: 0
+ });
+}
+
+getTotalAmount() {
+ return this.budgetItems.reduce((sum, item) => sum + item.qty * item.price, 0);
+}
+
+}
diff --git a/ng-ttc-frontend/src/app/component/main-dashboard/main-dashboard.component.css b/ng-ttc-frontend/src/app/component/main-dashboard/main-dashboard.component.css
index 70db525..f9e1370 100644
--- a/ng-ttc-frontend/src/app/component/main-dashboard/main-dashboard.component.css
+++ b/ng-ttc-frontend/src/app/component/main-dashboard/main-dashboard.component.css
@@ -643,4 +643,4 @@
max-height: 25rem;
overflow-y: auto;
padding-right: 0.5rem;
-}
\ No newline at end of file
+}
diff --git a/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.css b/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.html b/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.html
new file mode 100644
index 0000000..275fd54
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.html
@@ -0,0 +1,107 @@
+
+
+ หน้าหลัก ( landing )
+
+
+
+
+

+
+

+
+
+
+
+
+
+
+
+
เมนู
+
+
+
+
+
+
สัญญา / ข้อตกลง
+
+
+
+
+

+
การอนุมัติโครงการ
+
+
+
+
+
เอกสารฟอร์มวิทยาลัย
+
+
+
+
+

+
จัดสรรงบประมาณ
+
+
+
+
+
วิเคราะห์ & รายงาน
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
diff --git a/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.ts b/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.ts
new file mode 100644
index 0000000..12414c8
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/main-landing/main-landing.component.ts
@@ -0,0 +1,18 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'app-main-landing',
+ standalone: false,
+ templateUrl: './main-landing.component.html',
+ styleUrls: ['./main-landing.component.css']
+})
+export class MainLandingComponent implements OnInit {
+
+ constructor(
+
+ ) {}
+
+ ngOnInit() {
+ }
+
+}
diff --git a/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.css b/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.css
new file mode 100644
index 0000000..70db525
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.css
@@ -0,0 +1,646 @@
+:host {
+ display: block;
+ padding: 2rem clamp(1.25rem, 4vw, 3rem) 3rem;
+ background: radial-gradient(120% 120% at 0% 0%, #f6f8ff 0%, #eef5ff 55%, #ffffff 100%);
+ min-height: 100%;
+}
+
+.dashboard {
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+ max-width: 1280px;
+ margin: 0 auto;
+}
+
+.dashboard__hero {
+ background: #0f172a;
+ color: #f8fafc;
+ padding: 2rem;
+ border-radius: 28px;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1.5rem;
+ justify-content: space-between;
+ align-items: center;
+ box-shadow: 0 20px 50px rgba(15, 23, 42, 0.3);
+}
+
+.hero__text h1 {
+ margin: 0 0 0.5rem;
+ font-size: clamp(1.8rem, 3vw, 2.5rem);
+}
+
+.hero__subtitle {
+ margin: 0;
+ color: rgba(248, 250, 252, 0.7);
+}
+
+.eyebrow {
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ font-size: 0.8rem;
+ color: rgba(248, 250, 252, 0.8);
+ margin: 0 0 0.5rem;
+}
+
+.hero__actions {
+ display: flex;
+ gap: 0.75rem;
+ flex-wrap: wrap;
+}
+
+.btn {
+ border: none;
+ border-radius: 999px;
+ padding: 0.65rem 1.5rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.btn--primary {
+ background: linear-gradient(135deg, #22d3ee, #0ea5e9);
+ color: #0f172a;
+ box-shadow: 0 15px 30px rgba(14, 165, 233, 0.35);
+}
+
+.btn--ghost {
+ background: rgba(248, 250, 252, 0.12);
+ color: #f8fafc;
+ border: 1px solid rgba(248, 250, 252, 0.2);
+}
+
+.btn--compact {
+ padding: 0.45rem 1.15rem;
+ font-size: 0.9rem;
+}
+
+.btn:focus-visible {
+ outline: 3px solid rgba(14, 165, 233, 0.4);
+ outline-offset: 3px;
+}
+
+.btn:hover {
+ transform: translateY(-1px);
+}
+
+.dashboard__stats {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
+ gap: 1rem;
+}
+
+.dashboard__periods {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+ gap: 1rem;
+}
+
+.period-card {
+ background: rgba(15, 23, 42, 0.85);
+ color: #f8fafc;
+ border-radius: 22px;
+ padding: 1.25rem 1.5rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ box-shadow: 0 18px 35px rgba(15, 23, 42, 0.4);
+}
+
+.period-card__header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 0.9rem;
+ color: rgba(248, 250, 252, 0.75);
+}
+
+.period-card__badge {
+ padding: 0.2rem 0.75rem;
+ border-radius: 999px;
+ font-size: 0.8rem;
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.period-card__badge--year { background: rgba(248, 250, 252, 0.14); }
+.period-card__badge--month { background: rgba(125, 211, 252, 0.25); }
+.period-card__badge--week { background: rgba(110, 231, 183, 0.2); }
+
+.period-card__values {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 0.75rem;
+}
+
+.muted {
+ margin: 0;
+ font-size: 0.8rem;
+ color: rgba(248, 250, 252, 0.65);
+}
+
+.income,
+.expense,
+.net {
+ margin: 0.1rem 0 0;
+ font-size: 1.2rem;
+ font-weight: 600;
+}
+
+.income { color: #34d399; }
+.expense { color: #fbbf24; }
+.net { color: #38bdf8; }
+
+.trend-chip {
+ background: rgba(248, 250, 252, 0.12);
+ padding: 0.35rem 0.9rem;
+ border-radius: 999px;
+ font-size: 0.85rem;
+ font-weight: 600;
+ align-self: flex-start;
+}
+
+.stat-card {
+ background: #ffffff;
+ border-radius: 20px;
+ padding: 1.25rem;
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+ box-shadow: 0 8px 30px rgba(15, 23, 42, 0.08);
+}
+
+.stat-card__icon {
+ width: 52px;
+ height: 52px;
+ border-radius: 16px;
+ flex-shrink: 0;
+ background: #e2e8f0;
+}
+
+.accent-mint { background: linear-gradient(135deg, #a7f3d0, #34d399); }
+.accent-lavender { background: linear-gradient(135deg, #ddd6fe, #a78bfa); }
+.accent-amber { background: linear-gradient(135deg, #fde68a, #fbbf24); }
+.accent-teal { background: linear-gradient(135deg, #99f6e4, #14b8a6); }
+
+.stat-card__label {
+ margin: 0;
+ color: #475569;
+ font-size: 0.9rem;
+}
+
+.stat-card__value {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: #0f172a;
+}
+
+.stat-card__trend {
+ margin: 0;
+ color: #64748b;
+ font-size: 0.85rem;
+}
+
+.dashboard__grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 1.5rem;
+}
+
+.panel {
+ background: #ffffff;
+ border-radius: 24px;
+ padding: 1.5rem;
+ box-shadow: 0 12px 35px rgba(15, 23, 42, 0.08);
+ display: flex;
+ flex-direction: column;
+ gap: 1.2rem;
+}
+
+.panel--main {
+ grid-column: span 2;
+ min-height: 280px;
+}
+
+.panel--side {
+ grid-column: span 1;
+}
+
+@media (max-width: 900px) {
+ .panel--main {
+ grid-column: span 1;
+ }
+}
+
+.panel__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+}
+
+.panel__header h2 {
+ margin: 0;
+ font-size: 1.2rem;
+}
+
+.panel__header p {
+ margin: 0;
+ color: #94a3b8;
+ font-size: 0.9rem;
+}
+
+.ledger-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: 1.5rem;
+}
+
+.quick-log__form {
+ display: flex;
+ flex-direction: column;
+ gap: 0.9rem;
+}
+
+.quick-log__form label {
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+ font-size: 0.9rem;
+ color: #475569;
+}
+
+.quick-log__form input,
+.quick-log__form textarea {
+ border: 1px solid #e2e8f0;
+ border-radius: 14px;
+ padding: 0.75rem 1rem;
+ font-family: inherit;
+ font-size: 0.95rem;
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
+}
+
+.quick-log__form input:focus,
+.quick-log__form textarea:focus {
+ border-color: #0ea5e9;
+ box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
+ outline: none;
+}
+
+.quick-log__grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 0.85rem;
+}
+
+.quick-log__toggle {
+ display: inline-flex;
+ gap: 0.4rem;
+ background: #f1f5f9;
+ border-radius: 999px;
+ padding: 0.25rem;
+}
+
+.toggle-btn {
+ border: none;
+ background: transparent;
+ border-radius: 999px;
+ padding: 0.4rem 1.1rem;
+ font-weight: 600;
+ color: #475569;
+ cursor: pointer;
+}
+
+.toggle-btn.is-active {
+ background: #0ea5e9;
+ color: #f8fafc;
+}
+
+.ledger-table {
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+}
+
+.pie-panel__content {
+ display: grid;
+ grid-template-columns: minmax(220px, 1fr) 1fr;
+ gap: 2rem;
+ align-items: center;
+}
+
+.pie-chart {
+ width: 220px;
+ height: 220px;
+ border-radius: 50%;
+ position: relative;
+ margin: 0 auto;
+ box-shadow: inset 0 0 20px rgba(15, 23, 42, 0.08);
+}
+
+.pie-chart__center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 120px;
+ height: 120px;
+ border-radius: 50%;
+ background: #ffffff;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ box-shadow: 0 10px 25px rgba(15, 23, 42, 0.1);
+}
+
+.pie-chart__center p {
+ margin: 0;
+ font-size: 0.85rem;
+ color: #94a3b8;
+}
+
+.pie-chart__center strong {
+ font-size: 1.2rem;
+ color: #0f172a;
+}
+
+.pie-legend {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.75rem;
+}
+
+.pie-legend__item {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.4rem 0;
+}
+
+.swatch {
+ width: 14px;
+ height: 14px;
+ border-radius: 4px;
+}
+
+.pie-legend__label {
+ margin: 0;
+ font-weight: 600;
+ color: #0f172a;
+}
+
+.pie-legend__value {
+ margin: 0;
+ color: #94a3b8;
+ font-size: 0.85rem;
+}
+
+.ledger-row {
+ display: grid;
+ grid-template-columns: 2fr 1fr 0.8fr 1.2fr;
+ gap: 1rem;
+ align-items: center;
+ padding: 0.75rem 0.4rem;
+ border-bottom: 1px solid #e2e8f0;
+}
+
+.ledger-head {
+ text-transform: uppercase;
+ font-size: 0.75rem;
+ letter-spacing: 0.08em;
+ color: #94a3b8;
+}
+
+.ledger-main {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+}
+
+.pill {
+ padding: 0.2rem 0.7rem;
+ border-radius: 999px;
+ font-size: 0.8rem;
+ font-weight: 600;
+}
+
+.pill--income {
+ background: rgba(16, 185, 129, 0.12);
+ color: #059669;
+}
+
+.pill--expense {
+ background: rgba(248, 113, 113, 0.15);
+ color: #dc2626;
+}
+
+.ledger-title {
+ margin: 0;
+ font-weight: 600;
+}
+
+.ledger-date {
+ margin: 0;
+ font-size: 0.85rem;
+ color: #94a3b8;
+}
+
+.ledger-category {
+ font-weight: 500;
+ color: #475569;
+}
+
+.ledger-amount {
+ font-weight: 700;
+}
+
+.ledger-note {
+ color: #64748b;
+ font-size: 0.9rem;
+}
+
+.trend-chart {
+ display: flex;
+ gap: 1rem;
+ align-items: flex-end;
+ min-height: 180px;
+}
+
+.trend-chart__bar {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.trend-chart__value {
+ width: 100%;
+ border-radius: 16px 16px 6px 6px;
+ background: linear-gradient(180deg, rgba(14, 165, 233, 0.8) 0%, rgba(56, 189, 248, 0.4) 100%);
+}
+
+.trend-chart__label {
+ font-size: 0.85rem;
+ color: #475569;
+}
+
+.ratio-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.ratio {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-radius: 18px;
+ padding: 0.85rem 1.2rem;
+ font-weight: 600;
+}
+
+.ratio--positive {
+ background: rgba(16, 185, 129, 0.12);
+ color: #047857;
+}
+
+.ratio--neutral {
+ background: rgba(59, 130, 246, 0.12);
+ color: #1d4ed8;
+}
+
+.ratio--warning {
+ background: rgba(251, 191, 36, 0.15);
+ color: #b45309;
+}
+
+.alerts-panel .alert {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background: #f8fafc;
+ border-radius: 18px;
+ padding: 1rem 1.2rem;
+ gap: 1rem;
+}
+
+.alert__title {
+ margin: 0 0 0.3rem;
+ font-weight: 600;
+ color: #0f172a;
+}
+
+.alert__detail {
+ margin: 0;
+ color: #64748b;
+ font-size: 0.9rem;
+}
+
+.alert__tag {
+ padding: 0.4rem 0.9rem;
+ border-radius: 999px;
+ background: #e0f2fe;
+ color: #0369a1;
+ font-size: 0.85rem;
+ font-weight: 600;
+}
+
+.task-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.85rem;
+}
+
+.task {
+ background: #f8fafc;
+ border-radius: 18px;
+ padding: 1rem 1.2rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 1rem;
+}
+
+.task__title {
+ margin: 0 0 0.25rem;
+ font-weight: 600;
+}
+
+.task__due {
+ margin: 0;
+ color: #94a3b8;
+ font-size: 0.9rem;
+}
+
+.task__badge {
+ padding: 0.35rem 0.8rem;
+ border-radius: 12px;
+ background: #e2e8f0;
+ font-weight: 600;
+}
+
+.is-credit {
+ color: #10b981;
+ font-weight: 600;
+}
+
+.is-debit {
+ color: #ef4444;
+ font-weight: 600;
+}
+
+@media (max-width: 640px) {
+ .dashboard__hero,
+ .panel {
+ padding: 1.25rem;
+ }
+
+ .quick-log__grid {
+ grid-template-columns: 1fr;
+ }
+
+ .pie-panel__content {
+ grid-template-columns: 1fr;
+ }
+
+ .pie-chart {
+ width: 180px;
+ height: 180px;
+ }
+
+ .ledger-row {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .ledger-row span:nth-child(3),
+ .ledger-row span:nth-child(4) {
+ text-align: left;
+ }
+}
+
+.quick-log__form select {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
+ background-position: right 0.5rem center;
+ background-repeat: no-repeat;
+ background-size: 1.5em 1.5em;
+ padding-right: 2.5rem;
+}
+
+.ledger-table.is-scrollable {
+ max-height: 25rem;
+ overflow-y: auto;
+ padding-right: 0.5rem;
+}
\ No newline at end of file
diff --git a/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.html b/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.html
new file mode 100644
index 0000000..277c5a3
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.html
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
งบทั้งหมด
+
+ {{ totalBudget | number:'1.0-2' }} บาท
+
+
+
+
+
งบที่อนุมัติแล้ว
+
+ {{ approvedBudget | number:'1.0-2' }} บาท
+
+
+
+
+
งบคงเหลือ
+
= 0 ? 'text-blue-600' : 'text-red-600'"
+ >
+ {{ remainingBudget | number:'1.0-2' }} บาท
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.ts b/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.ts
new file mode 100644
index 0000000..17e33f2
--- /dev/null
+++ b/ng-ttc-frontend/src/app/component/main-manager/main-manager.component.ts
@@ -0,0 +1,168 @@
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
+import { GeneralService } from '../../services/generalservice';
+import { IDropAct, IStateDrop, IStateResultResponse, IActData, IActSumData } from '../../interfaces/dashboard.interface'
+import { DashboardStateService } from '../../services/state/dashboard-state.service';
+import { Router } from '@angular/router';
+
+@Component({
+ selector: 'app-main-manager',
+ standalone: false,
+ templateUrl: './main-manager.component.html',
+ styleUrl: './main-manager.component.css'
+})
+export class MainManagerComponent implements OnInit {
+
+ mode: string = 'i';
+
+ totalBudget = 200000; // งบทั้งหมด
+ approvedBudget = 65000; // งบที่อนุมัติแล้ว
+
+
+
+ get remainingBudget() {
+ return this.totalBudget - this.approvedBudget;
+ }
+
+
+
+ projects = [
+ { code: 'PRJ001', name: 'ระบบจัดการน้ำดื่ม', owner: 'นาย A', budget: 20000, status: 'WAIT' },
+ { code: 'PRJ002', name: 'ปรับปรุงอาคาร B', owner: 'นางสาว B', budget: 45000, status: 'WAIT' },
+ { code: 'PRJ003', name: 'ซื้อคอมพิวเตอร์', owner: 'นาย C', budget: 30000, status: 'APPROVED' }
+ ];
+
+ approveProject(p: any) {
+ p.status = 'APPROVED';
+ this.approvedBudget += p.budget;
+ }
+
+ rejectProject(p: any) {
+ p.status = 'REJECTED';
+ }
+
+ openBudgetDetail(project: any) {
+ this.router.navigate(['/main/manager/budget', project.code]);
+ }
+
+
+
+ budgetCategoriesDrop = {
+ expense: [
+ { dtlcod: 'BDG001', dtlnam: 'เงินรายได้' },
+ { dtlcod: 'BDG002', dtlnam: 'งบดำเนินงาน ปวส.' },
+ { dtlcod: 'BDG003', dtlnam: 'โครงการส่งเสริมพัฒนาทักษะวิชาชีพทักษะพื้นฐาน' },
+ { dtlcod: 'BDG004', dtlnam: 'ค่ากิจกรรมพัฒนาคุณภาพผู้เรียน' },
+ { dtlcod: 'BDG005', dtlnam: 'อุดหนุนส่งเสริมและพัฒนาผู้เรียนองค์การวิชาชีพแห่งประเทศไทย (อวท.)' },
+ { dtlcod: 'BDG006', dtlnam: 'งบดำเนินงาน ระยะสั้น' },
+ { dtlcod: 'BDG007', dtlnam: 'โครงการบูรณาการการพัฒนาทักษะทางวิชาชีพกับการเสริมสร้างคุณลักษณะอันพึงประสงค์ (FIX IT)' },
+ { dtlcod: 'BDG008', dtlnam: 'โครงการพัฒนาทักษะและสมรรถนะวิชาชีพกำลังคน (Up-skill, Re-skill)' },
+ { dtlcod: 'BDG009', dtlnam: 'งบดำเนินงาน ปวช.' },
+ { dtlcod: 'BDG010', dtlnam: 'โครงการขยายและยกระดับการจัดอาชีวศึกษาระบบทวิภาคีคุณภาพสูง' },
+ { dtlcod: 'BDG011', dtlnam: 'ปวช.(สอจ)' },
+ { dtlcod: 'BDG012', dtlnam: 'ค่าจัดการเรียนการสอน' },
+ { dtlcod: 'BDG013', dtlnam: 'งบดำเนินงาน 170000' },
+ { dtlcod: 'BDG014', dtlnam: 'โครงการพัฒนาทักษะและศักยภาพภาพการจัดการเรียนการสอนอาชีวศึกษา' },
+ { dtlcod: 'BDG015', dtlnam: 'ศึกษาธิการ' },
+ { dtlcod: 'BDG016', dtlnam: 'Up-skill' },
+ { dtlcod: 'BDG017', dtlnam: 'ติดตามผู้สำเร็จ' },
+ { dtlcod: 'BDG018', dtlnam: 'ทวิภาคี' },
+ { dtlcod: 'BDG019', dtlnam: 'พันธุกรรม' },
+ { dtlcod: 'BDG020', dtlnam: 'ปวส(สาธารณูประโภค)' },
+ { dtlcod: 'BDG021', dtlnam: 'ปวส(ค่าสาธารณูปโภค)' },
+ { dtlcod: 'BDG022', dtlnam: 'งบดำเนินงาน (ค่าสาธารณูปโภค)' },
+ { dtlcod: 'BDG023', dtlnam: 'ค่าหนังสือเรียน' },
+ { dtlcod: 'BDG024', dtlnam: 'โครงการอาชีวะต้านยาเสพติด' },
+ { dtlcod: 'BDG025', dtlnam: 'ค่าตอบแทนพนักงานราชการ' },
+ { dtlcod: 'BDG026', dtlnam: 'ค่าอุปกรณ์การเรียน' },
+ { dtlcod: 'BDG027', dtlnam: 'โครงการยกระดับและพัฒนาขีดความสามารถด้านภาษาและทักษะดิจิทัลเพื่อพัฒนากำลังคนให้มีสมรรถนะสูง' },
+ { dtlcod: 'BDG028', dtlnam: 'โครงการอนุรักษ์พันธุกรรมพืชอันเนื่องมาจากพระราชดำริ' },
+ { dtlcod: 'BDG029', dtlnam: 'ปวช.(สอจ.)' },
+ { dtlcod: 'BDG030', dtlnam: 'โครงการพัฒนาศักยภาพผู้เรียนอาชีวศึกษาในการเป็นผู้ประกอบการ (บ่มเพาะ)' },
+ { dtlcod: 'BDG031', dtlnam: 'โครงการพัฒนาและยกระดับการติดตามผู้สำเร็จการศึกษาอาชีวศึกษา' },
+ { dtlcod: 'BDG032', dtlnam: 'โครงการเสริมสร้างคุณธรรม จริยธรรมและธรรมาภิบาลในสถานศึกษา' },
+ { dtlcod: 'BDG033', dtlnam: 'โครงการจัดการอาชีวศึกษาเพื่อสนองพระราชดำริ' },
+ { dtlcod: 'BDG034', dtlnam: 'เงินรายได้ ป.ตรี' },
+ { dtlcod: 'BDG035', dtlnam: 'งบดำเนินงาน 235200' }
+ ]
+};
+
+ // isModalOpen: boolean = false;
+ // isSubmitting: boolean = false;
+ // arrearsForm!: FormGroup;
+ // saveFrm!: FormGroup;
+ // myActData: IActData[] = [];
+ // // myDropAct: IStateDrop[] = [];
+ // myDropAct: IStateDrop = { income: [], expense: [] };
+ // myActSumData: IActSumData = {
+ // summary: {
+ // totalIncome: '',
+ // totalExpense: '',
+ // netProfit: '',
+ // profitRate: '',
+ // adjustedProfitRate: '',
+ // period: ''
+ // },
+ // pie: {
+ // income: [],
+ // expense: []
+ // }
+ // };
+ // ActSumDataGradient: any
+
+
+ // readonly ownerName = 'Nuttakit';
+
+ constructor(
+ private router: Router
+ ) {}
+
+
+
+
+ ngOnInit(): void {
+ this.setupFormControl();
+ // this.dashboardStateService.getStateResult().subscribe(data => {
+ // if (data) {
+ // this.myDropAct = data;
+ // }
+ // });
+ // // ผลลับท์ ของ รายการ
+ // this.dashboardStateService.getStateAccountResult().subscribe(data => {
+ // if (data) {
+ // this.myActData = data;
+ // }
+ // });
+ // // ผลลัพการ คำนวณ ของ ปัญชี ต่างๆ
+ // this.dashboardStateService.getStateSumResult().subscribe(data => {
+ // if (data) {
+ // this.myActSumData = data;
+ // this.ActSumDataGradient = this.buildExpenseGradient()
+ // }
+ // });
+ }
+ setupFormControl(){
+ // this.arrearsForm = new FormGroup({
+ // // email: new FormControl('',[Validators.required, Validators.email, Validators.maxLength(100)]),
+ // amount: new FormControl('',[Validators.required, Validators.maxLength(20)]),
+ // expdtm: new FormControl('',[Validators.required, Validators.maxLength(12)]),
+ // note: new FormControl('',[Validators.maxLength(200)]),
+ // reason: new FormControl('',[Validators.required, Validators.maxLength(200)])
+ // });
+
+ // this.saveFrm = new FormGroup({
+ // actacpdtm: new FormControl('',[Validators.required, Validators.maxLength(12)]),
+ // actqty: new FormControl('',[Validators.required]),
+ // actcat: new FormControl('',[Validators.required, Validators.maxLength(1)]),
+ // actcmt: new FormControl('',[Validators.maxLength(200)])
+ // });
+ }
+
+ onSaveSubmit(){
+
+ }
+
+ onArrearsSubmit(){
+
+ }
+}
diff --git a/ng-ttc-frontend/src/app/component/sidebar/sidebar.component.html b/ng-ttc-frontend/src/app/component/sidebar/sidebar.component.html
index f920b7a..1ab33a0 100644
--- a/ng-ttc-frontend/src/app/component/sidebar/sidebar.component.html
+++ b/ng-ttc-frontend/src/app/component/sidebar/sidebar.component.html
@@ -10,33 +10,54 @@
- Global Sidebar
+
+
+
+
+ -
+
+ @if(isOpen){
+ หน้าหลัก
+ }
+
- -
- Dashboard
+ @if(isOpen){
+ Dashboard
+ }
-
+ -
+
+ @if(isOpen){
+ Manager
+ }
+
-
- Report
+ @if(isOpen){
+ Report
+ }
@@ -45,7 +66,9 @@
hover:bg-red-700 hover:shadow-lg transition-all duration-300 ease-in-out"
(click)="logout()">
- Logout
+ @if(isOpen){
+ Logout
+ }
diff --git a/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.css b/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.html b/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.html
new file mode 100644
index 0000000..5e40efe
--- /dev/null
+++ b/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.html
@@ -0,0 +1,2 @@
+
+
diff --git a/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.ts b/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.ts
new file mode 100644
index 0000000..8c34ecf
--- /dev/null
+++ b/ng-ttc-frontend/src/app/content/main-manager-content/main-manager-content.component.ts
@@ -0,0 +1,162 @@
+import { DashboardStateService } from '../../services/state/dashboard-state.service';
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { ChartConfiguration, ChartOptions } from 'chart.js';
+import { BaseChartDirective } from 'ng2-charts';
+import { GeneralService } from '../../services/generalservice';
+import { IDropAct, IStateDrop, IActData, IActSumData } from '../../interfaces/dashboard.interface';
+
+
+@Component({
+ selector: 'app-main-manager-content',
+ standalone: false,
+ templateUrl: './main-manager-content.component.html',
+ styleUrls: ['./main-manager-content.component.css']
+})
+export class MainManagerContentComponent implements OnInit {
+ // @ViewChild(BaseChartDirective) chart?: BaseChartDirective;
+ myDropAct!: IStateDrop;
+ myActData: IActData[] = [];
+ myActSumData: IActSumData = {
+ summary: {
+ totalIncome: '',
+ totalExpense: '',
+ netProfit: '',
+ profitRate: '',
+ adjustedProfitRate: '',
+ period: ''
+ },
+ pie: {
+ income: [],
+ expense: []
+ }
+ };
+
+ constructor(
+ private generalService: GeneralService,
+ private dashboardStateService: DashboardStateService
+ ) {}
+
+ ngOnInit(): void {
+ let token = localStorage.getItem('access_token')
+ this.OnSearchAct(token, true);
+ this.OnSetupDashboard(token, true);
+ this.OnSearchSum(token, true);
+ }
+
+ OnSearchAct(value: any, setupFirst: boolean): void {
+ const uri = '/api/web/accountingSearch';
+ let request = {
+ token: value
+ }
+ this.generalService.postRequest(uri, request).subscribe({
+ next: (result: any) => {
+ if (result.code === '200') {
+ this.generalService.trowApi(result);
+ this.myActData = result.data;
+ this.dashboardStateService.setStateAccountResult(this.myActData);
+ }else{
+ this.generalService.trowApi(result);
+ }
+ },
+ error: (error: any) => {
+ this.generalService.trowApi(error);
+ },
+ complete: () => {
+
+ }
+ });
+ }
+
+
+
+ OnSetupDashboard(value: any, setupFirst: boolean): void {
+ const uri = '/api/web/accountingSetup';
+ let request = {
+ token: value
+ }
+ this.generalService.postRequest(uri, request).subscribe({
+ next: (result: any) => {
+ if (result.code === '200') {
+ this.generalService.trowApi(result);
+ this.myDropAct = result.data
+ this.dashboardStateService.setStateResult(this.myDropAct)
+ }else{
+ this.generalService.trowApi(result);
+ }
+ },
+ error: (error: any) => {
+ this.generalService.trowApi(error);
+ },
+ complete: () => {
+
+ }
+ });
+ }
+
+ OnSearchSum(value: any, setupFirst: boolean): void {
+ const uri = '/api/web/accountingSum';
+ let request = {
+ token: value
+ }
+ this.generalService.postRequest(uri, request).subscribe({
+ next: (result: any) => {
+ if (result.code === '200') {
+ this.generalService.trowApi(result);
+ this.myActSumData = result.data
+ this.dashboardStateService.setStateSumResult(this.myActSumData);
+ }else{
+ this.generalService.trowApi(result);
+ }
+ },
+ error: (error: any) => {
+ this.generalService.trowApi(error);
+ },
+ complete: () => {
+
+ }
+ });
+ }
+
+ // fetchChartData(): void {
+ // // NOTE: Using a placeholder endpoint as the actual one was not provided.
+ // const uri = '/api/dashboard/summary-last-6-months';
+
+ // this.generalService.getRequest(uri).subscribe({
+ // next: (result: any) => {
+ // if (result.code === '200' && result.data) {
+ // this.processChartData(result.data);
+ // } else {
+ // console.warn('Could not fetch chart data:', result.message_th);
+ // // Optionally, display placeholder data or an error message
+ // this.setupPlaceholderData();
+ // }
+ // },
+ // error: (error: any) => {
+ // console.error('Error fetching chart data:', error);
+ // // Display placeholder data on error to show the graph structure
+ // this.setupPlaceholderData();
+ // }
+ // });
+ // }
+
+ // processChartData(data: any[]): void {
+ // const labels = data.map(item => item.month);
+ // const revenues = data.map(item => item.revenue);
+
+ // this.lineChartData.labels = labels;
+ // this.lineChartData.datasets[0].data = revenues;
+
+ // this.chart?.update();
+ // }
+
+ // setupPlaceholderData(): void {
+ // // This function is called if the API fails, to show a sample graph.
+ // const labels = ['January', 'February', 'March', 'April', 'May', 'June'];
+ // const revenues = [1200, 1900, 3000, 5000, 2300, 3200]; // Sample data
+
+ // this.lineChartData.labels = labels;
+ // this.lineChartData.datasets[0].data = revenues;
+
+ // this.chart?.update();
+ // }
+}
diff --git a/ng-ttc-frontend/src/app/controls/main-control/main-control-routing.module.ts b/ng-ttc-frontend/src/app/controls/main-control/main-control-routing.module.ts
index 285e146..3b0629d 100644
--- a/ng-ttc-frontend/src/app/controls/main-control/main-control-routing.module.ts
+++ b/ng-ttc-frontend/src/app/controls/main-control/main-control-routing.module.ts
@@ -1,7 +1,10 @@
+import { MainManagerContentComponent } from './../../content/main-manager-content/main-manager-content.component';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MainDashboardContentComponent } from '../../content/main-dashboard-content/main-dashboard-content.component';
import { MainReportComponent } from '../../component/main-report/main-report.component';
+import { BudgetAproval } from '../../component/budget-aproval/budget-aproval';
+import { MainLandingComponent } from '../../component/main-landing/main-landing.component';
// import { MainReportComponent } from '../../component/main-report/main-report.component';
@@ -9,6 +12,15 @@ import { MainReportComponent } from '../../component/main-report/main-report.com
const routes: Routes = [
{ path: 'dashboard', component: MainDashboardContentComponent },
{ path: 'report', component: MainReportComponent },
+ { path: 'landing', component: MainLandingComponent },
+ { path: 'manager', component: MainManagerContentComponent },
+ {
+ path: 'manager',
+ children: [
+ { path: '', component: MainManagerContentComponent }, // รายการโครงการ
+ { path: 'budget/:code', component: BudgetAproval }, // จัดการงบประมาณ
+ ]
+ },
// children: [
// {
// path: 'dashboard',
@@ -18,8 +30,8 @@ const routes: Routes = [
// { path: '', redirectTo: 'profile', pathMatch: 'full' }
// ]
- { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
- { path: '**', redirectTo: 'dashboard' }
+ { path: '', redirectTo: 'landing', pathMatch: 'full' },
+ { path: '**', redirectTo: 'landing' }
];
@NgModule({
diff --git a/ng-ttc-frontend/src/app/controls/main-control/main-control.module.ts b/ng-ttc-frontend/src/app/controls/main-control/main-control.module.ts
index ce71e45..9e53d4a 100644
--- a/ng-ttc-frontend/src/app/controls/main-control/main-control.module.ts
+++ b/ng-ttc-frontend/src/app/controls/main-control/main-control.module.ts
@@ -1,3 +1,4 @@
+import { MainManagerContentComponent } from './../../content/main-manager-content/main-manager-content.component';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
// import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@@ -10,6 +11,9 @@ import { MainDashboardComponent } from '../../component/main-dashboard/main-dash
import { MainDashboardContentComponent } from '../../content/main-dashboard-content/main-dashboard-content.component';
import { AccDateFormatPipe } from '../../pipe/dtmtodatetime.pipe';
import { MainReportComponent } from '../../component/main-report/main-report.component';
+import { MainManagerComponent } from '../../component/main-manager/main-manager.component';
+import { BudgetAproval } from '../../component/budget-aproval/budget-aproval';
+import { MainLandingComponent } from '../../component/main-landing/main-landing.component';
// import { MainReportComponent } from '../../component/main-report/main-report.component';
@@ -20,6 +24,10 @@ import { MainReportComponent } from '../../component/main-report/main-report.com
MainDashboardComponent,
MainDashboardContentComponent,
MainReportComponent,
+ MainManagerContentComponent,
+ MainManagerComponent,
+ BudgetAproval,
+ MainLandingComponent,
AccDateFormatPipe
// MainReportComponent
],
diff --git a/ng-ttc-frontend/src/index.html b/ng-ttc-frontend/src/index.html
index c6f97e2..43c87cd 100644
--- a/ng-ttc-frontend/src/index.html
+++ b/ng-ttc-frontend/src/index.html
@@ -2,7 +2,7 @@
- AccountingNgNuttakit
+ TTC
diff --git a/ng-ttc-frontend/src/styles.css b/ng-ttc-frontend/src/styles.css
index ddfe0d5..165eee0 100644
--- a/ng-ttc-frontend/src/styles.css
+++ b/ng-ttc-frontend/src/styles.css
@@ -72,6 +72,8 @@ html, body, app-root {
}
+
+
/* sensible default box model */
*, *::before, *::after { box-sizing: border-box; }
@@ -219,3 +221,45 @@ body {
font-weight: 900;
font-style: italic;
}
+
+
+/* Custom-Table */
+.ledger-table {
+ display: flex;
+ flex-direction: column;
+ gap: 0.4rem;
+}
+
+.ledger-table.is-scrollable {
+ max-height: 25rem;
+ overflow-y: auto;
+ padding-right: 0.5rem;
+}
+
+
+.ledger-row {
+ display: grid;
+ grid-template-columns: 2fr 1fr 0.8fr 1.2fr;
+ gap: 1rem;
+ align-items: center;
+ padding: 0.75rem 0.4rem;
+ border-bottom: 1px solid #e2e8f0;
+}
+
+
+.ledger-row {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.ledger-row span:nth-child(3),
+.ledger-row span:nth-child(4) {
+ text-align: left;
+}
+
+
+.ledger-head {
+ text-transform: uppercase;
+ font-size: 0.75rem;
+ letter-spacing: 0.08em;
+ color: #94a3b8;
+}
diff --git a/ng-ttc-frontend/tailwind.config.js b/ng-ttc-frontend/tailwind.config.js
new file mode 100644
index 0000000..8974f83
--- /dev/null
+++ b/ng-ttc-frontend/tailwind.config.js
@@ -0,0 +1,10 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ "./src/**/*.{html,ts}",
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}