-imporve system
+chatwidget
This commit is contained in:
@@ -30,6 +30,7 @@ import { MainProjectContent } from './content/main-project-content/main-project-
|
||||
import { MainProjectAdd } from './component/main-project-add/main-project-add';
|
||||
import { BudgetAprovalContent } from './content/budget-aproval-content/budget-aproval-content';
|
||||
import { ThemeSwitcherComponent } from './component/theme-switcher/theme-switcher';
|
||||
import { ChatWidgetComponent } from './component/chat-widget-component/chat-widget-component';
|
||||
// import { BudgetAproval } from './component/budget-aproval/budget-aproval';
|
||||
// import { AccDateFormatPipe } from './pipe/dtmtodatetime.pipe';
|
||||
// import { DtmtodatetimePipe } from './dtmtodatetime.pipe';
|
||||
@@ -42,6 +43,7 @@ import { ThemeSwitcherComponent } from './component/theme-switcher/theme-switche
|
||||
SidebarComponent,
|
||||
LicensePrivacyTermsComponent,
|
||||
TokenTimerComponent,
|
||||
// ChatWidgetComponent,
|
||||
// ThemeSwitcherComponent,
|
||||
// BudgetAprovalContent
|
||||
// MainProjectAdd,
|
||||
|
||||
@@ -184,7 +184,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 🟢 Modal Confirmation (Save / Cancel) -->
|
||||
@if(showConfirmModal) {
|
||||
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in">
|
||||
<div class="bg-white rounded-2xl shadow-2xl w-96 overflow-hidden transform transition-all scale-100">
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
/* Custom Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #94a3b8;
|
||||
}
|
||||
|
||||
.animate-fade-in-up {
|
||||
animation: fadeInUp 0.3s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<div class="fixed bottom-5 right-5 z-50 flex flex-col items-end space-y-4 font-sans">
|
||||
|
||||
<!-- หน้าต่างแชท -->
|
||||
<div *ngIf="isOpen"
|
||||
class="w-80 h-96 bg-white rounded-xl shadow-2xl flex flex-col overflow-hidden border border-gray-200 animate-fade-in-up">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="bg-red-800 p-3 flex justify-between items-center text-white shadow-md">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="relative">
|
||||
<div class="w-8 h-8 bg-red-700 rounded-full flex items-center justify-center text-xs font-bold border border-red-600">
|
||||
AI
|
||||
</div>
|
||||
<div class="absolute bottom-0 right-0 w-2.5 h-2.5 bg-green-400 border-2 border-red-800 rounded-full"></div>
|
||||
</div>
|
||||
<div class="flex flex-col leading-tight">
|
||||
<span class="font-bold text-sm">ผู้ช่วยวิเคราะห์ข้อมูล</span>
|
||||
<span class="text-xs text-red-100">ตอบกลับภายใน 1 นาที</span>
|
||||
</div>
|
||||
</div>
|
||||
<button (click)="toggleChat()" class="hover:bg-red-700 p-1 rounded transition text-red-100 hover:text-white">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Chat Body -->
|
||||
<div class="flex-1 p-4 overflow-y-auto bg-slate-50 space-y-3" #scrollContainer>
|
||||
<div *ngFor="let msg of messages"
|
||||
class="flex w-full"
|
||||
[ngClass]="{'justify-end': msg.isUser, 'justify-start': !msg.isUser}">
|
||||
|
||||
<!-- Avatar ฝั่งซ้าย (Support) -->
|
||||
<div *ngIf="!msg.isUser" class="w-6 h-6 bg-red-100 rounded-full shrink-0 mr-2 flex items-center justify-center text-xs text-red-800 font-bold self-end mb-1">
|
||||
AI
|
||||
</div>
|
||||
|
||||
<div [ngClass]="{
|
||||
'bg-red-800 text-white rounded-tl-2xl rounded-tr-2xl rounded-bl-2xl': msg.isUser,
|
||||
'bg-white text-gray-800 border border-gray-200 rounded-tl-2xl rounded-tr-2xl rounded-br-2xl': !msg.isUser
|
||||
}"
|
||||
class="max-w-[75%] px-4 py-2 text-sm shadow-sm wrap-break-words relative group">
|
||||
{{ msg.text }}
|
||||
<span class="text-[10px] absolute bottom-0 -mb-5 opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 whitespace-nowrap"
|
||||
[ngClass]="{'right-0': msg.isUser, 'left-0': !msg.isUser}">
|
||||
<!-- 10:42 AM -->
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer / Input -->
|
||||
<div class="p-3 bg-white border-t border-gray-200 flex items-center space-x-2">
|
||||
<button class="text-gray-400 hover:text-red-800 transition">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13" />
|
||||
</svg>
|
||||
</button>
|
||||
<input type="text"
|
||||
[(ngModel)]="newMessage"
|
||||
(keyup.enter)="sendMessage()"
|
||||
placeholder="พิมพ์ข้อความ..."
|
||||
class="flex-1 bg-gray-100 rounded-full px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-red-500 focus:bg-white transition text-gray-700 placeholder-gray-400">
|
||||
<button (click)="sendMessage()"
|
||||
[disabled]="!newMessage.trim()"
|
||||
class="text-red-950 hover:text-red-800 p-2 transition disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Launcher Button -->
|
||||
<button (click)="toggleChat()"
|
||||
class="group w-14 h-14 bg-red-800 hover:bg-red-700 text-white rounded-full shadow-lg shadow-red-800/30 flex items-center justify-center transition-all transform hover:scale-110 focus:outline-none ring-4 ring-red-50 hover:ring-red-100 active:scale-95">
|
||||
|
||||
<!-- Notification Badge -->
|
||||
<!-- <span *ngIf="!isOpen" class="absolute top-0 right-0 -mt-1 -mr-1 flex h-4 w-4">
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
|
||||
<span class="relative inline-flex rounded-full h-4 w-4 bg-red-500 text-[10px] items-center justify-center text-white font-bold">1</span>
|
||||
</span> -->
|
||||
|
||||
<!-- Icon X -->
|
||||
<svg *ngIf="isOpen" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transition-transform rotate-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
|
||||
<!-- Icon Chat -->
|
||||
<svg *ngIf="!isOpen" xmlns="http://www.w3.org/2000/svg" class="h-7 w-7 transition-transform group-hover:-rotate-12" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-chat-widget-component',
|
||||
standalone: false,
|
||||
templateUrl: './chat-widget-component.html',
|
||||
styleUrl: './chat-widget-component.css',
|
||||
})
|
||||
export class ChatWidgetComponent {
|
||||
isOpen = false;
|
||||
newMessage = '';
|
||||
|
||||
messages = [
|
||||
{ text: 'สวัสดีครับ มีอะไรให้ทีมงานช่วยเหลือไหมครับ? 👋', isUser: false },
|
||||
];
|
||||
|
||||
toggleChat() {
|
||||
this.isOpen = !this.isOpen;
|
||||
}
|
||||
|
||||
sendMessage() {
|
||||
if (this.newMessage.trim()) {
|
||||
// 1. ใส่ข้อความเราลงไป
|
||||
this.messages.push({ text: this.newMessage, isUser: true });
|
||||
this.newMessage = '';
|
||||
|
||||
// 2. จำลองบอทตอบกลับ (Auto Reply Simulation)
|
||||
setTimeout(() => {
|
||||
this.messages.push({
|
||||
text: 'ขอบคุณที่ติดต่อมาครับ ขณะนี้เจ้าหน้าที่กำลังติดลูกค้าท่านอื่น จะรีบตอบกลับให้เร็วที่สุดครับ',
|
||||
isUser: false
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,9 @@ export class MainManagerComponent implements OnInit {
|
||||
p.status = 'CN';
|
||||
}
|
||||
|
||||
download(){
|
||||
|
||||
}
|
||||
openBudgetDetail(idx: IPrjMst) {
|
||||
this.router.navigate(['/main/manager/aproval'], {
|
||||
state: {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
<!-- <app-main-dashboard></app-main-dashboard> -->
|
||||
<app-main-manager (documentDownload)="OnDownloadPrjDoc($event)"></app-main-manager>
|
||||
<app-chat-widget-component></app-chat-widget-component>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ChatWidgetComponent } from './../../component/chat-widget-component/chat-widget-component';
|
||||
import { MainManagerContentComponent } from './../../content/main-manager-content/main-manager-content.component';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@@ -36,7 +37,8 @@ import { BudgetAprovalContent } from '../../content/budget-aproval-content/budge
|
||||
MainProject,
|
||||
MainProjectAdd,
|
||||
BudgetAprovalContent,
|
||||
AccDateFormatPipe
|
||||
AccDateFormatPipe,
|
||||
ChatWidgetComponent
|
||||
// MainReportComponent
|
||||
],
|
||||
imports: [
|
||||
|
||||
@@ -62,7 +62,7 @@ export class GeneralService {
|
||||
map((res: any) => res),
|
||||
catchError((error: any) => {
|
||||
const response = error?.error;
|
||||
console.error('❌ [POST Request Error]:', error);
|
||||
// console.error('❌ [POST Request Error]:', error);
|
||||
return throwError(() => ({
|
||||
status: error.status,
|
||||
code: response?.code ?? '500',
|
||||
@@ -117,7 +117,7 @@ export class GeneralService {
|
||||
const options: any = {
|
||||
...this.getHttpOptions(true),
|
||||
params: httpParams,
|
||||
responseType: isBlob ? 'blob' : 'json' // ✅ สลับ Type ตามค่า isBlob
|
||||
responseType: isBlob ? 'blob' : 'json'
|
||||
};
|
||||
|
||||
return this.http.get(fullUrl, options).pipe(
|
||||
|
||||
Reference in New Issue
Block a user