Commit 0987f285 by Ooh-Ao

จัดการสมาชิก

parent d2625cfd
......@@ -24,15 +24,21 @@ async def create_project_member(db: AsyncSession, pm_in: ProjectMemberCreate):
raise HTTPException(status_code=400, detail=str(e.orig))
return new_pm
# READ ALL (โหลดข้อมูลของ Project ด้วย)
# READ ALL (โหลดข้อมูล Project และ Member ด้วย)
async def get_all_project_members(db: AsyncSession):
stmt = select(ProjectMember).options(selectinload(ProjectMember.project))
stmt = select(ProjectMember).options(
selectinload(ProjectMember.project),
selectinload(ProjectMember.member)
)
result = await db.execute(stmt)
return result.scalars().all()
# READ ONE (โหลดข้อมูลของ Project ด้วย)
# READ ONE (โหลดข้อมูล Project และ Member ด้วย)
async def get_project_member_by_id(db: AsyncSession, pm_id: UUID):
stmt = select(ProjectMember).options(selectinload(ProjectMember.project)).where(ProjectMember.pmId == pm_id)
stmt = select(ProjectMember).options(
selectinload(ProjectMember.project),
selectinload(ProjectMember.member)
).where(ProjectMember.pmId == pm_id)
result = await db.execute(stmt)
return result.scalar_one_or_none()
......@@ -73,8 +79,22 @@ async def delete_project_member(db: AsyncSession, pm_id: UUID):
return {"message": "ProjectMember deleted successfully"}
# READ Projects by MemberId (โหลดข้อมูล Project ที่สัมพันธ์กับ ProjectMember ด้วย)
# READ Projects by MemberId (โหลดข้อมูล Project ด้วย)
async def get_projects_by_member_id(db: AsyncSession, member_id: UUID):
stmt = select(ProjectMember).options(selectinload(ProjectMember.project)).where(ProjectMember.memberId == member_id)
stmt = select(ProjectMember).options(
selectinload(ProjectMember.project),
selectinload(ProjectMember.member)
).where(ProjectMember.memberId == member_id)
result = await db.execute(stmt)
return result.scalars().all()
async def get_members_by_project_id(db: AsyncSession, project_id: UUID):
"""
ดึงข้อมูล ProjectMember ทั้งหมดที่สัมพันธ์กับ project_id ที่กำหนด
พร้อมโหลดข้อมูลของ Member ด้วย (nested)
"""
stmt = select(ProjectMember).options(
selectinload(ProjectMember.member)
).where(ProjectMember.projectId == project_id)
result = await db.execute(stmt)
return result.scalars().all()
......@@ -34,7 +34,7 @@ class Member(Base):
updatedAt = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
# ProjectEmployees = relationship("ProjectEmployee", back_populates="member")
project_member = relationship("ProjectMember", back_populates="member")
# ฟังก์ชันเพื่อแฮชรหัสผ่านก่อนบันทึก
def hash_password(self, password):
self.passwordHash = bcrypt.hash(password)
......
......@@ -10,23 +10,9 @@ class ProjectMember(Base):
__tablename__ = 'project_member'
pmId = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
# Foreign Keys
memberId = Column(
UUID(as_uuid=True),
ForeignKey("member.memberId"), # หรือ "users.userId" ตามตารางจริง
nullable=False
)
projectId = Column(
UUID(as_uuid=True),
ForeignKey("project.projectId"),
nullable=False
)
memberId = Column(UUID(as_uuid=True), ForeignKey("member.memberId"), nullable=False)
projectId = Column(UUID(as_uuid=True), ForeignKey("project.projectId"), nullable=False)
role_in_project = Column(String(100), nullable=True)
# Relationship เชื่อมกลับไปยัง Project
project = relationship("Project", back_populates="project_member")
# ถ้ามี Model Member/User ก็สามารถประกาศ relationship ได้ เช่น
# member = relationship("Member", back_populates="project_members")
project = relationship("Project", back_populates="project_member", lazy="joined")
member = relationship("Member", back_populates="project_member", lazy="joined")
......@@ -12,7 +12,8 @@ from ..controllers.project_member_controller import (
get_project_member_by_id,
update_project_member,
delete_project_member,
get_projects_by_member_id
get_projects_by_member_id,
get_members_by_project_id
)
from ..schemas.project_member_schema import (
ProjectMemberCreate,
......@@ -75,3 +76,11 @@ async def get_projects_for_member(
"""
pms = await get_projects_by_member_id(db, memberId)
return pms
@router.get("/project/{projectId}", response_model=List[ProjectMemberResponse])
async def get_member_for_project(
projectId: UUID,
db: AsyncSession = Depends(get_db)
):
pms = await get_members_by_project_id(db, projectId)
return pms
\ No newline at end of file
# myproject/schemas/project_member_schema.py
from pydantic import BaseModel
from typing import Optional
from uuid import UUID
from .project_schema import ProjectResponse # Import schema ของ Project
from .project_schema import ProjectResponse # Schema ของ Project
from .member_schema import MemberResponse # Schema ของ Member
class ProjectMemberBase(BaseModel):
memberId: UUID
......@@ -15,7 +14,8 @@ class ProjectMemberCreate(ProjectMemberBase):
class ProjectMemberResponse(ProjectMemberBase):
pmId: UUID
projectId: UUID
project: Optional[ProjectResponse] = None # เพิ่ม field นี้เพื่อแสดงข้อมูลของ Project
project: Optional[ProjectResponse] = None # ข้อมูลของ Project ที่สัมพันธ์กัน
member: Optional[MemberResponse] = None # ข้อมูลของ Member ที่สัมพันธ์กัน
class Config:
orm_mode = True
<app-page-header [title]="'จัดการสมาชิก'" [activeTitle]="'ผู้ดูแลระบบ'" [title1]="'จัดการสมาชิก'"></app-page-header>
<app-page-header [title]="'จัดการสมาชิกในโครงการ'" [activeTitle]="'จัดการข้อมูลโครงการ'"
[title1]="'จัดการสมาชิกในโครงการ'"></app-page-header>
<div class="grid grid-cols-12 gap-6">
......@@ -11,27 +12,17 @@
</div>
<div class="flex flex-wrap gap-2">
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-primary-full me-2" (click)="new()"
data-hs-overlay="#modal-detail"><i class="ri-add-line font-semibold align-middle"></i>{{ 'Create' |
data-hs-overlay="#modal-detail"><i class="ri-add-line font-semibold align-middle"></i>{{
'เพิ่มพนักงานเข้าโครงการ' |
translate}}
</a>
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-success-full me-2" *ngIf="someSelected"
(click)="adjustSelect(1)"><i class="ri-user-follow-line font-semibold align-middle"></i>{{ 'Active' |
translate}}
</a>
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-secondary-full me-2"
*ngIf="someSelected" (click)="adjustSelect(0)"><i
class="ri-user-unfollow-line font-semibold align-middle"></i>{{ 'Unactive' |
translate}}
</a>
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-danger-full me-2" *ngIf="someSelected"
(click)="deleteSelect()"><i class="ri-delete-bin-line font-semibold align-middle"></i>{{ 'Delete' |
translate}}
</a>
<div>
<input class="form-control form-control" type="text" placeholder="ค้นหาสมาชิก"
<input class="form-control form-control" type="text" placeholder="ค้นหาพนักงานในโครงการ"
aria-label=".form-control-sm example" [(ngModel)]='searchTerm'>
</div>
<!-- <div>
......@@ -56,13 +47,10 @@
<input class="form-check-input check-all" type="checkbox" id="all-products"
(change)="toggleAll($event)" [checked]="allSelected" aria-label="...">
</th>
<th scope="col" class="text-start">{{ 'Username' | translate}}</th>
<!-- <th scope="col" class="text-start">{{ 'Username' | translate}}</th> -->
<th scope="col" class="text-start">{{ 'Fullname' | translate}}</th>
<th scope="col" class="text-start">{{ 'Email' | translate}}</th>
<th scope="col" class="text-start">{{ 'Mobile' | translate}}</th>
<th scope="col" class="text-start">{{ 'User Group' | translate}}</th>
<th scope="col" class="text-start">{{ 'Status' | translate}}</th>
<th scope="col" class="text-start">{{ 'Update Date' | translate}}</th>
<th scope="col" class="text-start"></th>
</tr>
</thead>
......@@ -70,19 +58,18 @@
@for(item of filterList;track filterList){
<tr class="border border-defaultborder dark:border-defaultborder/10">
<td class="product-checkbox"><input class="form-check-input" type="checkbox" [checked]="selectedItems.get(item.memberId)"
(change)="onCheckboxChange(item.memberId)" aria-label="..." value="">
<td class="product-checkbox"><input class="form-check-input" type="checkbox"
[checked]="selectedItems.get(item.memberId)" (change)="onCheckboxChange(item.memberId)"
aria-label="..." value="">
</td>
<td>
<div class="flex items-center">
<span class="avatar avatar-sm p-1 me-1 bg-light !rounded-full">
<img
[src]="item.getPicture()"
alt="" id="profile-img">
<img [src]="item.member.getPicture()" alt="" id="profile-img">
</span>
<div class="ms-2">
<p class="font-semibold mb-0 flex items-center text-primary"><a (click)="view(item)">
{{item.username}}</a></p>
{{item.member.getFullname()}}</a></p>
<p class="text-[0.75rem] text-muted mb-0">{{item.memberId}}</p>
</div>
</div>
......@@ -98,34 +85,22 @@
</div>
</div>
</td> -->
<td> {{item.firstName}} {{item.lastName}}</td>
<!-- <td> {{item.member.getFullname()}}</td> -->
<td>
<div>
<span class="block mb-1"><i
class="ri-mail-line me-2 align-middle text-[.875rem] text-[#8c9097] dark:text-white/50 inline-flex"></i>{{item.email}}</span>
class="ri-mail-line me-2 align-middle text-[.875rem] text-[#8c9097] dark:text-white/50 inline-flex"></i>{{item.member.email}}</span>
</div>
</td>
<td>
<div>
<span class="block"><i
class="ri-phone-line me-2 align-middle text-[.875rem] text-[#8c9097] dark:text-white/50 inline-flex"></i>{{item.phoneNumber}}</span>
class="ri-phone-line me-2 align-middle text-[.875rem] text-[#8c9097] dark:text-white/50 inline-flex"></i>{{item.member.phoneNumber}}</span>
</div>
</td>
<td> <span
class="badge bg-{{ item.role == 1 ? 'primary' : 'info'}} text-white">{{item.getRole()}}</span>
</td>
<td> <span
class="badge bg-{{ item.status == 1 ? 'primary' : 'danger'}} text-white">{{item.getStatus()}}</span>
</td>
<td><span class="badge bg-info/10 text-primary"><i
class="bi bi-clock me-1"></i>{{item.updatedAt | date : 'medium'}}</span></td>
<td>
<td>
<div class="flex flex-row items-center !gap-2 ">
<a aria-label="anchor" (click)="view(item)" data-hs-overlay="#modal-detail"
class="ti-btn ti-btn-wave !gap-0 !m-0 bg-info/10 text-info hover:bg-info hover:text-white hover:border-info"><i
class="ri-pencil-line"></i></a>
<a aria-label="anchor" href="javascript:void(0);" (click)="delete(item)"
class="ti-btn ti-btn-wave product-btn !gap-0 !m-0 bg-danger/10 text-danger hover:bg-danger hover:text-white hover:border-danger"><i
class="ri-delete-bin-line"></i></a>
......@@ -186,11 +161,11 @@
<!-- Start:: Create Contact -->
<div id="modal-detail" class="hs-overlay hidden ti-modal [--overlay-backdrop:static]">
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out">
<div class="hs-overlay-open:mt-7 ti-modal-box mt-0 ease-out lg:!max-w-4xl lg:w-full m-3 lg:!mx-auto">
<div class="ti-modal-content">
<div class="ti-modal-header">
<h6 class="modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">{{ 'Create' |
translate }} {{ 'User' | translate }}
<h6 class="modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">{{
'เพิ่มพนักงานเข้าโครงการ' }}
</h6>
<button type="button" class="hs-dropdown-toggle !text-[1rem] !font-semibold !text-defaulttextcolor"
data-hs-overlay="#modal-detail" #closeModal>
......@@ -199,100 +174,133 @@
</button>
</div>
<div class="ti-modal-body px-4">
<div class="grid grid-cols-12 gap-4">
<div class="grid grid-cols-12 gap-6">
<div class="xl:col-span-12 col-span-12">
<div class="mb-0 text-center">
<span class="avatar avatar-xxl avatar-rounded">
<img [src]="selectModel.getPicture()" alt="" id="profile-img">
<span class="badge rounded-full bg-primary avatar-badge">
<input ng2FileSelect [uploader]="uploaderProfile" type="file" name="photo" class="absolute w-full h-full opacity-[0]" id="profile-change">
<i class="fe fe-camera text-[.625rem]"></i>
</span>
</span>
</div>
<div class="box">
<div class="box-header justify-between">
<div class="box-title">
{{ 'All List' | translate}} <span
class="badge bg-light text-default rounded-full ms-1 text-[0.75rem] align-middle">{{itemsList.length}}</span>
</div>
<div class="xl:col-span-12 col-span-12">
<label for="deal-title" class="form-label">{{'Username' | translate}}</label>
<input type="text" class="form-control" id="deal-title" placeholder="" [(ngModel)]="selectModel.username">
<div class="text-danger" *ngIf="!selectModel.username">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="box-body">
<div class="table-responsive">
<table class="table whitespace-nowrap min-w-full ti-custom-table-hover">
<thead>
<tr class="border-b border-defaultborder">
<th scope="col" class="text-start"></th>
<th scope="col" class="text-start">{{ 'Fullname' | translate}}</th>
<th scope="col" class="text-start">{{ 'Email' | translate}}</th>
<th scope="col" class="text-start">{{ 'Mobile' | translate}}</th>
<div class="xl:col-span-12 col-span-12">
<label for="deal-title" class="form-label">{{'Password' | translate}}</label>
<input type="password" class="form-control" id="deal-title" placeholder=""
[(ngModel)]="selectModel.password">
<div class="text-danger" *ngIf="!selectModel.password">
{{'Please fill in information' | translate}}
</tr>
</thead>
<tbody>
@for(item of userList;track userList){
<tr class="border border-defaultborder dark:border-defaultborder/10">
<td>
<!-- <div class="flex flex-row items-center !gap-2 ">
<a aria-label="anchor" (click)="view(item)" data-hs-overlay="#modal-detail"
class="ti-btn ti-btn-wave !gap-0 !m-0 bg-info/10 text-info hover:bg-info hover:text-white hover:border-info"><i
class="ri-pencil-line"></i></a>
<a aria-label="anchor" href="javascript:void(0);" (click)="delete(item)"
class="ti-btn ti-btn-wave product-btn !gap-0 !m-0 bg-danger/10 text-danger hover:bg-danger hover:text-white hover:border-danger"><i
class="ri-delete-bin-line"></i></a>
</div> -->
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-primary-full me-2"
(click)="selectMember(item)"><i
class="ri-add-line font-semibold align-middle"></i>{{ 'เลือก' |
translate}}
</a>
</td>
<td>
<div class="flex items-center">
<span class="avatar avatar-sm p-1 me-1 bg-light !rounded-full">
<img [src]="item.getPicture()" alt="" id="profile-img">
</span>
<div class="ms-2">
<p class="font-semibold mb-0 flex items-center text-primary"><a>
{{item.firstName}} {{item.lastName}}</a></p>
<p class="text-[0.75rem] text-muted mb-0">{{item.memberId}}</p>
</div>
</div>
</td>
<div class="xl:col-span-12 col-span-12">
<label for="deal-title" class="form-label">{{'Confirm Password' | translate}}</label>
<input type="password" class="form-control" id="deal-title" placeholder="" [(ngModel)]="confirmPassword">
<div class="text-danger" *ngIf="!confirmPassword">
{{'Please fill in information' | translate}}
</div>
<div class="text-danger" *ngIf="confirmPassword && (confirmPassword != selectModel.password)">
{{'Password Not Match' | translate}}
<!-- <td>
<div class="flex">
<div class="ms-2">
<p class="font-semibold mb-0 flex items-center text-primary"><a (click)="view(item)"
data-hs-overlay="#modal-detail">
{{item.username}}</a></p>
<p class="text-[0.75rem] text-muted mb-0">{{item.memberId}}</p>
</div>
</div>
<div class="xl:col-span-6 col-span-12">
<label for="deal-title" class="form-label">{{'ชื่อ' | translate}}</label>
<input type="text" class="form-control" id="deal-title" placeholder="" [(ngModel)]="selectModel.firstName">
<div class="text-danger" *ngIf="!selectModel.firstName">
{{'Please fill in information' | translate}}
</td> -->
<!-- <td> {{item.firstName}} {{item.lastName}}</td> -->
<td>
<div>
<span class="block mb-1"><i
class="ri-mail-line me-2 align-middle text-[.875rem] text-[#8c9097] dark:text-white/50 inline-flex"></i>{{item.email}}</span>
</div>
</td>
<td>
<div>
<span class="block"><i
class="ri-phone-line me-2 align-middle text-[.875rem] text-[#8c9097] dark:text-white/50 inline-flex"></i>{{item.phoneNumber}}</span>
</div>
</td>
</tr>
}
<div class="xl:col-span-6 col-span-12">
<label for="deal-title" class="form-label">{{'นามสกุล' | translate}}</label>
<input type="text" class="form-control" id="deal-title" placeholder="" [(ngModel)]="selectModel.lastName">
<div class="text-danger" *ngIf="!selectModel.lastName">
{{'Please fill in information' | translate}}
</tbody>
</table>
</div>
</div>
<div class="xl:col-span-6 col-span-12">
<label for="deal-title" class="form-label">{{'อีเมล' | translate}}</label>
<input type="text" class="form-control" id="deal-title" placeholder="" [(ngModel)]="selectModel.email">
<div class="text-danger" *ngIf="!selectModel.email">
{{'Please fill in information' | translate}}
<!-- <div class="box-footer">
<div class="flex items-center flex-wrap overflow-auto" *ngIf="filterList.length > 0">
<div class="mb-2 sm:mb-0">
<div>
{{'Showing' | translate}} {{filterList.length}} {{'entries'
| translate}} <i class="bi bi-arrow-right ms-2 font-semibold"></i>
</div>
</div>
<div class="ms-auto">
<nav aria-label="Page navigation">
<ul class="ti-pagination mb-0">
<li *ngIf="pageIndex>0" class="page-item {{pageIndex==0 ? 'disabled' : ''}}"><a
class="page-link px-3 py-[0.375rem]"
(click)="pageIndex = pageIndex-1;updatePagedItems()">{{'Previous' | translate}}</a></li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="pageIndex-1>0" (click)="pageIndex = pageIndex-2;updatePagedItems()">{{pageIndex-1}}</a></li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="pageIndex>0 && ((pageIndex-1)*10 < (searchTerm == '' ? itemsList.length : filterList.length))"
(click)="pageIndex = pageIndex-1;updatePagedItems()">{{pageIndex}}</a></li>
<div class="xl:col-span-6 col-span-12">
<label for="deal-title" class="form-label">{{'เบอร์ติดต่อ' | translate}}</label>
<input type="text" class="form-control" id="deal-title" placeholder=""
[(ngModel)]="selectModel.phoneNumber">
<div class="text-danger" *ngIf="!selectModel.phoneNumber">
{{'Please fill in information' | translate}}
<li class="page-item"><a class="page-link active px-3 py-[0.375rem]"
href="javascript:void(0);">{{pageIndex +1}}</a>
</li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="(pageIndex+1)*10 < (searchTerm == '' ? itemsList.length : filterList.length)"
(click)="pageIndex = pageIndex+1;updatePagedItems()">{{pageIndex +2}}</a></li>
<li class="page-item"><a class="page-link px-3 py-[0.375rem]" href="javascript:void(0);"
*ngIf="(pageIndex+2)*10 < (searchTerm == '' ? itemsList.length : filterList.length)"
(click)="pageIndex = pageIndex+2;updatePagedItems()">{{pageIndex +3}}</a></li>
<li *ngIf="(pageIndex+1)*10 < (searchTerm == '' ? itemsList.length : filterList.length)"
class="page-item"><a class="page-link px-3 py-[0.375rem]"
(click)="pageIndex = pageIndex+1;updatePagedItems()">{{'Next' |
translate}}</a>
</li>
</ul>
</nav>
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<label class="form-label">{{'User Role' | translate}}</label>
<ng-select name="choices-multiple-remove-button1" id="choices-multiple-remove-button1" placeholder=""
[(ngModel)]="selectModel.role">
<ng-option [value]="0">{{'ผู้ใช้งานทั่วไป' | translate}}</ng-option>
<ng-option [value]="1">{{'ผู้ดูแลบริษัท' | translate}}</ng-option>
</ng-select>
</div> -->
</div>
<div class="xl:col-span-12 col-span-12">
<label class="form-label">{{'Status' | translate}}</label>
<ng-select name="choices-multiple-remove-button2" id="choices-multiple-remove-button2" placeholder=""
[(ngModel)]="selectModel.status">
<ng-option [value]="0">{{'Unactive' | translate}}</ng-option>
<ng-option [value]="1">{{'Active' | translate}}</ng-option>
</ng-select>
</div>
</div>
</div>
<div class="ti-modal-footer">
......@@ -300,8 +308,8 @@
data-hs-overlay="#modal-detail">
{{'Cancel' | translate}}
</button>
<button type="button" (click)="save()" class="ti-btn bg-primary text-white !font-medium">{{'Save' |
translate}}</button>
<!-- <button type="button" (click)="save()" class="ti-btn bg-primary text-white !font-medium">{{'Save' |
translate}}</button> -->
</div>
</div>
</div>
......
import { CommonModule } from "@angular/common";
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
import { NgSelectModule } from "@ng-select/ng-select";
import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { SharedModule } from "../../../shared/shared.module";
import { UserService } from "../../services/user.service";
import { UserProfileModel } from "../../models/user.model";
import { FormsModule } from "@angular/forms";
import swal from 'sweetalert';
import { MatPaginator, PageEvent } from "@angular/material/paginator";
import { UserRoleModel } from "../../models/user-role-model";
import { FileUploadModule } from 'ng2-file-upload';
import { FileItem, FileUploader, ParsedResponseHeaders } from "ng2-file-upload";
import { environment } from "../../../../environments/environment";
import { TokenService } from "../../../shared/services/token.service";
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
import { NgSelectModule } from "@ng-select/ng-select";
import { TranslateModule, TranslateService } from "@ngx-translate/core";
import { SharedModule } from "../../../shared/shared.module";
import { FormsModule } from "@angular/forms";
import swal from 'sweetalert';
import { MatPaginator, PageEvent } from "@angular/material/paginator";
import { UserRoleModel } from "../../models/user-role-model";
import { FileUploadModule } from 'ng2-file-upload';
import { FileItem, FileUploader, ParsedResponseHeaders } from "ng2-file-upload";
import { environment } from "../../../../environments/environment";
import { TokenService } from "../../../shared/services/token.service";
import { ProjectMemberService } from "../../services/project-members.service";
import { ProjectMemberModel } from "../../models/project-members";
import { UserService } from "../../services/user.service";
import { UserProfileModel } from "../../models/user.model";
@Component({
selector: 'app-admin-project-emp-manage',
standalone: true,
......@@ -33,16 +35,18 @@ export class AdminProjectEmpManageComponent {
allSelected = false;
someSelected = false;
confirmPassword = ""
itemsList: UserProfileModel[] = []
filterList: UserProfileModel[] = []
selectModel: UserProfileModel = new UserProfileModel()
itemsList: ProjectMemberModel[] = []
filterList: ProjectMemberModel[] = []
selectModel: ProjectMemberModel = new ProjectMemberModel()
selectedItems = new Map<string, boolean>();
roleList: UserRoleModel[] = []
empList: UserProfileModel[] = []
empList: ProjectMemberModel[] = []
descName = 'engName'
pageIndex = 0;
uploaderProfile: FileUploader | undefined;
uploadErrorMsg: string = "";
userList: UserProfileModel[] = []
get searchTerm(): string {
return this._searchTerm;
}
......@@ -56,12 +60,21 @@ export class AdminProjectEmpManageComponent {
this.updatePagedItems()
}
}
projectId = ""
_searchTerm = "";
constructor(private userService: UserService, public translate: TranslateService, private tokenService: TokenService) {
constructor(private projectMemberService: ProjectMemberService, private userService: UserService, public translate: TranslateService, private tokenService: TokenService) {
this.projectId = this.tokenService.getSelectCompany().projectId!;
this.getUserProject()
this.getMemberAll()
this.uploadConfig()
}
getMemberAll() {
this.userService.getLists().subscribe(result => {
this.userList = result
})
}
uploadConfig() {
this.uploaderProfile = new FileUploader({
url: environment.baseUrl + "/api/upload-image",
......@@ -103,7 +116,7 @@ export class AdminProjectEmpManageComponent {
if (item.isSuccess) {
const res = JSON.parse(response);
console.log("res", res);
this.selectModel.picture = res.filename
this.selectModel.member.picture = res.filename
swal(res.message, "บันทึกสำเร็จ", "success");
} else {
......@@ -115,7 +128,14 @@ export class AdminProjectEmpManageComponent {
ngOnInit(): void {
this.userService.getLists().subscribe(result => {
// this.projectMemberService.getLists(this.projectId).subscribe(result => {
// this.itemsList = result
// this.updatePagedItems()
// })
}
getUserProject() {
this.projectMemberService.getLists(this.projectId).subscribe(result => {
this.itemsList = result
this.updatePagedItems()
})
......@@ -124,17 +144,17 @@ export class AdminProjectEmpManageComponent {
filter(v: string) {
return this.itemsList?.filter(
(x) =>
x.memberId?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.username?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.email?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.phoneNumber?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getRole()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getStatus()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.getFullname()?.toLowerCase().indexOf(v.toLowerCase()) !== -1
x.member.memberId?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.member.username?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.member.email?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.member.phoneNumber?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.member.getRole()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.member.getStatus()?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.member.getFullname()?.toLowerCase().indexOf(v.toLowerCase()) !== -1
);
}
delete(item: UserProfileModel) {
delete(item: ProjectMemberModel) {
swal({
title: "Are you sure?",
text: "You won't be able to revert this!",
......@@ -145,9 +165,9 @@ export class AdminProjectEmpManageComponent {
})
.then((willDelete: any) => {
if (willDelete) {
this.userService.delete(item).subscribe(result => {
this.projectMemberService.delete(item).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit()
this.getUserProject()
})
}
......@@ -156,18 +176,18 @@ export class AdminProjectEmpManageComponent {
new() {
this.action = 'add'
this.selectModel = new UserProfileModel()
this.selectModel = new ProjectMemberModel()
}
view(item: UserProfileModel) {
view(item: ProjectMemberModel) {
this.action = 'edit'
this.confirmPassword = ''
this.selectModel = new UserProfileModel(item)
this.selectModel = new ProjectMemberModel(item)
console.log(this.selectModel)
}
save() {
selectMember(item: UserProfileModel) {
swal({
title: "Are you sure?",
text: "คุณต้องการบันทึกหรือไม่",
......@@ -178,17 +198,21 @@ export class AdminProjectEmpManageComponent {
.then((willDelete: any) => {
if (willDelete) {
if (this.action == 'add') {
this.userService.save(this.selectModel).subscribe(result => {
this.projectMemberService.save({
"memberId": item.memberId,
"role_in_project": "employee",
"projectId": this.projectId
}).subscribe(result => {
console.log(result)
swal("Save Success!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit()
this.getUserProject()
this.childModal?.nativeElement.click()
})
} else if (this.action == 'edit') {
this.userService.update(this.selectModel).subscribe(result => {
this.projectMemberService.update(this.selectModel).subscribe(result => {
console.log(result)
swal("Update Success!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit()
this.getUserProject()
this.childModal?.nativeElement.click()
})
}
......@@ -228,7 +252,7 @@ export class AdminProjectEmpManageComponent {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
employeeInfo += `${this.translate.instant('Fullname')}: ${user.getFullname()}\n`;
employeeInfo += `${this.translate.instant('Fullname')}: ${user.member.getFullname()}\n`;
}
}
});
......@@ -246,9 +270,9 @@ export class AdminProjectEmpManageComponent {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
this.userService.delete(user).subscribe(result => {
this.projectMemberService.delete(user).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit();
this.getUserProject();
});
}
}
......@@ -257,45 +281,13 @@ export class AdminProjectEmpManageComponent {
});
}
adjustSelect(status: number) {
let title = "Are you sure?"
let employeeInfo = ''; // ตัวแปรสำหรับเก็บข้อมูลพนักงาน
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
employeeInfo += `${this.translate.instant('Fullname')}: ${user.getFullname()}\n`;
}
}
});
swal({
title: title,
text: employeeInfo,
icon: "warning",
dangerMode: false,
buttons: ["Cancel", "Confirm"],
})
.then((willDelete: any) => {
if (willDelete) {
this.selectedItems.forEach((isSelected, memberId) => {
if (isSelected) {
const user = this.itemsList.find(user => user.memberId === memberId);
if (user) {
user.status = status
this.userService.update(user).subscribe(result => {
swal("Save Success!!", "บันทึกข้อมูลสำเร็จ", "success");
this.ngOnInit();
});
}
}
});
}
});
}
filterEmp(empId: string) {
this.selectModel = this.empList.filter(e => e.memberId == empId)[0]
}
// selectMember(){
// }
}
import { TranslateService } from "@ngx-translate/core";
import { BaseModel } from "./base.model";
import { ProjectModel } from "./project.model";
import { UserProfileModel } from "./user.model";
export class ProjectMemberModel extends BaseModel {
pm_id: string;
user_id: string;
projectId: string;
memberId: string;
role_in_project: string;
created_at: string;
updated_at: string;
pmId: string;
projectId: string;
project: ProjectModel;
member: UserProfileModel;
constructor(data?: Partial<ProjectMemberModel>, translateService?: TranslateService) {
super(data, translateService);
this.pm_id = data?.pm_id ?? '';
this.user_id = data?.user_id ?? '';
this.pmId = data?.pmId ?? '';
this.memberId = data?.memberId ?? '';
this.projectId = data?.projectId ?? '';
this.role_in_project = data?.role_in_project ?? '';
this.created_at = data?.created_at ?? new Date().toISOString();
this.updated_at = data?.updated_at ?? new Date().toISOString();
}
this.project = data?.project || new ProjectModel();
this.member = data?.member ? new UserProfileModel(data.member) : new UserProfileModel();
}
}
......@@ -19,7 +19,7 @@ export class ProjectMemberService {
.pipe(map((e) => new ProjectMemberModel(e)));
}
getLists() {
getLists(projectId: string) {
return this.http
.get<ProjectMemberModel[]>(this.apiBaseUrl)
.pipe(
......@@ -27,25 +27,23 @@ export class ProjectMemberService {
);
}
save(body: ProjectMemberModel) {
return this.http.post<{
"message": string,
"user": ProjectMemberModel
}>(this.apiBaseUrl, new ProjectMemberModel(body));
save(body: any) {
return this.http.post<ProjectMemberModel>(this.apiBaseUrl, body);
}
update(body: ProjectMemberModel) {
return this.http.put<{
"message": string,
"user": ProjectMemberModel
}>(this.apiBaseUrl + "/" + body.user_id, new ProjectMemberModel(body));
}>(this.apiBaseUrl + "/" + body.memberId, new ProjectMemberModel(body));
}
delete(body: ProjectMemberModel) {
return this.http.delete<{
"message": string,
"user": ProjectMemberModel
}>(this.apiBaseUrl + "/" + body.user_id);
}>(this.apiBaseUrl + "/" + body.pmId);
}
getCompanyAdmin(memberId: string) {
......
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