193 lines
10 KiB
Plaintext
193 lines
10 KiB
Plaintext
## Workflow ระดับ Project (correspondence_routing_steps, technical_doc_workflows): คือ "การเดินทาง" ของเอกสาร ระหว่างองค์กร (เช่น จากผู้รับเหมา -> ไปยังที่ปรึกษา -> ไปยังเจ้าของโครงการ)
|
|
|
|
## Workflow ระดับ Organization (Circulation): คือ "การแจกจ่าย" เอกสาร ภายในองค์กรของคุณเอง หลังจากที่คุณได้รับเอกสารนั้นมาแล้ว (เช่น เอกสารมาถึง Document Control แล้วต้องส่งต่อให้ใครบ้างในบริษัท)
|
|
|
|
circulation_templates: ตารางหลักสำหรับเก็บชื่อแม่แบบ
|
|
circulation_template_assignees: ตารางสำหรับเก็บ "รายชื่อผู้รับผิดชอบ" ที่ถูกกำหนดไว้ในแต่ละแม่แบบ
|
|
|
|
Workflow การทำงานใน Frontend
|
|
1. หน้า Admin Panel: จะต้องมีเมนูใหม่สำหรับให้ Admin หรือผู้มีสิทธิ์ เข้าไป สร้าง/แก้ไข/ลบ แม่แบบใบเวียน (circulation_templates) สำหรับองค์กรของตนเองได้
|
|
|
|
2. หน้าที่สร้างใบเวียน (Create Circulation Dialog):
|
|
* ที่ด้านบนสุดของฟอร์ม จะมี Dropdown ใหม่ ปรากฏขึ้นมา เขียนว่า "ใช้แม่แบบ (Use Template)"
|
|
* ใน Dropdown นี้ จะแสดงรายชื่อแม่แบบทั้งหมดที่องค์กรนั้นๆ สร้างไว้
|
|
* เมื่อผู้ใช้เลือกแม่แบบ:
|
|
** ระบบจะยิง API ไปดึงรายชื่อผู้รับผิดชอบจากตาราง circulation_template_assignees
|
|
** จากนั้น JavaScript จะทำการเติมข้อมูล (Auto-populate) ลงในช่อง "Main", "Action", และ "Information" ให้โดยอัตโนมัติ
|
|
* ผู้ใช้ยังสามารถ แก้ไข/เพิ่มเติม/ลบ รายชื่อผู้รับผิดชอบได้ตามต้องการ ก่อนที่จะกดสร้างใบเวียนจริง
|
|
|
|
|
|
การจัดการข้อมูล JSON จะเกิดขึ้นใน 3 ส่วนหลักๆ คือ Backend, Frontend, และ Database ครับ
|
|
|
|
## 1. การจัดการในฝั่ง Backend (NestJS)
|
|
นี่คือส่วนที่ทำหน้าที่หลักในการสร้างและอ่านข้อมูล JSON อย่างเป็นระบบและปลอดภัย
|
|
|
|
1.1 การแก้ไข Entity
|
|
เราจะแก้ไข Correspondence entity โดยเพิ่มคอลัมน์ details เข้าไป และลบ Entity ย่อยๆ ที่ไม่ใช้ออก
|
|
|
|
src/correspondences/entities/correspondence.entity.ts
|
|
@Entity('correspondences')
|
|
export class Correspondence {
|
|
// ... (คอลัมน์เดิมทั้งหมด: id, document_number, title, etc.)
|
|
|
|
@Column({
|
|
type: 'json', // ◀️ กำหนดประเภทข้อมูลเป็น JSON
|
|
nullable: true,
|
|
comment: 'เก็บข้อมูลเฉพาะของเอกสารแต่ละประเภทในรูปแบบ JSON'
|
|
})
|
|
details: any; // ◀️ ใช้ type 'any' หรือสร้าง Interface/Type ที่ซับซ้อนขึ้น
|
|
}
|
|
|
|
1.2 การสร้าง DTOs สำหรับแต่ละประเภทเอกสาร
|
|
เพื่อรักษาความถูกต้องของข้อมูล (Validation) เราจะสร้าง DTO แยกสำหรับเอกสารแต่ละประเภท
|
|
|
|
ตัวอย่าง src/correspondences/dto/create-letter.dto.ts:
|
|
|
|
TypeScript
|
|
|
|
import { ApiProperty } from '@nestjs/swagger';
|
|
import { IsNotEmpty, IsString } from 'class-validator';
|
|
|
|
// DTO สำหรับข้อมูลใน details ของ Letter
|
|
class LetterDetailsDto {
|
|
@ApiProperty()
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
attention_to: string;
|
|
|
|
@ApiProperty()
|
|
@IsString()
|
|
@IsNotEmpty()
|
|
signatory_name: string;
|
|
}
|
|
|
|
// DTO หลักสำหรับสร้าง Letter
|
|
export class CreateLetterDto {
|
|
@ApiProperty({ description: "ข้อมูลพื้นฐานของเอกสาร" })
|
|
@ValidateNested() // ◀️ บอกให้ class-validator ตรวจสอบ object ข้างในด้วย
|
|
@Type(() => CreateCorrespondenceDto) // ◀️ ใช้ DTO พื้นฐานร่วมกัน
|
|
base_data: CreateCorrespondenceDto;
|
|
|
|
@ApiProperty({ description: "ข้อมูลเฉพาะของ Letter" })
|
|
@ValidateNested()
|
|
@Type(() => LetterDetailsDto)
|
|
details: LetterDetailsDto;
|
|
}
|
|
|
|
1.3 การสร้าง API Endpoint และ Logic ใน Service
|
|
เราจะสร้าง Endpoint แยกสำหรับสร้างเอกสารแต่ละประเภทเพื่อความชัดเจน
|
|
|
|
ใน CorrespondencesController:
|
|
|
|
TypeScript
|
|
|
|
@Post('letter')
|
|
@ApiOperation({ summary: 'Create a new Letter' })
|
|
createLetter(@Body() createLetterDto: CreateLetterDto, @Req() req: Request) {
|
|
const user = req.user as any;
|
|
return this.correspondencesService.createTypedCorrespondence(
|
|
createLetterDto.base_data,
|
|
createLetterDto.details,
|
|
user
|
|
);
|
|
}
|
|
ใน CorrespondencesService:
|
|
|
|
TypeScript
|
|
|
|
async createTypedCorrespondence(baseData: CreateCorrespondenceDto, details: any, user: User): Promise<Correspondence> {
|
|
// ... (โค้ดตรวจสอบสิทธิ์เหมือนเดิม)
|
|
|
|
const newCorrespondence = this.correspondenceRepository.create({
|
|
...baseData, // ข้อมูลพื้นฐาน (เลขที่เอกสาร, ชื่อเรื่อง, etc.)
|
|
details: details, // ◀️ นำ object ของ details มาใส่ในคอลัมน์ JSON โดยตรง
|
|
created_by_user_id: user.user_id,
|
|
originator_org_id: user.org_id,
|
|
status_id: 1, // 'Draft'
|
|
});
|
|
|
|
return this.correspondenceRepository.save(newCorrespondence);
|
|
}
|
|
## 2. การจัดการในฝั่ง Frontend (Next.js / React)
|
|
Frontend จะทำหน้าที่แสดงฟอร์มที่ถูกต้องตามประเภทเอกสาร และส่งข้อมูลในรูปแบบที่ Backend ต้องการ
|
|
|
|
2.1 การแสดงฟอร์มแบบไดนามิก (Dynamic Forms)
|
|
ในหน้า "Create Correspondence" เมื่อผู้ใช้เลือกประเภทเอกสารจาก Dropdown เราจะใช้ State เพื่อแสดงฟอร์มที่ถูกต้อง
|
|
|
|
TypeScript
|
|
|
|
const [docType, setDocType] = useState('LETTER');
|
|
|
|
// ...
|
|
|
|
const renderDetailFields = () => {
|
|
switch (docType) {
|
|
case 'LETTER':
|
|
return (
|
|
<>
|
|
{/* ฟิลด์สำหรับ Attention To, Signatory */}
|
|
</>
|
|
);
|
|
case 'RFI':
|
|
return (
|
|
<>
|
|
{/* ฟิลด์สำหรับ Question, Required By Date */}
|
|
</>
|
|
);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return (
|
|
<form>
|
|
{/* ฟิลด์พื้นฐาน (Document Number, Title) */}
|
|
{/* Dropdown เลือกประเภทเอกสาร */}
|
|
{renderDetailFields()} {/* ◀️ แสดงฟิลด์เฉพาะทางที่นี่ */}
|
|
</form>
|
|
);
|
|
2.2 การส่งข้อมูล
|
|
เมื่อผู้ใช้กด Submit เราจะรวบรวมข้อมูลจากฟอร์มให้เป็นโครงสร้าง JSON ที่ Backend ต้องการ
|
|
|
|
JavaScript
|
|
|
|
const handleSubmit = () => {
|
|
// รวบรวมข้อมูลพื้นฐาน
|
|
const base_data = {
|
|
document_number: '...',
|
|
title: '...',
|
|
// ...
|
|
};
|
|
|
|
// รวบรวมข้อมูลเฉพาะทาง
|
|
const details = {
|
|
attention_to: '...',
|
|
signatory_name: '...',
|
|
};
|
|
|
|
// ส่งข้อมูลไปที่ API Endpoint ที่ถูกต้อง
|
|
fetch('/api/correspondences/letter', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ base_data, details }),
|
|
});
|
|
}
|
|
## 3. การจัดการในระดับฐานข้อมูล (MariaDB)
|
|
แม้ว่าเราจะไม่ค่อยได้ Query ข้อมูล JSON โดยตรงผ่าน SQL บ่อยนัก แต่ก็สามารถทำได้เมื่อจำเป็น (เช่น สำหรับการทำรายงานที่ซับซ้อน)
|
|
|
|
ตัวอย่าง: ค้นหาเอกสาร Letter ทั้งหมดที่ส่งถึง "Mr. John Doe"
|
|
|
|
SQL
|
|
|
|
SELECT
|
|
corr_id,
|
|
document_number,
|
|
details
|
|
FROM
|
|
correspondences
|
|
WHERE
|
|
type_id = (SELECT type_id FROM correspondence_types WHERE type_code = 'LETTER') -- กรองเฉพาะ Letter
|
|
AND JSON_VALUE(details, '$.attention_to') = 'Mr. John Doe'; -- ◀️ ค้นหาค่าใน JSON
|
|
การจัดการข้อมูลด้วยวิธีนี้จะทำให้ระบบของคุณมีความ
|
|
|
|
|