From b531e3a9068d721bc6e4a3020d240ed4bbfd4b9e Mon Sep 17 00:00:00 2001
From: Kritkhanin Anantakul <65160144@go.buu.ac.th>
Date: Mon, 3 Mar 2025 21:46:37 +0700
Subject: [PATCH]  order dialog edit delete btn / split gant file and carlendar

---
 src/components/GanttChart/GanttCalendar.vue |  55 ++
 src/components/GanttChart/GanttChart.vue    | 604 ++++++++++----------
 src/components/GanttChart/OrderDialog.vue   |  35 ++
 src/components/GanttChart/ganttChart.css    | 175 ++++++
 src/views/ProductQueueView.vue              |  26 +-
 5 files changed, 562 insertions(+), 333 deletions(-)
 create mode 100644 src/components/GanttChart/GanttCalendar.vue
 create mode 100644 src/components/GanttChart/OrderDialog.vue
 create mode 100644 src/components/GanttChart/ganttChart.css

diff --git a/src/components/GanttChart/GanttCalendar.vue b/src/components/GanttChart/GanttCalendar.vue
new file mode 100644
index 0000000..376830a
--- /dev/null
+++ b/src/components/GanttChart/GanttCalendar.vue
@@ -0,0 +1,55 @@
+<script setup>
+import { ref, watch } from 'vue';
+
+const props = defineProps({
+  modelValue: {
+    type: String,
+    default: '1/1/2024',
+  },
+});
+const emits = defineEmits(['update:modelValue']);
+
+const selectedDate = ref(props.modelValue);
+
+// เมื่อ selectedDate เปลี่ยน ให้ emit ออกไปเป็น v-model
+watch(selectedDate, (newVal) => {
+  emits('update:modelValue', newVal);
+});
+
+// (ตัวอย่าง) คุณอาจทำปุ่ม Back/Next ให้เปลี่ยนวันที่ได้จริง
+// แต่ตอนนี้เป็นเพียง placeholder
+</script>
+
+<template>
+  <v-col
+  cols="auto"
+  class="d-inline-flex align-center"
+  style="background-color: #7E9CD3; border-radius: 15px; max-width: fit-content; padding: 8px 16px;"
+>
+    <v-btn
+      class="mr-2"
+      style="background-color: #2B2E3F; color: white; border-radius: 10px;"
+      @click="selectedDate.value = '1/1/2024'"
+    >
+      &lt; Back
+    </v-btn>
+    <v-btn
+      style="background-color: white; color: black; min-width: 200px; border-radius: 15px;"
+    >
+      {{ selectedDate }}
+    </v-btn>
+    <v-btn
+      class="ml-2"
+      style="background-color: #2B2E3F; color: white; border-radius: 10px;"
+      @click="selectedDate.value = '1/2/2024'"
+    >
+      Next &gt;
+    </v-btn>
+    <v-btn
+      class="ml-2"
+      style="background-color: white; color: black; border-radius: 10px;"
+    >
+      <v-icon>mdi-dots-horizontal</v-icon>
+    </v-btn>
+  </v-col>
+</template>
diff --git a/src/components/GanttChart/GanttChart.vue b/src/components/GanttChart/GanttChart.vue
index 054f5d9..de84e2a 100644
--- a/src/components/GanttChart/GanttChart.vue
+++ b/src/components/GanttChart/GanttChart.vue
@@ -1,107 +1,216 @@
 <template>
-  <div class="gantt-chart">
-    <!-- Header: Time Scale -->
-    <div class="header">
-      <div class="machine-label"></div>
-      <div class="time-scale">
-        <div v-for="hour in hours" :key="hour" class="time-cell">
-          {{ formatHour(hour) }}
+  <div class="gantt-container">
+    <!-- Calendar: เชื่อมกับ selectedDate -->
+    <GanttCalendar v-model:modelValue="selectedDate" />
+
+    <!-- Gantt Chart UI -->
+    <div class="gantt-chart">
+      <!-- Header: Time Scale -->
+      <div class="header">
+        <div class="machine-label"></div>
+        <div class="time-scale">
+          <div
+            v-for="hour in hours"
+            :key="hour"
+            class="time-cell"
+          >
+            {{ formatHour(hour) }}
+          </div>
         </div>
       </div>
-    </div>
-
-    <!-- Rows: เครื่องจักรแต่ละตัว -->
-    <div class="rows">
-      <div v-for="machine in machines" :key="machine.id" class="row" @dragover.prevent="onDragOver($event)"
-        @drop="onDrop($event, machine.name)">
-        <div class="machine-label">
-          {{ machine.name }}
-        </div>
-        <div class="row-timeline">
-          <!-- เส้นแนวตั้ง (Grid Lines) -->
-          <div v-for="hour in hours" :key="'line-' + hour" class="vertical-line" :style="getLineStyle(hour)"></div>
 
-          <!-- แสดง Order -->
-          <div
-            v-for="order in orders.filter(o => pages.includes(o.page) && o.page === currentPage && o.machine === machine.name)"
-            :key="order.id" class="order" :class="{ 'faded': draggingOrder && draggingOrder.id === order.id }"
-            :style="getOrderStyle(order)">
-            <!-- Handle สำหรับ Resize ด้านซ้าย -->
-            <div class="resize-handle left" @mousedown="onResizeStart($event, order, 'left')"></div>
-
-            <!-- ส่วนกลางของ Order ใช้สำหรับลาก -->
-            <div class="order-content" draggable="true" @dragstart="onDragStart($event, order)"
-              @dragend="onDragEnd($event, order)">
-              {{ order.name }} ({{ order.start }} - {{ order.end }})
+      <!-- Rows: เครื่องจักรแต่ละตัว -->
+      <div class="rows">
+        <div
+          v-for="machine in machines"
+          :key="machine.id"
+          class="row"
+          @dragover.prevent="onDragOver($event)"
+          @drop="onDrop($event, machine.machineID)"
+        >
+          <div class="machine-label">
+            {{ machine.machineID }}
+          </div>
+          <div class="row-timeline">
+            <!-- เส้นแนวตั้ง (Grid Lines) -->
+            <div
+              v-for="hour in hours"
+              :key="'line-' + hour"
+              class="vertical-line"
+              :style="getLineStyle(hour)"
+            ></div>
+
+            <!-- แสดง Order ที่ตรงกับวันที่ (selectedDate), Page, และ Machine -->
+            <div
+              v-for="order in filteredOrders(machine.machineID)"
+              :key="order.queueID"
+              class="order"
+              :class="{ 'faded': draggingOrder && draggingOrder.queueID === order.queueID }"
+              :style="getOrderStyle(order)"
+            >
+              <!-- Handle สำหรับ Resize ด้านซ้าย -->
+              <div
+                class="resize-handle left"
+                @mousedown="onResizeStart($event, order, 'left')"
+              ></div>
+
+              <!-- ส่วนกลางของ Order ใช้สำหรับลาก และเปิด Dialog เมื่อคลิก -->
+              <div
+                class="order-content"
+                draggable="true"
+                @dragstart="onDragStart($event, order)"
+                @dragend="onDragEnd($event, order)"
+                @click.stop="openOrderDialog(order)"
+              >
+                {{ order.orderID }} ({{ getTimeString(order.startTime) }} - {{ getTimeString(order.finishTime) }})
+              </div>
+
+              <!-- Handle สำหรับ Resize ด้านขวา -->
+              <div
+                class="resize-handle right"
+                @mousedown="onResizeStart($event, order, 'right')"
+              ></div>
             </div>
-
-            <!-- Handle สำหรับ Resize ด้านขวา -->
-            <div class="resize-handle right" @mousedown="onResizeStart($event, order, 'right')"></div>
           </div>
         </div>
       </div>
-    </div>
 
-    <!-- Ghost Order ขณะลาก -->
-    <div v-if="ghostOrder" class="drag-ghost" :style="ghostStyle">
-      {{ ghostOrder.name }} ({{ ghostOrder.start }} - {{ ghostOrder.end }})
-    </div>
+      <!-- Ghost Order ขณะลาก -->
+      <div v-if="ghostOrder" class="drag-ghost" :style="ghostStyle">
+        {{ ghostOrder.orderID }} ({{ getTimeString(ghostOrder.startTime) }} - {{ getTimeString(ghostOrder.finishTime) }})
+      </div>
+
+      <v-divider :thickness="7"></v-divider>
+
+      <!-- Pagination -->
+      <div class="pagination">
+        <button
+          v-for="p in pages"
+          :key="p"
+          :class="['page-btn', { active: p === currentPage }]"
+          @click="currentPage = p"
+          @contextmenu.prevent="onPageRightClick(p, $event)"
+        >
+          {{ p }}
+          <button
+            v-if="pageToShowDelete === p"
+            class="delete-btn"
+            @click.stop="deletePage(p)"
+          >
+            Delete
+          </button>
+        </button>
+        <button class="page-btn add-page" @click="addPage">+</button>
+      </div>
 
-    <v-divider :thickness="7"></v-divider>
-
-    <!-- Pagination -->
-    <div class="pagination">
-      <button
-        v-for="p in pages"
-        :key="p"
-        :class="['page-btn', { active: p === currentPage }]"
-        @click="currentPage = p"
-        @contextmenu.prevent="onPageRightClick(p, $event)"
-      >
-        {{ p }}
-        <!-- ปุ่ม Delete จะแสดงเฉพาะเมื่อคลิกขวาที่ปุ่มนั้น -->
-        <button v-if="pageToShowDelete === p" class="delete-btn" @click.stop="deletePage(p)">Delete</button>
-      </button>
-      <!-- ปุ่ม + สำหรับเพิ่มหน้าใหม่ -->
-      <button class="page-btn add-page" @click="addPage">+</button>
+      <!-- Order Dialog -->
+      <OrderDialog
+        v-if="selectedOrder"
+        :order="selectedOrder"
+        @close="closeOrderDialog"
+        @edit="editOrder"
+        @delete="deleteOrder"
+      />
     </div>
   </div>
 </template>
 
 <script>
+import GanttCalendar from './GanttCalendar.vue';
+import OrderDialog from './OrderDialog.vue';
+import './ganttChart.css';
+
 export default {
   name: 'GanttChart',
+  components: {
+    GanttCalendar,
+    OrderDialog,
+  },
   data() {
     return {
-      // เวลางาน
+      // ค่าจาก Calendar
+      selectedDate: '1/1/2024',
+
+      // กำหนดช่วงเวลาใน Gantt
       startTime: '08:00',
       endTime: '17:00',
 
       // รายการเครื่องจักร
       machines: [
-        { id: 1, name: 'MC1' },
-        { id: 2, name: 'MC2' },
-        { id: 3, name: 'MC3' },
-        { id: 4, name: 'MC4' },
-        { id: 5, name: 'MC5' },
+        { id: 1, machineID: 'MC1' },
+        { id: 2, machineID: 'MC2' },
+        { id: 3, machineID: 'MC3' },
+        { id: 4, machineID: 'MC4' },
+        { id: 5, machineID: 'MC5' },
       ],
 
-      // รายการ Order
+      // ข้อมูล Order ตามโครงสร้าง Queue
       orders: [
-        { page: 1, id: 1, name: 'Order 1', start: '13:00', end: '15:00', machine: 'MC1', color: 'blue' },
-        { page: 1, id: 2, name: 'Order 2', start: '09:00', end: '11:00', machine: 'MC2' },
-        { page: 2, id: 3, name: 'Order 3', start: '10:00', end: '12:00', machine: 'MC1' },
-        { page: 2, id: 4, name: 'Order 4', start: '14:00', end: '16:00', machine: 'MC5' },
+        {
+          queueID: 1,
+          machineID: 'MC1',
+          orderID: 1,
+          pageNumber: 1,
+          startTime: '1/1/2024 09:00',
+          finishTime: '1/1/2024 11:00',
+          status: 'Process',
+          bottleSize: '600ml',
+          producedQuantity: 400,
+        },
+        {
+          queueID: 2,
+          machineID: 'MC2',
+          orderID: 2,
+          pageNumber: 1,
+          startTime: '1/1/2024 13:00',
+          finishTime: '1/1/2024 15:00',
+          status: 'Waiting',
+          bottleSize: '500ml',
+          producedQuantity: 200,
+        },
+        {
+          queueID: 3,
+          machineID: 'MC1',
+          orderID: 3,
+          pageNumber: 2,
+          startTime: '1/1/2024 10:00',
+          finishTime: '1/1/2024 12:00',
+          status: 'Process',
+          bottleSize: '700ml',
+          producedQuantity: 350,
+        },
+        {
+          queueID: 4,
+          machineID: 'MC5',
+          orderID: 4,
+          pageNumber: 2,
+          startTime: '1/1/2024 14:00',
+          finishTime: '1/1/2024 16:00',
+          status: 'Process',
+          bottleSize: '600ml',
+          producedQuantity: 500,
+        },
+        {
+          queueID: 5,
+          machineID: 'MC5',
+          orderID: 4,
+          pageNumber: 1,
+          startTime: '2/1/2024 14:00',
+          finishTime: '2/1/2024 16:00',
+          status: 'Process',
+          bottleSize: '600ml',
+          producedQuantity: 500,
+        },
       ],
 
-      // สำหรับการลากและการ Resize
+      // จัดการการลาก, Resize
       draggingOrder: null,
       dragOffset: 0,
       resizingOrder: null,
       resizeDirection: null,
 
-      // Ghost Order (ตัวอย่างที่ขยับตามเม้าส์)
-      ghostOrder: null, 
+      // Ghost Order (ขณะลาก)
+      ghostOrder: null,
       ghostStyle: {
         position: 'fixed',
         top: '0px',
@@ -118,13 +227,14 @@ export default {
         zIndex: 9999,
       },
 
-      // จัดการ Pagination
+      // Pagination
       pages: [1, 2],
       currentPage: 1,
-
-      // สำหรับการแสดงปุ่ม delete เมื่อคลิกขวาที่ page
       pageToShowDelete: null,
-    }
+
+      // Dialog
+      selectedOrder: null,
+    };
   },
   computed: {
     // สร้าง list ของชั่วโมงทั้งหมดจาก startTime ถึง endTime
@@ -132,92 +242,99 @@ export default {
       const startHour = parseInt(this.startTime.split(':')[0]);
       const endHour = parseInt(this.endTime.split(':')[0]);
       return Array.from({ length: endHour - startHour + 1 }, (_, i) => startHour + i);
-    }
+    },
   },
   methods: {
+    // แยก date ส่วนหน้า (1/1/2024) ออกจาก startTime/finishTime
+    getDateString(dateTimeStr) {
+      // สมมติ format = '1/1/2024 09:00'
+      return dateTimeStr.split(' ')[0];
+    },
+    // แยกเฉพาะส่วนเวลา (09:00)
+    getTimeString(dateTimeStr) {
+      return dateTimeStr.split(' ')[1];
+    },
+
+    // ฟิลเตอร์ order ตาม machineID, pageNumber, และ selectedDate
+    filteredOrders(machineID) {
+      return this.orders.filter((o) => {
+        const orderDate = this.getDateString(o.startTime);
+        return (
+          o.machineID === machineID &&
+          o.pageNumber === this.currentPage &&
+          orderDate === this.selectedDate
+        );
+      });
+    },
+
     // แปลงเลขชั่วโมงเป็น "HH:00"
     formatHour(hour) {
       return (hour < 10 ? '0' + hour : hour) + ':00';
     },
 
-    // สไตล์การวาง Order (ตำแหน่ง left, width, และ backgroundColor)
+    // สไตล์ตำแหน่งของ Order
     getOrderStyle(order) {
-      const startDecimal = this.timeToDecimal(order.start);
-      const endDecimal = this.timeToDecimal(order.end);
+      // แยกเวลาเฉพาะส่วน HH:mm
+      const start = this.getTimeString(order.startTime); // ex "09:00"
+      const end = this.getTimeString(order.finishTime);  // ex "11:00"
+
+      const startDecimal = this.timeToDecimal(start);
+      const endDecimal = this.timeToDecimal(end);
       const timelineStart = this.timeToDecimal(this.startTime);
       const timelineEnd = this.timeToDecimal(this.endTime);
 
       const ratioStart = (startDecimal - timelineStart) / (timelineEnd - timelineStart);
       const ratioEnd = (endDecimal - timelineStart) / (timelineEnd - timelineStart);
 
-      const left = ratioStart * 100 + '%';
-      const width = (ratioEnd - ratioStart) * 100 + '%';
-
       return {
-        left,
-        width,
-        backgroundColor: order.color || '#4caf50'
+        left: ratioStart * 100 + '%',
+        width: (ratioEnd - ratioStart) * 100 + '%',
+        backgroundColor: '#4caf50', // สามารถปรับตาม status หรืออื่นๆ ได้
       };
     },
 
-    // สไตล์ของเส้นแนวตั้ง (grid lines) ตามชั่วโมง
+    // สไตล์ของเส้นแนวตั้ง (grid lines)
     getLineStyle(hour) {
-      const startDecimal = this.timeToDecimal(this.startTime);
-      const endDecimal = this.timeToDecimal(this.endTime);
-      const ratio = (hour - startDecimal) / (endDecimal - startDecimal);
+      const timelineStart = this.timeToDecimal(this.startTime);
+      const timelineEnd = this.timeToDecimal(this.endTime);
+      const ratio = (hour - timelineStart) / (timelineEnd - timelineStart);
       return {
-        left: ratio * 100 + '%'
+        left: ratio * 100 + '%',
       };
     },
 
-    // แปลงเวลา "HH:MM" -> เลขทศนิยม (เช่น 9:30 => 9.5)
+    // แปลงเวลา "HH:MM" -> เลขทศนิยม
     timeToDecimal(timeStr) {
       const [hours, minutes] = timeStr.split(':').map(Number);
       return hours + minutes / 60;
     },
-
     // แปลงเลขทศนิยม -> "HH:MM"
     decimalToTime(decimal) {
       const hours = Math.floor(decimal);
       const minutes = Math.round((decimal - hours) * 60);
       return (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes);
     },
-    onDragEndGlobal() {
-      // ลบ Ghost Order ออกจาก UI
-      this.ghostOrder = null;
-      this.ghostStyle.display = 'none';
-      this.draggingOrder = null;
 
-      // เอา event listener ออก (ไม่งั้นมันจะถูกเรียกทุกครั้งที่ drag)
-      document.removeEventListener('dragend', this.onDragEndGlobal);
-    },
-
-    // เริ่มลาก Order (DragStart)
+    // Event ลาก (DragStart)
     onDragStart(event, order) {
       this.draggingOrder = order;
       const rect = event.target.getBoundingClientRect();
-      this.dragOffset = event.target.getBoundingClientRect().width / 2;
-
+      this.dragOffset = rect.width / 2;
       // ปิด preview เริ่มต้นของ HTML5 Drag & Drop
       const emptyImg = document.createElement('img');
       emptyImg.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
       event.dataTransfer.setDragImage(emptyImg, 0, 0);
 
-      // สร้าง Ghost Order
       this.ghostOrder = { ...order };
       this.ghostStyle.display = 'block';
-      this.ghostStyle.backgroundColor = order.color || '#4caf50';
+      this.ghostStyle.backgroundColor = '#4caf50';
 
       document.addEventListener('dragover', this.onDragOverGlobal);
       document.addEventListener('dragend', this.onDragEndGlobal);
     },
-
-    // ขณะลาก (DragOver) ที่ผูกใน template
     onDragOver(event) {
       event.preventDefault();
     },
-
-    // onDragOverGlobal - อัปเดตตำแหน่ง Ghost และเวลา
     onDragOverGlobal(event) {
       event.preventDefault();
       const rowTimeline = document.querySelector('.row-timeline');
@@ -228,34 +345,43 @@ export default {
 
       let ratio = offsetX / timelineWidth;
       ratio = Math.min(Math.max(ratio, 0), 1);
-      
+
       const timelineStart = this.timeToDecimal(this.startTime);
       const timelineEnd = this.timeToDecimal(this.endTime);
-      let newStartDecimal = timelineStart + ratio * (timelineEnd - timelineStart);
 
+      // คำนวณเวลาเริ่มใหม่ (เฉพาะส่วนเวลา)
+      const startDecimal = this.timeToDecimal(this.getTimeString(this.draggingOrder.startTime));
+      const endDecimal = this.timeToDecimal(this.getTimeString(this.draggingOrder.finishTime));
+      const duration = endDecimal - startDecimal;
+
+      let newStartDecimal = timelineStart + ratio * (timelineEnd - timelineStart);
       newStartDecimal = Math.round(newStartDecimal * 2) / 2;
 
-      const duration = this.timeToDecimal(this.draggingOrder.end) - this.timeToDecimal(this.draggingOrder.start);
       let newEndDecimal = newStartDecimal + duration;
       if (newEndDecimal > timelineEnd) {
         newEndDecimal = timelineEnd;
         newStartDecimal = newEndDecimal - duration;
       }
 
-      this.ghostOrder.start = this.decimalToTime(newStartDecimal);
-      this.ghostOrder.end = this.decimalToTime(newEndDecimal);
+      // สร้าง String ใหม่ "วัน/เดือน/ปี เวลา"
+      const datePart = this.getDateString(this.draggingOrder.startTime); // ex "1/1/2024"
+      const newStartStr = datePart + ' ' + this.decimalToTime(newStartDecimal);
+      const newEndStr = datePart + ' ' + this.decimalToTime(newEndDecimal);
+
+      this.ghostOrder.startTime = newStartStr;
+      this.ghostOrder.finishTime = newEndStr;
 
       const snappedRatioStart = (newStartDecimal - timelineStart) / (timelineEnd - timelineStart);
       const snappedLeft = timelineRect.left + snappedRatioStart * timelineWidth;
-
       const snappedRatioEnd = (newEndDecimal - timelineStart) / (timelineEnd - timelineStart);
       const snappedWidth = (snappedRatioEnd - snappedRatioStart) * timelineWidth;
 
+      // หาแถว (machine) ที่ใกล้ที่สุด
       const rows = document.querySelectorAll('.row');
       let closestRow = null;
       let minDistance = Infinity;
 
-      rows.forEach(row => {
+      rows.forEach((row) => {
         const rect = row.getBoundingClientRect();
         const distance = Math.abs(event.clientY - rect.top);
         if (distance < minDistance) {
@@ -265,101 +391,97 @@ export default {
       });
 
       if (closestRow) {
-        this.ghostOrder.machine = closestRow.querySelector('.machine-label').textContent.trim();
+        this.ghostOrder.machineID = closestRow.querySelector('.machine-label').textContent.trim();
         this.ghostStyle.top = closestRow.getBoundingClientRect().top + 'px';
       }
-      
+
       this.ghostStyle.left = snappedLeft + 'px';
       this.ghostStyle.width = snappedWidth + 'px';
     },
-
-    // จบการลาก Order (DragEnd) => คำนวณตำแหน่งใหม่
+    onDragEndGlobal() {
+      this.ghostOrder = null;
+      this.ghostStyle.display = 'none';
+      this.draggingOrder = null;
+      document.removeEventListener('dragend', this.onDragEndGlobal);
+    },
     onDragEnd(event, order) {
       if (!this.ghostOrder) return;
-
-      order.start = this.ghostOrder.start;
-      order.end = this.ghostOrder.end;
-      order.machine = this.ghostOrder.machine;
-
+      order.startTime = this.ghostOrder.startTime;
+      order.finishTime = this.ghostOrder.finishTime;
+      order.machineID = this.ghostOrder.machineID;
       document.removeEventListener('dragover', this.onDragOverGlobal);
       this.ghostOrder = null;
       this.ghostStyle.display = 'none';
       this.draggingOrder = null;
     },
-
-    // เมื่อปล่อย Drag บนเครื่องจักรใหม่ => เปลี่ยน machine ของ Order
     onDrop(event, newMachine) {
       event.preventDefault();
-      
-      if (this.draggingOrder) {
-        this.draggingOrder.start = this.ghostOrder.start;
-        this.draggingOrder.end = this.ghostOrder.end;
-        this.draggingOrder.machine = newMachine;
+      if (this.draggingOrder && this.ghostOrder) {
+        this.draggingOrder.startTime = this.ghostOrder.startTime;
+        this.draggingOrder.finishTime = this.ghostOrder.finishTime;
+        this.draggingOrder.machineID = newMachine;
       }
-
       this.ghostOrder = null;
       this.ghostStyle.display = 'none';
       this.draggingOrder = null;
     },
 
-    // เริ่ม Resize (mousedown ที่ handle)
+    // Resize
     onResizeStart(event, order, direction) {
       event.preventDefault();
       this.resizingOrder = order;
       this.resizeDirection = direction;
-      document.addEventListener("mousemove", this.onResizing);
-      document.addEventListener("mouseup", this.onResizeEnd);
+      document.addEventListener('mousemove', this.onResizing);
+      document.addEventListener('mouseup', this.onResizeEnd);
     },
-
-    // ขณะ Resize
     onResizing(event) {
       if (!this.resizingOrder) return;
-
       const rowTimeline = document.querySelector('.row-timeline');
       if (!rowTimeline) return;
-
       const timelineRect = rowTimeline.getBoundingClientRect();
       const timelineWidth = timelineRect.width;
       const offsetX = event.clientX - timelineRect.left;
+
       let ratio = offsetX / timelineWidth;
       ratio = Math.min(Math.max(ratio, 0), 1);
 
       const timelineStart = this.timeToDecimal(this.startTime);
       const timelineEnd = this.timeToDecimal(this.endTime);
-      let newTimeDecimal = timelineStart + ratio * (timelineEnd - timelineStart);
 
+      const startDec = this.timeToDecimal(this.getTimeString(this.resizingOrder.startTime));
+      const endDec = this.timeToDecimal(this.getTimeString(this.resizingOrder.finishTime));
+
+      let newTimeDecimal = timelineStart + ratio * (timelineEnd - timelineStart);
       newTimeDecimal = Math.round(newTimeDecimal * 2) / 2;
 
+      const datePart = this.getDateString(this.resizingOrder.startTime); // ex: "1/1/2024"
+
       if (this.resizeDirection === 'left') {
-        if (newTimeDecimal >= this.timeToDecimal(this.resizingOrder.end)) return;
-        this.resizingOrder.start = this.decimalToTime(newTimeDecimal);
+        if (newTimeDecimal >= endDec) return;
+        const newStartStr = datePart + ' ' + this.decimalToTime(newTimeDecimal);
+        this.resizingOrder.startTime = newStartStr;
       } else if (this.resizeDirection === 'right') {
-        if (newTimeDecimal <= this.timeToDecimal(this.resizingOrder.start)) return;
-        this.resizingOrder.end = this.decimalToTime(newTimeDecimal);
+        if (newTimeDecimal <= startDec) return;
+        const newEndStr = datePart + ' ' + this.decimalToTime(newTimeDecimal);
+        this.resizingOrder.finishTime = newEndStr;
       }
     },
-
-    // จบการ Resize
     onResizeEnd() {
       this.resizingOrder = null;
       this.resizeDirection = null;
-      document.removeEventListener("mousemove", this.onResizing);
-      document.removeEventListener("mouseup", this.onResizeEnd);
+      document.removeEventListener('mousemove', this.onResizing);
+      document.removeEventListener('mouseup', this.onResizeEnd);
     },
 
-    // เพิ่มหน้าใหม่
+    // Pagination
     addPage() {
       const newPage = this.pages.length + 1;
       this.pages.push(newPage);
     },
-
-    // เมื่อคลิกขวาที่ปุ่ม page
     onPageRightClick(page, event) {
       event.preventDefault();
       this.pageToShowDelete = page;
     },
-
-    // ลบหน้า
     deletePage(page) {
       const index = this.pages.indexOf(page);
       if (index !== -1) {
@@ -370,170 +492,32 @@ export default {
       }
       this.pageToShowDelete = null;
     },
-
-    // ซ่อนปุ่ม delete เมื่อคลิกนอก page-btn
     onDocumentClick(event) {
       if (!event.target.closest('.page-btn')) {
         this.pageToShowDelete = null;
       }
-    }
+    },
+
+    // Dialog
+    openOrderDialog(order) {
+      this.selectedOrder = { ...order };
+    },
+    closeOrderDialog() {
+      this.selectedOrder = null;
+    },
+    editOrder(order) {
+      alert('Edit functionality not implemented yet.\nOrder ID: ' + order.orderID);
+    },
+    deleteOrder(order) {
+      this.orders = this.orders.filter((o) => o.queueID !== order.queueID);
+      this.closeOrderDialog();
+    },
   },
   mounted() {
     document.addEventListener('click', this.onDocumentClick);
   },
   beforeUnmount() {
     document.removeEventListener('click', this.onDocumentClick);
-  }
-}
+  },
+};
 </script>
-
-<style scoped>
-.gantt-chart {
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-}
-
-.header {
-  display: flex;
-  background: #fff;
-}
-
-.machine-label {
-  width: 80px;
-  text-align: center;
-  font-weight: bold;
-  background: #ffffff;
-  line-height: 40px;
-  border-bottom: 1px solid #ffffff;
-}
-
-.time-scale {
-  display: flex;
-  flex: 1;
-}
-
-.time-cell {
-  flex: 1;
-  text-align: center;
-  border-bottom: 1px solid #ddd;
-  font-size: 15px;
-  line-height: 40px;
-  font-weight: bold;
-}
-
-.rows {
-  flex: 1;
-  overflow-y: auto;
-}
-
-.row {
-  display: flex;
-  min-height: 60px;
-  border-bottom: 1px solid #ddd;
-}
-
-.row-timeline {
-  position: relative;
-  flex: 1;
-  overflow: hidden;
-}
-
-.vertical-line {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  width: 1px;
-  background-color: #ddd;
-}
-
-.order {
-  position: absolute;
-  top: 10px;
-  height: 40px;
-  color: #fff;
-  border-radius: 20px;
-  user-select: none;
-  display: flex;
-  align-items: center;
-  z-index: 1;
-}
-
-.order-content {
-  flex: 1;
-  text-align: center;
-  line-height: 40px;
-  cursor: grab;
-  padding: 0 10px;
-}
-
-.resize-handle {
-  width: 5px;
-  height: 100%;
-  cursor: ew-resize;
-  position: absolute;
-}
-
-.resize-handle.left {
-  left: 0;
-  border-top-left-radius: 10px;
-  border-bottom-left-radius: 10px;
-}
-
-.resize-handle.right {
-  right: 0;
-  border-top-right-radius: 10px;
-  border-bottom-right-radius: 10px;
-}
-
-.order.faded {
-  opacity: 0.3;
-}
-
-.drag-ghost {
-  box-sizing: border-box;
-  text-align: center;
-  pointer-events: none;
-}
-
-.pagination {
-  display: flex;
-  justify-content: flex-start;
-  align-items: center;
-  gap: 5px;
-  width: 100%;
-  margin-top: 10px;
-}
-
-.page-btn {
-  background: #ffffff;
-  border: 1px solid #ffffff;
-  padding: 5px 10px;
-  cursor: pointer;
-  font-size: 14px;
-  position: relative;
-}
-
-.page-btn.active {
-  background: #007bff;
-  color: #ffffff;
-}
-
-.page-btn.add-page {
-  font-weight: bold;
-  background: #ffffff;
-}
-
-/* สไตล์สำหรับปุ่ม Delete ที่แสดงเมื่อคลิกขวา */
-.delete-btn {
-  margin-left: 5px;
-  background-color: red;
-  color: #fff;
-  border: none;
-  padding: 2px 5px;
-  cursor: pointer;
-  border-radius: 3px;
-  font-size: 12px;
-}
-</style>
diff --git a/src/components/GanttChart/OrderDialog.vue b/src/components/GanttChart/OrderDialog.vue
new file mode 100644
index 0000000..81adfb3
--- /dev/null
+++ b/src/components/GanttChart/OrderDialog.vue
@@ -0,0 +1,35 @@
+<template>
+    <div class="order-dialog-overlay">
+      <div class="order-dialog">
+        <h3>Order Details</h3>
+        <p><strong>QueueID:</strong> {{ order.queueID }}</p>
+        <p><strong>Machine:</strong> {{ order.machineID }}</p>
+        <p><strong>OrderID:</strong> {{ order.orderID }}</p>
+        <p><strong>PageNumber:</strong> {{ order.pageNumber }}</p>
+        <p><strong>Start:</strong> {{ order.startTime }}</p>
+        <p><strong>Finish:</strong> {{ order.finishTime }}</p>
+        <p><strong>Status:</strong> {{ order.status }}</p>
+        <p><strong>Bottle Size:</strong> {{ order.bottleSize }}</p>
+        <p><strong>Produced:</strong> {{ order.producedQuantity }}</p>
+  
+        <div class="dialog-buttons">
+          <button @click="$emit('edit', order)">Edit</button>
+          <button @click="$emit('delete', order)">Delete</button>
+          <button @click="$emit('close')">Close</button>
+        </div>
+      </div>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    name: 'OrderDialog',
+    props: {
+      order: {
+        type: Object,
+        required: true,
+      },
+    },
+  };
+  </script>
+  
\ No newline at end of file
diff --git a/src/components/GanttChart/ganttChart.css b/src/components/GanttChart/ganttChart.css
new file mode 100644
index 0000000..b290d1e
--- /dev/null
+++ b/src/components/GanttChart/ganttChart.css
@@ -0,0 +1,175 @@
+.gantt-chart {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+  }
+  
+  .header {
+    display: flex;
+    background: #fff;
+  }
+  
+  .machine-label {
+    width: 80px;
+    text-align: center;
+    font-weight: bold;
+    background: #ffffff;
+    line-height: 40px;
+    border-bottom: 1px solid #ffffff;
+  }
+  
+  .time-scale {
+    display: flex;
+    flex: 1;
+  }
+  
+  .time-cell {
+    flex: 1;
+    text-align: center;
+    border-bottom: 1px solid #ddd;
+    font-size: 15px;
+    line-height: 40px;
+    font-weight: bold;
+  }
+  
+  .rows {
+    flex: 1;
+    overflow-y: auto;
+  }
+  
+  .row {
+    display: flex;
+    min-height: 60px;
+    border-bottom: 1px solid #ddd;
+  }
+  
+  .row-timeline {
+    position: relative;
+    flex: 1;
+    overflow: hidden;
+  }
+  
+  .vertical-line {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    width: 1px;
+    background-color: #ddd;
+  }
+  
+  .order {
+    position: absolute;
+    top: 10px;
+    height: 40px;
+    color: #fff;
+    border-radius: 20px;
+    user-select: none;
+    display: flex;
+    align-items: center;
+    z-index: 1;
+  }
+  
+  .order-content {
+    flex: 1;
+    text-align: center;
+    line-height: 40px;
+    cursor: grab;
+    padding: 0 10px;
+  }
+  
+  .resize-handle {
+    width: 5px;
+    height: 100%;
+    cursor: ew-resize;
+    position: absolute;
+  }
+  
+  .resize-handle.left {
+    left: 0;
+    border-top-left-radius: 10px;
+    border-bottom-left-radius: 10px;
+  }
+  
+  .resize-handle.right {
+    right: 0;
+    border-top-right-radius: 10px;
+    border-bottom-right-radius: 10px;
+  }
+  
+  .order.faded {
+    opacity: 0.3;
+  }
+  
+  .drag-ghost {
+    box-sizing: border-box;
+    text-align: center;
+    pointer-events: none;
+  }
+  
+  .pagination {
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+    gap: 5px;
+    width: 100%;
+    margin-top: 10px;
+  }
+  
+  .page-btn {
+    background: #ffffff;
+    border: 1px solid #ffffff;
+    padding: 5px 10px;
+    cursor: pointer;
+    font-size: 14px;
+    position: relative;
+  }
+  
+  .page-btn.active {
+    background: #007bff;
+    color: #ffffff;
+  }
+  
+  .page-btn.add-page {
+    font-weight: bold;
+    background: #ffffff;
+  }
+  
+  /* สไตล์สำหรับปุ่ม Delete ที่แสดงเมื่อคลิกขวา */
+  .delete-btn {
+    margin-left: 5px;
+    background-color: red;
+    color: #fff;
+    border: none;
+    padding: 2px 5px;
+    cursor: pointer;
+    border-radius: 3px;
+    font-size: 12px;
+  }
+  
+  /* สไตล์สำหรับ Order Dialog */
+  .order-dialog-overlay {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0, 0, 0, 0.5);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    z-index: 10000;
+  }
+  
+  .order-dialog {
+    background: #fff;
+    padding: 20px;
+    border-radius: 8px;
+    width: 300px;
+    text-align: center;
+  }
+  
+  .dialog-buttons button {
+    margin: 5px;
+  }
+  
\ No newline at end of file
diff --git a/src/views/ProductQueueView.vue b/src/views/ProductQueueView.vue
index 1d818e7..df11423 100644
--- a/src/views/ProductQueueView.vue
+++ b/src/views/ProductQueueView.vue
@@ -7,7 +7,8 @@ const selectedDate = ref('1/1/2024')
 const employees = Array.from({ length: 10 }, (_, i) => `EM${i + 1}`)
 const orders = ref([
   { id: 1, name: 'ORDER1' },
-  { id: 2, name: 'ORDER2' }
+  { id: 2, name: 'ORDER2' },
+  { id: 3, name: 'ORDER3' }
 ])
 
 // Drag and drop functionality
@@ -43,28 +44,7 @@ const handleDrop = (targetOrder) => {
   <v-container class="pa-0">
     <!-- Gantt chart -->
     <v-sheet class="pa-1 mb-3"
-      style="border-radius: 15px; max-width: 98%; margin-left: auto; margin-right: auto; min-height: 500px;">
-
-      <!-- Timeline -->
-      <v-sheet class="pa-3 mb-3">
-        <v-col cols="auto" class="d-flex align-center">
-          <v-col cols="auto" class="d-flex align-center" style="background-color: #7E9CD3; border-radius: 15px; ">
-            <v-btn class="mr-2" style="background-color: #2B2E3F; color: white;  border-radius: 10px;">&lt; Back</v-btn>
-            <v-btn style="background-color: white; color: black; min-width: 200px; border-radius: 15px;">{{ selectedDate
-            }}</v-btn>
-            <v-btn class="ml-2" style="background-color: #2B2E3F; color: white; border-radius: 10px;">Next &gt;</v-btn>
-            <v-btn class="ml-2"
-              style="background-color: white; color: black; border-radius: 10px;"><v-icon>mdi-dots-horizontal</v-icon></v-btn>
-          </v-col>
-          <v-btn class="ml-auto"
-            style="background-color: #0077D8; font-weight: bold; color: white; border-radius: 12px; padding: 28px; display: flex; align-items: center; justify-content: center; font-size: 18px;">
-            Make a queue
-          </v-btn>
-
-        </v-col>
-        <v-row>
-        </v-row>
-      </v-sheet>
+      style="border-radius: 15px; max-width: 98%; margin-left: auto; margin-right: auto; min-height: 460px;">
       <!-- Gantt Chart -->
       <GanttChart />
     </v-sheet>
-- 
GitLab