- ปรับรูปแบบ template html

This commit is contained in:
x2Skyz
2025-11-26 15:16:46 +07:00
parent 9e4af33493
commit 97fef61d8d
11 changed files with 156 additions and 125 deletions

View File

@@ -8,7 +8,7 @@
<!-- <span class="bg-red-100 text-red-800 p-2 rounded-lg text-xl">💸</span> -->
<span>จัดสรรงบประมาณ</span>
</h2>
<p class="text-gray-500 mt-1 ml-1 text-sm">โครงการ: <span class="font-medium text-red-900">{{projectTitle}}</span></p>
<p class="text-gray-500 mt-1 ml-1 text-sm">โครงการ: <span class="font-medium text-red-900">{{projectTitle || prjnam}}</span></p>
</div>
<div class="text-sm text-gray-500 bg-white px-4 py-2 rounded-full shadow-sm border border-gray-100">
รายการทั้งหมด: <span class="font-bold text-red-800">{{ myTrnMst.length }}</span> รายการ
@@ -26,7 +26,7 @@
<!-- <span class="bg-red-600 text-white w-6 h-6 flex items-center justify-center rounded-full text-xs shadow-sm">
{{ isEditMode ? '✎' : '✚' }}
</span> -->
{{ isEditMode ? 'แก้ไขรายการ' : 'เพิ่มรายการงบประมาณ' }}
<span class="w-1 h-6 bg-red-900 rounded-full mr-1"></span>{{ isEditMode ? 'แก้ไขรายการ' : 'เพิ่มรายการงบประมาณ' }}
</div>
<button class="text-gray-400 transition-transform duration-300" [ngClass]="{'rotate-180': isFormExpanded}">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">

View File

@@ -17,6 +17,7 @@ import { ToastrService } from 'ngx-toastr';
})
export class BudgetAproval implements OnInit {
@Output() ExpenseEventSubmit = new EventEmitter<any>();
@Input() prjnam!: string;
budgetForm!: FormGroup;
isFormExpanded = true;

View File

@@ -1,126 +1,124 @@
<div class="w-full p-6">
<div class="w-full p-6">
<!-- Summary Cards -->
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6 mb-8">
<!--
<div class="bg-white border border-gray-200 rounded-2xl p-5 shadow-sm hover:shadow-md transition">
<div class="text-gray-500 text-sm">งบทั้งหมด</div>
<div class="text-3xl font-bold text-gray-800 mt-1">
{{ totalBudget | number:'1.0-2' }} บาท
<div class="flex flex-col md:flex-row justify-between items-end mb-6 gap-4">
<div>
<h1 class="text-2xl font-bold text-gray-800 flex items-center gap-2">
<span class="w-2 h-8 bg-red-900 rounded-full"></span> รายการโครงการทั้งหมด
</h1>
<p class="text-gray-500 mt-1 text-sm pl-4">จัดการงบประมาณและตรวจสอบสถานะโครงการ</p>
</div>
</div>
<div class="bg-white border border-gray-200 rounded-2xl p-5 shadow-sm hover:shadow-md transition">
<div class="text-gray-500 text-sm">งบที่อนุมัติแล้ว</div>
<div class="text-3xl font-bold text-green-600 mt-1">
{{ approvedBudget | number:'1.0-2' }} บาท
</div>
</div>
<div class="bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden">
<div class="bg-white border border-gray-200 rounded-2xl p-5 shadow-sm hover:shadow-md transition">
<div class="text-gray-500 text-sm">งบคงเหลือ</div>
<div
class="text-3xl font-bold mt-1"
[ngClass]="remainingBudget >= 0 ? 'text-blue-600' : 'text-red-600'"
>
{{ remainingBudget | number:'1.0-2' }} บาท
</div>
</div> -->
</div>
<!-- Add Button -->
<!-- <div class="mb-4">
<button
class=" rounded-3xl bg-green-600 hover:bg-green-700 text-white px-5 py-2.5 text-sm font-medium shadow-sm flex items-center gap-2 transition"
>
เพิ่มโครงการใหม่
</button>
</div>
-->
<!-- Table -->
<div class="overflow-x-auto bg-white border border-gray-200 rounded-2xl shadow-sm">
<table class="min-w-full text-left border-collapse">
<thead class="bg-red-900 border-b border-gray-200 text-white text-sm">
<tr>
<th class="py-3 px-4 font-semibold">ลำดับ</th>
<th class="py-3 px-4 font-semibold">รหัสโครงการ</th>
<th class="py-3 px-4 font-semibold">ชื่อโครงการ</th>
<th class="py-3 px-4 font-semibold">ผู้รับผิดชอบ</th>
<th class="py-3 px-4 font-semibold">งบที่ขออนุมัติ</th>
<th class="py-3 px-4 font-semibold">หมวดงบ</th>
<th class="py-3 px-4 font-semibold">จำนวนที่อนุมัติ</th>
<th class="py-3 px-4 font-semibold text-center">สถานะ</th>
<th class="py-3 px-4 font-semibold text-center">ดำเนินการ</th>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-red-900 text-white text-sm uppercase tracking-wider leading-normal">
<th class="py-4 px-6 font-medium w-16 text-center">ลำดับ</th>
<th class="py-4 px-6 font-medium min-w-[200px]">ชื่อโครงการ / รหัส</th>
<th class="py-4 px-6 font-medium">ผู้รับผิดชอบ</th>
<th class="py-4 px-6 font-medium text-right">งบที่ขอ (บาท)</th>
<th class="py-4 px-6 font-medium text-right">อนุมัติ (บาท)</th>
<th class="py-4 px-6 font-medium text-center">สถานะ</th>
<th class="py-4 px-6 font-medium text-center">จัดการ</th>
</tr>
</thead>
<tbody>
@for(idx of myPrjMst; track idx.prjseq; let i = $index){
<tr class="border-b border-gray-100 hover:bg-blue-50/20 transition">
<td class="py-4 px-4 text-gray-700">{{ i + 1 }}</td>
<td class="py-4 px-4 font-medium text-gray-700"> {{ idx.prjseq }}</td>
<td class="py-4 px-4 text-gray-800 font-semibold leading-tight">{{ idx.prjnam }}</td>
<td class="py-4 px-4 text-gray-700">{{ idx.prjusrnam }}</td>
<td class="py-4 px-4 text-blue-700 font-bold whitespace-nowrap"> {{ idx.prjwntbdg | number:'1.0-0' }} บาท</td>
<tbody class="text-gray-600 text-sm">
@for(idx of myPrjMst; track idx.prjseq; let i = $index) {
<tr class="border-b border-gray-100 hover:bg-red-50/40 transition duration-200 group">
@if(idx.prjbdgnam){
<td class="py-4 px-4 text-gray-800 font-semibold leading-tight">{{ idx.prjbdgnam }}</td>
}@else {
<td class="py-4 px-4 text-gray-400 font-semibold leading-tight italic">ไม่จัดสรร</td>
}
<td class="py-4 px-4 w-40">
<!-- <input type="number" class="w-full px-4 py-2.5 border border-gray-300 rounded-xl bg-white focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-300 text-sm transition"/> -->
{{ idx.prjacpbdg }} บาท
<td class="py-4 px-6 text-center text-gray-400 font-mono">
{{ i + 1 }}
</td>
<td class="py-4 px-4 text-center">
<span
class="px-3 py-1.5 rounded-full text-xs font-semibold inline-flex items-center gap-1
shadow-sm border"
<td class="py-4 px-6">
<div class="flex flex-col">
<span class="font-bold text-gray-800 text-base group-hover:text-red-900 transition-colors">
{{ idx.prjnam }}
</span>
<span class="text-xs text-gray-400 mt-1 font-mono bg-gray-100 inline-block px-1.5 py-0.5 rounded w-fit">
#{{ idx.prjseq }}
</span>
</div>
</td>
<td class="py-4 px-6">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center text-gray-500 text-xs font-bold">
{{ idx.prjusrnam?.charAt(0) }}
</div>
<span class="font-medium">{{ idx.prjusrnam }}</span>
</div>
</td>
<td class="py-4 px-6 text-right">
<span class="font-mono text-gray-600">
{{ idx.prjwntbdg | number:'1.0-0' }}
</span>
</td>
<td class="py-4 px-6 text-right">
<span class="font-mono font-bold text-lg"
[ngClass]="{
'text-green-600': (idx.prjacpbdg ?? 0) > 0,
'text-gray-300': !idx.prjacpbdg || idx.prjacpbdg === 0
}">
{{ (idx.prjacpbdg ?? 0) | number:'1.0-0' }}
</span>
</td>
<td class="py-4 px-6 text-center">
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-semibold border"
[ngClass]="{
'bg-yellow-50 text-yellow-700 border-yellow-200': idx.prjcomstt === 'UAC',
'bg-green-50 text-green-700 border-green-200': idx.prjcomstt === 'BAP',
'bg-red-50 text-red-700 border-red-200': idx.prjcomstt === 'CN'
}"
>
<ng-container *ngIf="idx.prjcomstt === 'BAP'">อนุมัติแล้ว</ng-container>
<ng-container *ngIf="idx.prjcomstt === 'UAC'">รออนุมัติ</ng-container>
<ng-container *ngIf="idx.prjcomstt === 'CN'">ไม่อนุมัติ</ng-container>
}">
<span class="w-1.5 h-1.5 rounded-full"
[ngClass]="{
'bg-yellow-500': idx.prjcomstt === 'UAC',
'bg-green-500': idx.prjcomstt === 'BAP',
'bg-red-500': idx.prjcomstt === 'CN'
}"></span>
@if(idx.prjcomstt === 'UAC'){ รออนุมัติ }
@else if(idx.prjcomstt === 'BAP'){ อนุมัติแล้ว }
@else if(idx.prjcomstt === 'CN'){ ไม่อนุมัติ }
</span>
</td>
<td class="py-4 px-4 text-center space-x-2 whitespace-nowrap">
<button
class="bg-red-900 hover:bg-red-950 text-white px-4 py-2 rounded-xl text-sm
shadow-sm font-medium transition"
(click)="openBudgetDetail(idx)">
จัดสรรงบประมาณ
<td class="py-4 px-6 text-center">
<button (click)="openBudgetDetail(idx)"
class="text-red-900 hover:text-white border border-red-900 hover:bg-red-900 focus:ring-4 focus:outline-none focus:ring-red-300 font-medium rounded-lg text-xs px-4 py-2 text-center transition-all duration-200 shadow-sm flex items-center justify-center gap-1 mx-auto whitespace-nowrap">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
จัดสรรงบ
</button>
</td>
</tr>
} @empty {
<tr>
<td colspan="7" class="py-12 text-center text-gray-400">
<div class="flex flex-col items-center justify-center">
<svg class="w-12 h-12 text-gray-300 mb-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<span>ไม่พบข้อมูลโครงการในระบบ</span>
</div>
</td>
</tr>
}
</tbody>
</table>
<!-- endtable -->
</div>
<!-- Pagination
<div class="flex justify-end items-center gap-3 mt-5">
<button class="px-4 py-2 border border-gray-300 rounded-xl bg-white hover:bg-gray-100">
1
</button>
<button class="px-4 py-2 border border-gray-300 rounded-xl bg-white hover:bg-gray-100">
2
</button>
</div> -->
<div class="bg-gray-50 px-6 py-4 border-t border-gray-200 flex justify-between items-center text-xs text-gray-500">
<div>แสดง {{ myPrjMst.length }} รายการ</div>
</div>
</div>
</div>

View File

@@ -36,7 +36,12 @@ export class MainManagerComponent implements OnInit {
}
openBudgetDetail(idx: IPrjMst) {
this.router.navigate(['/main/budget/approve', idx.prjseq]);
this.router.navigate(['/main/manager/aproval'], {
state: {
prjseq: idx.prjseq,
prjnam: idx.prjnam
}
});
}
constructor(

View File

@@ -15,6 +15,7 @@
<span>เพิ่มโครงการ</span>
</button>
<!-- โครงการ -->
<div class="overflow-x-auto">
<table class="min-w-full text-sm border-collapse">
<thead class="bg-red-900 text-white">
@@ -25,6 +26,8 @@
<th class="py-3 px-4 text-center rounded-tr-lg w-20">ดำเนินการ</th>
</tr>
</thead>
<!-- เนื้อหา -->
<tbody>
<tr class="border-b hover:bg-gray-50 transition duration-100">
<td class="py-3 px-4 text-gray-700">1</td>

View File

@@ -1 +1 @@
<app-budget-aproval (ExpenseEventSubmit)="OnBudgetExp($event)"></app-budget-aproval>
<app-budget-aproval (ExpenseEventSubmit)="OnBudgetExp($event)" [prjnam]="prjNam"></app-budget-aproval>

View File

@@ -14,16 +14,24 @@ export class BudgetAprovalContent implements OnInit {
myTrnmst: ITrnmst[]=[];
myDropBdg: IDropBdg[]=[];
constructor(
prjSeq:string = '';
prjNam:string = '';
; constructor(
private router: Router,
private route: ActivatedRoute,
private generalService: GeneralService,
private transactionStateService: TransactionStateService
){}
){
const nav = this.router.getCurrentNavigation();
if (nav?.extras.state) {
this.prjSeq = nav.extras.state['prjseq'];
this.prjNam = nav.extras.state['prjnam'];
}
}
ngOnInit(): void {
let param = this.route.snapshot.paramMap.get('seq');
this.OnSearchTrn(param);
// this.prjSeq = this.route.snapshot.param.get('seq');
this.OnSearchTrn(this.prjSeq);
this.OnBudgetSearch();
}

View File

@@ -36,7 +36,6 @@ export class MainManagerContentComponent implements OnInit {
private generalService: GeneralService,
private projectStateService: ProjectStateService
) {}
ngOnInit(): void {
this.OnSearchPrj({}, true);
}

View File

@@ -18,14 +18,14 @@ const routes: Routes = [
{ path: 'manager', component: MainManagerContentComponent },
{ path: 'project', component: MainProjectContent },
{ path: 'project/:mode', component: MainProjectContent },
{ path: 'budget/approve/:seq', component: BudgetAprovalContent},
// {
// path: 'manager',
// children: [
// { path: '', component: MainManagerContentComponent }, // รายการโครงการ
// { path: 'budget/:code', component: BudgetAproval }, // จัดการงบประมาณ
// ]
// },
// { path: 'budget/approve/:seq', component: BudgetAprovalContent},
{
path: 'manager',
children: [
{ path: '', component: MainManagerContentComponent }, // รายการโครงการ
{ path: 'aproval', component: BudgetAprovalContent }, // จัดการงบประมาณ
]
},
// children: [
// {
// path: 'dashboard',

View File

@@ -5,7 +5,7 @@ export interface IPrjMst {
prjwntbdg?: string;
prjbdgnam?: string;
prjbdgcod?: string;
prjacpbdg?: string;
prjacpbdg?: number;
prjcomstt?: string;
prjacpdtm?: string;
}

View File

@@ -20,6 +20,23 @@ export class TransactionStateService {
this.transactionState.next(transactions);
}
// 🟢 [NEW] อัปเดตหรือเพิ่มรายการเดียว
setStateEditOne(item: ITrnmst): void {
const current = this.transactionState.getValue() || [];
// หา index จาก trnseq (หรือ key อื่นที่ unique)
const index = current.findIndex(x => x.trnseq === item.trnseq);
if (index !== -1) {
// กรณีมีอยู่แล้ว -> อัปเดตข้อมูลทับ
current[index] = { ...current[index], ...item };
this.transactionState.next([...current]); // spread เพื่อ trigger change detection
} else {
// กรณีไม่มี (รายการใหม่) -> เพิ่มต่อท้าย
this.transactionState.next([...current, item]);
}
}
// เคลียร์ state
clearState(): void {
this.transactionState.next(null);