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
66b5f4ce
Commit
66b5f4ce
authored
Oct 06, 2025
by
sawit
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
modal จองห้องประชุม
parent
c8dc0a75
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
71 additions
and
12 deletions
+71
-12
meeting-booking.component.html
...tal-manage/meeting-booking/meeting-booking.component.html
+43
-5
meeting-booking.component.ts
...ortal-manage/meeting-booking/meeting-booking.component.ts
+28
-7
No files found.
src/app/portal-manage/meeting-booking/meeting-booking.component.html
View file @
66b5f4ce
...
@@ -49,6 +49,11 @@
...
@@ -49,6 +49,11 @@
</mat-form-field>
</mat-form-field>
</div>
</div>
<!-- Room Preview -->
<div
class=
"form-row"
*
ngIf=
"getSelectedRoomImage() as img"
>
<img
[
src
]="
img
"
alt=
"room"
style=
"width:100%;max-height:180px;object-fit:cover;border-radius:8px;border:1px solid #e9ecef;"
/>
</div>
<div
class=
"form-row"
>
<div
class=
"form-row"
>
<mat-form-field
appearance=
"outline"
class=
"form-field"
>
<mat-form-field
appearance=
"outline"
class=
"form-field"
>
<mat-label>
วันที่เริ่มต้น
</mat-label>
<mat-label>
วันที่เริ่มต้น
</mat-label>
...
@@ -77,16 +82,37 @@
...
@@ -77,16 +82,37 @@
</mat-form-field>
</mat-form-field>
</div>
</div>
<!-- Attendees section -->
<div
class=
"form-row"
>
<mat-form-field
appearance=
"outline"
class=
"form-field"
>
<mat-label>
จำนวนผู้เข้าร่วม
</mat-label>
<input
matInput
type=
"number"
min=
"0"
formControlName=
"attendeeCount"
[
value
]="
attendees
.
length
"
readonly
>
</mat-form-field>
<mat-form-field
appearance=
"outline"
class=
"form-field"
>
<mat-label>
เพิ่มผู้เข้าร่วม (พิมพ์อีเมลแล้วกด Enter)
</mat-label>
<mat-chip-grid
#
chipList
aria-label=
"Attendees"
>
<mat-chip-row
*
ngFor=
"let a of attendees"
[
removable
]="
true
"
(
removed
)="
removeAttendee
(
a
)"
>
{{ a }}
<button
matChipRemove
aria-label=
"remove"
>
<mat-icon>
cancel
</mat-icon>
</button>
</mat-chip-row>
<input
placeholder=
"เพิ่มอีเมลผู้เข้าร่วม"
[
matChipInputFor
]="
chipList
"
[
matChipInputSeparatorKeyCodes
]="
separatorKeysCodes
"
(
matChipInputTokenEnd
)="
addAttendee
($
event
)"
/>
</mat-chip-grid>
</mat-form-field>
</div>
<mat-form-field
appearance=
"outline"
class=
"form-field-full"
>
<mat-form-field
appearance=
"outline"
class=
"form-field-full"
>
<mat-label>
รายละเอียด
</mat-label>
<mat-label>
รายละเอียด
</mat-label>
<textarea
matInput
formControlName=
"description"
rows=
"3"
placeholder=
"รายละเอียดเพิ่มเติม (ไม่บังคับ)"
></textarea>
<textarea
matInput
formControlName=
"description"
rows=
"3"
placeholder=
"รายละเอียดเพิ่มเติม (ไม่บังคับ)"
></textarea>
</mat-form-field>
</mat-form-field>
<div
class=
"form-actions"
>
<div
class=
"form-actions"
>
<button
mat-raised-button
color=
"primary"
type=
"submit"
[
disabled
]="!
bookingForm
.
valid
"
>
<mat-icon>
event
</mat-icon>
จองห้องประชุม
</button>
<button
mat-button
type=
"button"
(
click
)="
bookingForm
.
reset
()"
>
<button
mat-button
type=
"button"
(
click
)="
bookingForm
.
reset
()"
>
<mat-icon>
refresh
</mat-icon>
<mat-icon>
refresh
</mat-icon>
รีเซ็ต
รีเซ็ต
...
@@ -95,6 +121,10 @@
...
@@ -95,6 +121,10 @@
<mat-icon>
close
</mat-icon>
<mat-icon>
close
</mat-icon>
ยกเลิก
ยกเลิก
</button>
</button>
<button
mat-raised-button
color=
"primary"
type=
"submit"
[
disabled
]="!
bookingForm
.
valid
"
>
<mat-icon>
event
</mat-icon>
จองห้องประชุม
</button>
</div>
</div>
</form>
</form>
</div>
</div>
...
@@ -210,6 +240,7 @@
...
@@ -210,6 +240,7 @@
(
click
)="
onEventClick
({
event:
e
})"
>
(
click
)="
onEventClick
({
event:
e
})"
>
<span
class=
"time"
*
ngIf=
"e.StartTime && e.EndTime"
>
{{ e.StartTime | date:'HH:mm' }}-{{ e.EndTime | date:'HH:mm' }}
</span>
<span
class=
"time"
*
ngIf=
"e.StartTime && e.EndTime"
>
{{ e.StartTime | date:'HH:mm' }}-{{ e.EndTime | date:'HH:mm' }}
</span>
<span
class=
"title"
>
{{ e.Subject }}
</span>
<span
class=
"title"
>
{{ e.Subject }}
</span>
<span
class=
"count"
*
ngIf=
"e.AttendeesCount"
>
({{ e.AttendeesCount }})
</span>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -258,6 +289,9 @@
...
@@ -258,6 +289,9 @@
</span>
</span>
</div>
</div>
<div
class=
"quick-info-content"
>
<div
class=
"quick-info-content"
>
<div
class=
"info-item"
*
ngIf=
"getRoomImageByName(data.Location)"
>
<img
[
src
]="
getRoomImageByName
(
data
.
Location
)"
alt=
"room"
style=
"width:100%;max-height:140px;object-fit:cover;border-radius:8px;border:1px solid #e9ecef;"
/>
</div>
<div
class=
"info-item"
>
<div
class=
"info-item"
>
<mat-icon>
location_on
</mat-icon>
<mat-icon>
location_on
</mat-icon>
<span>
{{ data.Location }}
</span>
<span>
{{ data.Location }}
</span>
...
@@ -276,7 +310,11 @@
...
@@ -276,7 +310,11 @@
</div>
</div>
<div
class=
"info-item"
*
ngIf=
"data.Attendees"
>
<div
class=
"info-item"
*
ngIf=
"data.Attendees"
>
<mat-icon>
group
</mat-icon>
<mat-icon>
group
</mat-icon>
<span>
{{ data.Attendees }}
</span>
<span>
{{ data.Attendees }} ({{ data.AttendeesCount || (data.AttendeesList?.length || 0) }} คน)
</span>
</div>
<div
class=
"info-item"
*
ngIf=
"data.AttendeesList?.length"
>
<mat-icon>
badge
</mat-icon>
<span>
{{ data.AttendeesList.join(', ') }}
</span>
</div>
</div>
</div>
</div>
<div
class=
"quick-info-actions"
>
<div
class=
"quick-info-actions"
>
...
...
src/app/portal-manage/meeting-booking/meeting-booking.component.ts
View file @
66b5f4ce
...
@@ -72,6 +72,7 @@ import { MeetingRoom, MeetingBooking, BookingTimeSlot, BookingStatistics } from
...
@@ -72,6 +72,7 @@ import { MeetingRoom, MeetingBooking, BookingTimeSlot, BookingStatistics } from
})
})
export
class
MeetingBookingComponent
implements
OnInit
{
export
class
MeetingBookingComponent
implements
OnInit
{
rooms$
:
Observable
<
MeetingRoom
[]
>
;
rooms$
:
Observable
<
MeetingRoom
[]
>
;
private
roomsSnapshot
:
MeetingRoom
[]
=
[];
bookings$
:
Observable
<
MeetingBooking
[]
>
;
bookings$
:
Observable
<
MeetingBooking
[]
>
;
statistics$
:
Observable
<
BookingStatistics
>
;
statistics$
:
Observable
<
BookingStatistics
>
;
...
@@ -110,6 +111,7 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -110,6 +111,7 @@ export class MeetingBookingComponent implements OnInit {
private
snackBar
:
MatSnackBar
private
snackBar
:
MatSnackBar
)
{
)
{
this
.
rooms$
=
this
.
meetingBookingService
.
rooms$
;
this
.
rooms$
=
this
.
meetingBookingService
.
rooms$
;
this
.
rooms$
.
subscribe
(
r
=>
this
.
roomsSnapshot
=
r
||
[]);
this
.
bookings$
=
this
.
meetingBookingService
.
bookings$
;
this
.
bookings$
=
this
.
meetingBookingService
.
bookings$
;
this
.
bookingForm
=
this
.
fb
.
group
({
this
.
bookingForm
=
this
.
fb
.
group
({
...
@@ -118,7 +120,8 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -118,7 +120,8 @@ export class MeetingBookingComponent implements OnInit {
description
:
[
''
],
description
:
[
''
],
startDateTime
:
[
''
,
Validators
.
required
],
startDateTime
:
[
''
,
Validators
.
required
],
endDateTime
:
[
''
,
Validators
.
required
],
endDateTime
:
[
''
,
Validators
.
required
],
attendees
:
[[]]
attendees
:
[[]],
attendeeCount
:
[
0
,
[
Validators
.
min
(
0
)]]
});
});
this
.
statistics$
=
this
.
meetingBookingService
.
getBookingStatistics
(
this
.
statistics$
=
this
.
meetingBookingService
.
getBookingStatistics
(
...
@@ -180,7 +183,7 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -180,7 +183,7 @@ export class MeetingBookingComponent implements OnInit {
const
value
=
(
event
.
value
||
''
).
trim
();
const
value
=
(
event
.
value
||
''
).
trim
();
if
(
value
)
{
if
(
value
)
{
this
.
attendees
.
push
(
value
);
this
.
attendees
.
push
(
value
);
this
.
bookingForm
.
patchValue
({
attendees
:
this
.
attendees
});
this
.
bookingForm
.
patchValue
({
attendees
:
this
.
attendees
,
attendeeCount
:
this
.
attendees
.
length
});
}
}
event
.
chipInput
!
.
clear
();
event
.
chipInput
!
.
clear
();
}
}
...
@@ -189,7 +192,7 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -189,7 +192,7 @@ export class MeetingBookingComponent implements OnInit {
const
index
=
this
.
attendees
.
indexOf
(
attendee
);
const
index
=
this
.
attendees
.
indexOf
(
attendee
);
if
(
index
>=
0
)
{
if
(
index
>=
0
)
{
this
.
attendees
.
splice
(
index
,
1
);
this
.
attendees
.
splice
(
index
,
1
);
this
.
bookingForm
.
patchValue
({
attendees
:
this
.
attendees
});
this
.
bookingForm
.
patchValue
({
attendees
:
this
.
attendees
,
attendeeCount
:
this
.
attendees
.
length
});
}
}
}
}
...
@@ -287,7 +290,9 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -287,7 +290,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor
:
this
.
getStatusColor
(
booking
.
status
),
CategoryColor
:
this
.
getStatusColor
(
booking
.
status
),
Status
:
booking
.
status
,
Status
:
booking
.
status
,
Organizer
:
booking
.
organizerName
,
Organizer
:
booking
.
organizerName
,
Attendees
:
booking
.
attendees
.
map
(
a
=>
a
.
userName
).
join
(
', '
)
Attendees
:
booking
.
attendees
.
map
(
a
=>
a
.
userName
).
join
(
', '
),
AttendeesList
:
booking
.
attendees
.
map
(
a
=>
a
.
userName
),
AttendeesCount
:
booking
.
attendees
.
length
}));
}));
}
else
{
}
else
{
// ถ้าไม่มีข้อมูลจาก service ให้ใช้ข้อมูลตัวอย่าง
// ถ้าไม่มีข้อมูลจาก service ให้ใช้ข้อมูลตัวอย่าง
...
@@ -384,7 +389,9 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -384,7 +389,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor
:
'success'
,
CategoryColor
:
'success'
,
Status
:
'confirmed'
,
Status
:
'confirmed'
,
Organizer
:
'John Doe'
,
Organizer
:
'John Doe'
,
Attendees
:
'Jane Smith, Bob Johnson'
Attendees
:
'Jane Smith, Bob Johnson'
,
AttendeesList
:
[
'Jane Smith'
,
'Bob Johnson'
],
AttendeesCount
:
2
},
},
{
{
Id
:
2
,
Id
:
2
,
...
@@ -397,7 +404,9 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -397,7 +404,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor
:
'info'
,
CategoryColor
:
'info'
,
Status
:
'pending'
,
Status
:
'pending'
,
Organizer
:
'Alice Brown'
,
Organizer
:
'Alice Brown'
,
Attendees
:
'Charlie Wilson, Diana Lee'
Attendees
:
'Charlie Wilson, Diana Lee'
,
AttendeesList
:
[
'Charlie Wilson'
,
'Diana Lee'
],
AttendeesCount
:
2
},
},
{
{
Id
:
3
,
Id
:
3
,
...
@@ -410,7 +419,9 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -410,7 +419,9 @@ export class MeetingBookingComponent implements OnInit {
CategoryColor
:
'warning'
,
CategoryColor
:
'warning'
,
Status
:
'confirmed'
,
Status
:
'confirmed'
,
Organizer
:
'Tech Lead'
,
Organizer
:
'Tech Lead'
,
Attendees
:
'ทีมพัฒนา'
Attendees
:
'ทีมพัฒนา'
,
AttendeesList
:
[
'ทีมพัฒนา'
],
AttendeesCount
:
1
}
}
];
];
...
@@ -512,6 +523,16 @@ export class MeetingBookingComponent implements OnInit {
...
@@ -512,6 +523,16 @@ export class MeetingBookingComponent implements OnInit {
return
items
;
return
items
;
}
}
public
getRoomImageByName
(
roomName
:
string
):
string
|
undefined
{
const
room
=
this
.
roomsSnapshot
.
find
(
r
=>
r
.
name
===
roomName
);
return
room
?.
imageUrl
;
}
public
getSelectedRoomImage
():
string
|
undefined
{
const
room
=
this
.
roomsSnapshot
.
find
(
r
=>
r
.
id
===
this
.
bookingForm
?.
value
?.
roomId
);
return
room
?.
imageUrl
;
}
public
monthLabel
():
string
{
public
monthLabel
():
string
{
const
d
=
this
.
selectedDate_schedule
;
const
d
=
this
.
selectedDate_schedule
;
return
`
${
d
.
toLocaleString
(
'th-TH'
,
{
month
:
'long'
})}
${
d
.
getFullYear
()}
`
;
return
`
${
d
.
toLocaleString
(
'th-TH'
,
{
month
:
'long'
})}
${
d
.
getFullYear
()}
`
;
...
...
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