diff --git a/src/controllers/IssuesController.ts b/src/controllers/IssuesController.ts new file mode 100644 index 00000000..7514d1b9 --- /dev/null +++ b/src/controllers/IssuesController.ts @@ -0,0 +1,60 @@ +import { + Controller, + Get, + Post, + Put, + Delete, + Route, + Security, + Tags, + Body, + Path, + Request, + Response, +} from "tsoa"; +import HttpStatusCode from "../interfaces/http-status"; +import { AppDataSource } from "../database/data-source"; +import { Issues, CreateIssueRequest, UpdateIssueRequest } from "../entities/Issues"; +import HttpSuccess from "../interfaces/http-success"; + +@Route("api/v1/org/issues") +@Tags("issues") +@Security("bearerAuth") +@Response( + HttpStatusCode.INTERNAL_SERVER_ERROR, + "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง", +) +export class IssuesController extends Controller { + private issuesRepository = AppDataSource.getRepository(Issues); + + @Get("lists") + async getIssues() { + const issues = await this.issuesRepository.find({ + order: { + createdAt: "DESC", + }, + }); + return new HttpSuccess(issues); + } + + @Post("") + async createIssue(@Body() requestBody: CreateIssueRequest) { + let issue = this.issuesRepository.create(requestBody); + + await this.issuesRepository.save(issue); + + return new HttpSuccess(issue); + } + + @Put("{id}") + async updateIssue(@Path("id") id: string, @Body() requestBody: Partial) { + let issue = await this.issuesRepository.findOneBy({ id }); + if (!issue) { + this.setStatus(HttpStatusCode.NOT_FOUND); + return { message: "ไม่พบข้อมูลที่ต้องการแก้ไข" }; + } + Object.assign(issue, requestBody); + await this.issuesRepository.save(issue); + return new HttpSuccess(issue); + } +} diff --git a/src/entities/Issues.ts b/src/entities/Issues.ts new file mode 100644 index 00000000..8bf3143e --- /dev/null +++ b/src/entities/Issues.ts @@ -0,0 +1,93 @@ +import { Entity, Column, BeforeInsert } from "typeorm"; +import { AppDataSource } from "../database/data-source"; +import { EntityBase } from "./base/Base"; + +@Entity("issues") +export class Issues extends EntityBase { + @Column({ + type: "varchar", + nullable: false, + length: 20, + comment: "รหัส issue เช่น ISS20260127001", + }) + codeIssue: string; + + @Column({ type: "varchar", nullable: false, length: 255, comment: "หัวข้อ" }) + title: string; + + @Column({ type: "text", nullable: false, comment: "รายละเอียดของปัญหา" }) + description: string | null; + + @Column({ type: "varchar", nullable: false, length: 50, comment: "ระบบ" }) + system: string; + + @Column({ type: "varchar", nullable: false, length: 255, comment: "เมนู" }) + menu: string | null; + + @Column({ type: "varchar", nullable: true, length: 500, comment: "สังกัด" }) + org: string | null; + + @Column({ type: "text", nullable: true, comment: "หมายเหตุ" }) + remark: string | null; + + @Column({ + type: "enum", + enum: ["NEW", "IN_PROGRESS", "RESOLVED", "CLOSED"], + default: "NEW", + comment: "สถานะการแก้ไขปัญหา", + }) + status: "NEW" | "IN_PROGRESS" | "RESOLVED" | "CLOSED"; + + @BeforeInsert() + async generateCodeIssue() { + const today = new Date(); + const dateStr = today.toISOString().slice(0, 10).replace(/-/g, ""); + const prefix = `ISS${dateStr}`; + + const repository = AppDataSource.getRepository(Issues); + const lastIssue = await repository + .createQueryBuilder("issue") + .where("issue.codeIssue LIKE :prefix", { prefix: `${prefix}%` }) + .orderBy("issue.codeIssue", "DESC") + .getOne(); + + let runningNumber = 1; + if (lastIssue) { + const lastNumber = parseInt(lastIssue.codeIssue.slice(-3), 10); + runningNumber = lastNumber + 1; + } + + this.codeIssue = `${prefix}${runningNumber.toString().padStart(3, "0")}`; + } +} + +// Interface สำหรับ TSOA Response +export interface IssueResponse { + id: string; + codeIssue: string; + title: string; + description: string | null; + system: string; + menu: string | null; + org: string | null; + remark: string | null; + status: "NEW" | "IN_PROGRESS" | "RESOLVED" | "CLOSED"; + createdAt: Date; + lastUpdatedAt: Date; + createdFullName: string; + lastUpdateFullName: string; +} + +export interface CreateIssueRequest { + title: string; + description?: string; + system: string; + status?: "NEW" | "IN_PROGRESS" | "RESOLVED" | "CLOSED"; + menu?: string; + org?: string; +} + +export interface UpdateIssueRequest { + status?: "NEW" | "IN_PROGRESS" | "RESOLVED" | "CLOSED"; + remark?: string; +} diff --git a/src/migration/1769509622176-create_table_issues.ts b/src/migration/1769509622176-create_table_issues.ts new file mode 100644 index 00000000..493ab458 --- /dev/null +++ b/src/migration/1769509622176-create_table_issues.ts @@ -0,0 +1,33 @@ +import { MigrationInterface, QueryRunner, Table } from "typeorm"; + +export class CreateTableIssues1769509622176 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable(new Table({ + name: "issues", + columns: [ + { name: "id", type: "char", length: "36", isPrimary: true, isGenerated: true, generationStrategy: "uuid" }, + { name: "codeIssue", type: "varchar", length: "20", isNullable: false, comment: "รหัส issue เช่น ISS20260127001" }, + { name: "title", type: "varchar", length: "255", isNullable: false, comment: "หัวข้อ" }, + { name: "description", type: "text", isNullable: false, comment: "รายละเอียดของปัญหา" }, + { name: "system", type: "varchar", length: "50", isNullable: false, comment: "ระบบ" }, + { name: "menu", type: "varchar", length: "255", isNullable: true, comment: "เมนู" }, + { name: "org", type: "varchar", length: "500", isNullable: true, comment: "สังกัด" }, + { name: "remark", type: "text", isNullable: true, comment: "หมายเหตุ" }, + { name: "status", type: "enum", enum: ["NEW", "IN_PROGRESS", "RESOLVED", "CLOSED"], default: "'NEW'", comment: "สถานะการแก้ไขปัญหา" }, + { name: "createdUserId", type: "char", length: "40", isNullable: false, default: "'00000000-0000-0000-0000-000000000000'", comment: "User Id ที่สร้างข้อมูล" }, + { name: "createdFullName", type: "varchar", length: "200", isNullable: false, default: "'System Administrator'", comment: "ชื่อ User ที่สร้างข้อมูล" }, + { name: "createdAt", type: "timestamp", default: "CURRENT_TIMESTAMP", comment: "สร้างข้อมูลเมื่อ" }, + { name: "lastUpdateUserId", type: "char", length: "40", isNullable: false, default: "'00000000-0000-0000-0000-000000000000'", comment: "User Id ที่แก้ไขข้อมูล" }, + { name: "lastUpdateFullName", type: "varchar", length: "200", isNullable: false, default: "'System Administrator'", comment: "ชื่อ User ที่แก้ไขข้อมูลล่าสุด" }, + { name: "lastUpdatedAt", type: "timestamp", default: "CURRENT_TIMESTAMP", comment: "แก้ไขข้อมูลล่าสุดเมื่อ" }, + + ], + }), true); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable("issues"); + } + +}