Commit a2ae82b1 by DESKTOP-E3GSHH7\myhr

การจัดการบทความ

parent ec2177a8
:host {
display: block;
}
.small-html {
font-size: 0.85rem; /* ลดขนาดฟอนต์ */
line-height: 1.2; /* ลดระยะบรรทัด */
max-height: 150px; /* จำกัดความสูง */
overflow-y: auto; /* ถ้าเนื้อหายาวเกิน ให้เลื่อนดูได้ */
display: block;
}
.border-radius-1{
border-radius: 0.50rem;
}
.font-14{
font-size: 14px;
}
.font-16{
font-size: 16px;
}
.font-24{
font-size: 24px;
}
.font-36{
font-size: 36px;
}
\ No newline at end of file
<app-page-header [title]="'จัดการบทความ'" [activeTitle]="'ผู้ดูแลระบบ'" [title1]="'จัดการบทความ'"></app-page-header>
<div class="grid grid-cols-12 gap-6">
<div class="xl:col-span-12 col-span-12">
<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="flex flex-wrap gap-2">
<a href="javascript:void(0);" class="hs-dropdown-toggle ti-btn ti-btn-primary-full me-2" (click)="new()"
(click)="openDialog()" data-hs-overlay="#modal-detail"><i
class="ri-add-line font-semibold align-middle"></i>{{ 'Create' |
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="ค้นหาบริษัท"
aria-label=".form-control-sm example" [(ngModel)]='searchTerm'>
</div>
</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">
<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">รูปภาพ</th>
<th scope="col" class="text-start">หัวข้อบทความ</th>
<th scope="col" class="text-start">ผู้เขียนบทความ</th>
<!-- <th scope="col" class="text-start">{{"Status" | translate}}</th> -->
<th scope="col" class="text-start">วันที่สร้าง</th>
<th scope="col" class="text-start">วันที่เเก้ไขล่าสุด</th>
<!-- <th scope="col" class="text-start">{{"Update Date" | translate}}</th> -->
<th scope="col" class="text-start">การจัดการ</th>
</tr>
</thead>
<tbody>
@if (filterList.length > 0) {
@for (item of filterList; track item.articleId) {
<tr class="border border-defaultborder dark:border-defaultborder/10">
<td class="product-checkbox">
<input class="form-check-input" type="checkbox" [checked]="selectedItems.get(item.articleId) || false"
(change)="onCheckboxChange(item.articleId)" aria-label="...">
</td>
<td>
<div class="flex items-center">
<span class="p-3 me-1">
<img [src]="item.getPicture()" alt="" id="profile-img" class="border-radius-1">
</span>
</div>
</td>
<td>
<div>
<span class="block mb-1">
{{item.title}}
</span>
</div>
</td>
<td>
<div>
<span class="block mb-1">
{{item.author}}
</span>
</div>
</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.createdDate | date : 'medium'}}
</span>
</td>
<td>
<span class="badge bg-info/10 text-primary">
<i class="bi bi-clock me-1"></i>
{{item.lastModifiedDate | date : 'medium'}}
</span>
</td>
<td>
<div class="flex flex-row items-center !gap-2 ">
<a aria-label="anchor" (click)="viewArticleDetail(item.articleId)"
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-search-line"></i>
</a>
<a aria-label="anchor" (click)="view(item)" (click)="openDialog()"
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>
</td>
</tr>
}
} @else {
<tr>
<td [attr.colspan]="6" class="text-center py-4">
<ng-container *ngIf="itemsList.length === 0 && !searchTerm">
<p>กำลังโหลดข้อมูล หรือไม่มีข้อมูลเลย...</p>
</ng-container>
<ng-container *ngIf="itemsList.length > 0 && filterList.length === 0 && searchTerm">
<p>ไม่พบข้อมูลที่ค้นหา...</p>
</ng-container>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
<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>
<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>
</div>
</div>
</div>
<ng-template #articleModel let-modal>
<h3 mat-dialog-title>
<h3 class="modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">{{ 'Create' |
translate }}{{ 'บทความ' | translate }}
</h3>
</h3>
<div class="w-full flex justify-end">
<div class="absolute flex">
<div class="px-1">
</div>
</div>
</div>
<mat-dialog-content>
<div class="box p-9 top-4">
<div class="grid grid-cols-12 gap-4">
<div class="xl:col-span-12 col-span-12 justify-items-center">
<div class="mb-0 text-center">
<span class="">
<img [src]="selectModel.getPicture()" alt="" id="profile-img" class="border-radius-1"
style="width: 300px; height: 200px;">
<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>
<div class="xl:col-span-6 col-span-12">
<label for="articleId" class="text-primary mt-4 font-bold font-14">{{'รหัสบทความ' | translate}}</label>
<input type="text" class="form-control" id="articleId" placeholder="" [(ngModel)]="selectModel.articleId"
[readonly]="action === 'edit'" [ngClass]="{ '!bg-input-readonly': action === 'edit' }">
<div class="text-danger" *ngIf="!selectModel.articleId && action === 'add'">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-6 col-span-12">
<label for="title" class="text-primary mt-4 font-bold font-14">{{'ชื่อหัวข้อบทความ' | translate}}</label>
<input type="text" class="form-control" id="title" placeholder="" [(ngModel)]="selectModel.title">
<div class="text-danger" *ngIf="!selectModel.title">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<label for="author" class="form-label">{{'ผู้เขียนบทความ' | translate}}</label>
<input type="text" class="form-control" id="author" placeholder="" [(ngModel)]="selectModel.author">
<div class="text-danger" *ngIf="!selectModel.author">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-6 col-span-12">
<label for="createdDate" class="form-label">{{'วันที่สร้าง' | translate}}</label>
<input type="datetime-local" class="form-control" id="createdDate" placeholder=""
[(ngModel)]="selectModel.createdDate">
<div class="text-danger" *ngIf="!selectModel.createdDate">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-6 col-span-12">
<label for="lastModifiedDate" class="form-label">{{'วันที่เเก้ไขล่าสุด' | translate}}</label>
<input type="datetime-local" class="form-control" id="lastModifiedDate" placeholder=""
[(ngModel)]="selectModel.lastModifiedDate">
<div class="text-danger" *ngIf="!selectModel.lastModifiedDate">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-6 col-span-12">
<label for="Detail_d">{{"เรื่องย่อ" | translate}}: <span class="text-danger">*</span></label>
<quill-editor [(ngModel)]="!selectModel.excerpt" [modules]="quillConfig" [styles]="{height: '200px'}"
theme="snow" (onEditorCreated)="onEditorCreated($event)" (onContentChanged)="onContentChanged($event)"
#excerpt="ngModel">
</quill-editor>
</div>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<button type="button" class="hs-dropdown-toggle ti-btn ti-btn-light align-middle" 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>
</mat-dialog-actions>
</ng-template>
<!-- <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="ti-modal-content">
<div class="ti-modal-header">
<h6 class="modal-title text-[1rem] font-semibold text-defaulttextcolor" id="mail-ComposeLabel">{{ 'Create' |
translate }} {{ 'บทความ' | translate }}
</h6>
<button type="button" class="hs-dropdown-toggle !text-[1rem] !font-semibold !text-defaulttextcolor"
data-hs-overlay="#modal-detail" #closeModal>
<span class="sr-only">{{'Close' | translate}}</span>
<i class="ri-close-line"></i>
</button>
</div>
<div class="ti-modal-body px-4">
<div class="grid grid-cols-12 gap-4">
<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>
<div class="xl:col-span-12 col-span-12">
<label for="articleId" class="form-label">{{'รหัสบทความ' | translate}}</label>
<input type="text" class="form-control" id="articleId" placeholder="" [(ngModel)]="selectModel.articleId"
[readonly]="action === 'edit'" [ngClass]="{ '!bg-input-readonly': action === 'edit' }">
<div class="text-danger" *ngIf="!selectModel.articleId && action === 'add'">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<label for="title" class="form-label">{{'ชื่อหัวข้อบทความ' | translate}}</label>
<input type="text" class="form-control" id="title" placeholder="" [(ngModel)]="selectModel.title">
<div class="text-danger" *ngIf="!selectModel.title">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<label for="author" class="form-label">{{'ผู้เขียนบทความ' | translate}}</label>
<input type="text" class="form-control" id="author" placeholder="" [(ngModel)]="selectModel.author">
<div class="text-danger" *ngIf="!selectModel.author">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<label for="createdDate" class="form-label">{{'วันที่สร้าง' | translate}}</label>
<input type="datetime-local" class="form-control" id="createdDate" placeholder=""
[(ngModel)]="selectModel.createdDate">
<div class="text-danger" *ngIf="!selectModel.createdDate">
{{'Please fill in information' | translate}}
</div>
</div>
<div class="xl:col-span-12 col-span-12">
<label for="lastModifiedDate" class="form-label">{{'วันที่เเก้ไขล่าสุด' | translate}}</label>
<input type="datetime-local" class="form-control" id="lastModifiedDate" placeholder=""
[(ngModel)]="selectModel.lastModifiedDate">
<div class="text-danger" *ngIf="!selectModel.lastModifiedDate">
{{'Please fill in information' | translate}}
</div>
</div>
</div>
</div>
<div class="ti-modal-footer">
<button type="button" class="hs-dropdown-toggle ti-btn ti-btn-light align-middle"
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>
</div>
</div>
</div>
</div> -->
\ No newline at end of file
import { Component, ElementRef, ViewChild } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Router, RouterModule } from '@angular/router';
import { SharedModule } from '../../../shared/shared.module';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import swal from 'sweetalert';
import { MatPaginator } from '@angular/material/paginator';
import { FormsModule } from '@angular/forms';
import { NgSelectModule } from '@ng-select/ng-select';
import { CommonModule } from '@angular/common';
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 { ArticleModel } from '../../models/article.model';
import { ArticleService } from '../../services/article.service';
import { QuillModule } from 'ngx-quill';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
@Component({
selector: 'app-article-manage',
standalone: true,
imports: [
CommonModule,
SharedModule,
TranslateModule,
NgSelectModule,
FormsModule,
MatPaginator,
RouterModule,
FileUploadModule,
QuillModule,
MatDialogModule
],
templateUrl: './article-manage.component.html',
styleUrl: './article-manage.component.css',
})
export class ArticleManageComponent {
quillConfig = {
toolbar: [
['link'], // เพิ่มปุ่มลิงก์
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'script': 'sub' }, { 'script': 'super' }], // superscript/subscript
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
[{ 'direction': 'rtl' }], // text direction
[{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'align': [] }],
['clean'], // remove formatting button
]
};
@ViewChild('closeModal') public childModal?: ElementRef;
@ViewChild('modalDetail') public modalDetail?: ElementRef;
@ViewChild("articleModel") articleModel: any;
dialogRef: any
action = "new";
allSelected = false;
someSelected = false;
itemsList: ArticleModel[] = [];
filterList: ArticleModel[] = [];
selectModel: ArticleModel = new ArticleModel();
selectedItems = new Map<string, boolean>();
editorInstance: any;
// empList: ArticleModel[] = [];
// descName = 'engName';
pageIndex = 0;
uploaderProfile: FileUploader | undefined;
uploadErrorMsg: string = "";
get searchTerm(): string {
return this._searchTerm;
}
set searchTerm(val: string) {
this.pageIndex = 0;
this.allSelected = false;
this._searchTerm = val;
if (val != '') {
this.filterList = this.filter(val);
} else {
this.updatePagedItems();
}
}
_searchTerm = "";
constructor(private articleService: ArticleService, public translate: TranslateService, private tokenService: TokenService, private router: Router,private dialog: MatDialog,) {
this.uploadConfig();
}
isDescriptionValid(): boolean {
const plainText = this.editorInstance?.getText()?.trim() || '';
return plainText.length > 0;
}
onEditorCreated(quill: any) {
this.editorInstance = quill;
}
onContentChanged(event: any) {
const text = event.editor.getText().trim();
if (text.length === 0 && this.editorInstance) {
this.editorInstance.formatLine(0, 1, 'header', false);
}
this.selectModel.content = event.html;
}
uploadConfig() {
this.uploaderProfile = new FileUploader({
url: environment.baseUrl + "/api/upload-image",
isHTML5: true,
authToken: this.tokenService.getToken()!,
});
this.uploaderProfile.onAfterAddingFile = (fileItem: FileItem) => {
fileItem.withCredentials = false;
this.uploadErrorMsg = "";
while (this.uploaderProfile!.queue.length > 1) {
this.uploaderProfile!.queue[0].remove();
}
if (fileItem.file.size > 5000000) {
this.uploadErrorMsg = "maximum file size 5mb.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
fileItem.isCancel = true;
return;
}
if (fileItem.file.type!.indexOf("image") === -1) {
this.uploadErrorMsg = "please upload image only.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
fileItem.isCancel = true;
return;
}
fileItem.upload();
};
this.uploaderProfile.onCompleteItem = (
item: FileItem,
response: string,
status: number,
headers: ParsedResponseHeaders
) => {
if (item.isSuccess) {
const res = JSON.parse(response);
console.log("res", res);
this.selectModel.picture = res.filename;
swal(res.message, "บันทึกสำเร็จ", "success");
} else {
this.uploadErrorMsg = "cannot upload file.";
swal("Opp!!", "ไม่สามารถอัพโหลดได้", "info");
}
};
}
getArticle() {
this.articleService.getList().subscribe({
next: (response: ArticleModel[]) => {
this.itemsList = response.map((x: any) => new ArticleModel(x, this.translate));
console.log('ข้อมูลบริษัท (itemsList)', this.itemsList);
this.updatePagedItems();
},
error: (error) => {
console.error('error cant get company', error);
swal("ข้อผิดพลาด", "ไม่สามารถดึงข้อมูลบริษัทได้", "error");
}
});
}
ngOnInit(): void {
this.getArticle();
this.itemsList
}
filter(v: string) {
return this.itemsList?.filter(
(x) =>
x.articleId?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.title?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.content?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.excerpt?.toLowerCase().indexOf(v.toLowerCase()) !== -1 ||
x.author?.toLowerCase().indexOf(v.toLowerCase()) !== -1
// x.getStatus().toLowerCase().indexOf(v.toLowerCase()) !== -1
);
}
delete(item: ArticleModel) {
swal({
title: "คุณแน่ใจหรือไม่?",
text: "คุณจะไม่สามารถกู้คืนข้อมูลนี้ได้!",
icon: "warning",
dangerMode: true,
buttons: ["ยกเลิก", "ใช่, ลบเลย!"],
})
.then((willDelete: any) => {
if (willDelete) {
this.articleService.deletearticle(item).subscribe(result => {
swal("ลบสำเร็จ!!", "ลบข้อมูลสำเร็จ", "success");
this.ngOnInit();
}, error => {
console.error("เกิดข้อผิดพลาดในการลบ:", error);
swal("ข้อผิดพลาด!!", "ไม่สามารถลบข้อมูลได้", "error");
});
}
});
}
new() {
this.action = 'add';
this.selectModel = new ArticleModel();
// this.selectModel.status = 1;
this.selectModel.excerpt = "";
this.selectModel.picture = "";
this.selectModel.title = "";
this.selectModel.articleId = "";
this.selectModel.content = "";
this.selectModel.author = "";
this.selectModel.createdDate = new Date().toISOString();
}
view(item: ArticleModel) {
this.action = 'edit';
this.selectModel = new ArticleModel(item);
console.log(this.selectModel);
}
viewArticleDetail(articleId: string) {
this.router.navigate(['/admin/sub-articles', articleId]);
}
save() {
swal({
title: "คุณแน่ใจหรือไม่?",
text: "คุณต้องการบันทึกหรือไม่",
icon: "warning",
dangerMode: false,
buttons: ["ยกเลิก", "ยืนยัน"],
})
.then((willSave: any) => {
if (willSave) {
this.articleService.postArticle(this.selectModel).subscribe(result => {
console.log(result);
swal("บันทึกสำเร็จ!!", "บันทึกข้อมูลสมาชิก", "success");
this.ngOnInit();
this.childModal?.nativeElement.click();
}, error => {
console.error("เกิดข้อผิดพลาดในการบันทึก/อัปเดต:", error);
swal("ข้อผิดพลาด!!", "ไม่สามารถบันทึก/อัปเดตข้อมูลได้", "error");
});
}
});
}
updatePagedItems() {
const startIndex = this.pageIndex * 10;
const endIndex = startIndex + 10;
this.filterList = this.itemsList.slice(startIndex, endIndex);
}
toggleAll(event: any) {
this.allSelected = event.target.checked;
this.selectedItems.clear();
this.itemsList.forEach(item => {
this.selectedItems.set(item.articleId, this.allSelected);
});
this.someSelected = this.itemsList.some(item => this.selectedItems.get(item.articleId));
}
onCheckboxChange(articleId: string) {
const isSelected = this.selectedItems.get(articleId) || false;
this.selectedItems.set(articleId, !isSelected);
this.allSelected = this.itemsList.every(item => this.selectedItems.get(item.articleId));
this.someSelected = this.itemsList.some(item => this.selectedItems.get(item.articleId));
}
deleteSelect() {
let companyInfo = '';
const selectedarticleIdsToDelete: string[] = [];
this.selectedItems.forEach((isSelected, articleId) => {
if (isSelected) {
const item = this.itemsList.find(c => c.articleId === articleId);
if (item) {
companyInfo += `${this.translate.instant('บริษัท')}: ${item.title}\n`;
selectedarticleIdsToDelete.push(item.articleId);
}
}
});
if (selectedarticleIdsToDelete.length === 0) {
swal("ข้อผิดพลาด", "กรุณาเลือกบริษัทที่ต้องการลบ", "warning");
return;
}
swal({
title: "คุณแน่ใจหรือไม่?",
text: companyInfo,
icon: "warning",
dangerMode: true,
buttons: ["ยกเลิก", "ใช่, ลบเลย!"],
})
.then((willDelete: any) => {
if (willDelete) {
const deletePromises = selectedarticleIdsToDelete.map(articleId =>
this.articleService.deletearticleById(articleId).toPromise()
.then(() => true)
.catch(error => {
console.error(`Error deleting company ${articleId}:`, error);
return false;
})
);
Promise.all(deletePromises)
.then(results => {
const allSuccessful = results.every(success => success);
if (allSuccessful) {
swal("ลบสำเร็จ!!", "บันทึกข้อมูลสำเร็จ", "success");
} else {
swal("สำเร็จบางส่วน/ข้อผิดพลาด!!", "มีการลบข้อมูลบางส่วนไม่สำเร็จ หรือมีข้อผิดพลาด", "warning");
}
this.ngOnInit();
this.selectedItems.clear();
this.allSelected = false;
this.someSelected = false;
});
}
});
}
adjustSelect(status: number) { // เพิ่ม status เข้ามาในพารามิเตอร์
let title = "คุณแน่ใจหรือไม่?";
let companyInfo = '';
const selectedCompanies: ArticleModel[] = [];
this.selectedItems.forEach((isSelected, articleId) => {
if (isSelected) {
const company = this.itemsList.find(c => c.articleId === articleId);
if (company) {
companyInfo += `${this.translate.instant('ชื่อบริษัท')}: ${company.title}\n`;
selectedCompanies.push(company);
}
}
});
if (selectedCompanies.length === 0) {
swal("ข้อผิดพลาด", "กรุณาเลือกบริษัทที่ต้องการปรับสถานะ", "warning");
return;
}
swal({
title: title,
text: companyInfo,
icon: "warning",
dangerMode: false,
buttons: ["ยกเลิก", "ยืนยัน"],
})
.then((willAdjust: any) => {
if (willAdjust) {
const updatePromises = selectedCompanies.map(company => {
company.publish = status; // เปลี่ยนจาก publish เป็น status
return this.articleService.postArticle(company).toPromise()
.then(() => true)
.catch(error => {
console.error(`Error updating publish for company ${company.articleId}:`, error);
return false;
});
});
Promise.all(updatePromises)
.then(results => {
const allSuccessful = results.every(success => success);
if (allSuccessful) {
swal("บันทึกสำเร็จ!!", "บันทึกข้อมูลสำเร็จ", "success");
} else {
swal("สำเร็จบางส่วน/ข้อผิดพลาด!!", "มีการอัปเดตสถานะบางส่วนไม่สำเร็จ หรือมีข้อผิดพลาด", "warning");
}
this.ngOnInit();
this.selectedItems.clear();
this.allSelected = false;
this.someSelected = false;
});
}
});
}
openDialog() {
this.dialogRef = this.dialog.open(this.articleModel, {
width: '1100px',
disableClose: false,
});
}
closeDialog() {
this.dialogRef.close()
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { CommonComponent } from './common.component';
import { RouterModule, Routes } from '@angular/router';
import { SharedModule } from '../../shared/shared.module';
import { QuillModule } from 'ngx-quill';
export const admin: Routes = [
{
path: 'admin', children: [{
......@@ -21,6 +22,11 @@ export const admin: Routes = [
import('./company-manage/company-manage.component').then((m) => m.CompanyManageComponent),
},
{
path: 'manage-articles',
loadComponent: () =>
import('./article-manage/article-manage.component').then((m) => m.ArticleManageComponent),
},
{
path: 'admin-manage',
loadComponent: () =>
import('./admin-manage/admin-manage.component').then((m) => m.AdminManageComponent),
......@@ -54,7 +60,8 @@ export const admin: Routes = [
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(admin)
RouterModule.forChild(admin),
QuillModule.forRoot(),
],
exports: [RouterModule],
declarations: [CommonComponent]
......
import { TranslateService } from "@ngx-translate/core"
import { BaseModel, dataToArray } from "./base.model"
import { CompanyModel } from "./company.model"
import { environment } from "../../../environments/environment";
export interface ArticleModel {
articleId: string
companyId: CompanyModel[]
title: string
content: string
excerpt: string
category: string
author: string
picture: string
createdDate: string
lastModifiedDate: string
publish: number
viewCount: number
}
export class ArticleModel extends BaseModel implements ArticleModel {
articleId: string
companyId: CompanyModel[]
title: string
content: string
excerpt: string
category: string
author: string
picture: string
createdDate: string
lastModifiedDate: string
publish: number
viewCount: number
constructor(data?: Partial<ArticleModel>, translateService?: TranslateService) {
super(data, translateService)
this.articleId = data?.articleId!
this.companyId = dataToArray(data?.companyId).map((x:CompanyModel) => new CompanyModel(x,translateService))
this.title = data?.title!
this.content = data?.content!
this.excerpt = data?.excerpt!
this.category = data?.category!
this.author = data?.author!
this.picture = data?.picture!
this.createdDate = data?.createdDate!
this.lastModifiedDate = data?.lastModifiedDate!
this.publish = data?.publish!
this.viewCount = data?.viewCount!
}
getPicture(): string {
if (this.picture) {
return environment.baseUrl + "/files/image/" + this.picture
} else {
return ""
}
}
}
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { environment } from "../../../environments/environment";
import { CompanyModelS } from '../models/companys.mode';
import { ArticleModel } from '../models/article.model';
@Injectable({
providedIn: 'root'
})
export class ArticleService {
api = "/article"
urlApi = environment.baseUrl + "/article"
constructor(private http: HttpClient) { }
getById(articleId: string): Observable<ArticleModel> {
return this.http.get<ArticleModel>(this.urlApi + "/" + articleId)
}
getList(): Observable<ArticleModel[]> {
return this.http.get<ArticleModel[]>(this.urlApi + "/lists")
}
getListByCompany(companyId: CompanyModelS[]): Observable<ArticleModel[]> {
return this.http.get<ArticleModel[]>(this.urlApi + "/lists/" + companyId);
}
postArticle(body: ArticleModel): Observable<any> {
return this.http.post(this.urlApi, body)
}
deletearticle(body: ArticleModel) {
const options = {
headers: new HttpHeaders({
"Content-Type": "application/json",
}),
body: body,
};
return this.http.delete(this.urlApi, options)
}
deletearticleById(articleId: string) {
const options = {
headers: new HttpHeaders({
"Content-Type": "application/json",
}),
body: {articleId : articleId},
};
return this.http.delete(this.urlApi, options)
}
}
......@@ -109,6 +109,13 @@ export class NavService implements OnDestroy {
},
{
icon: 'buildings',
path: '/admin/manage-articles',
title: 'จัดการบทความ',
type: 'link',
},
{
icon: 'user-check',
path: '/admin/admin-manage',
title: 'จัดการสิทธิ์ผู้ดูแลระบบ',
......
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