Skip to main content

หน้าแดชบอร์ดและการวิเคราะห์ข้อมูล (Dashboard)

ภาพรวมระบบ (Dashboard)

หน้าจอ Dashboard จริง

หน้า Dashboard คือหน้าแรกหลังเข้าสู่ระบบของฝั่ง Admin และเป็นจุดรวมข้อมูลสรุปจาก endpoint เดียว คือ GET /dashboard/

การเข้าถึงหน้า Dashboard​

  • route ที่ใช้จริงคือ / และ /home
  • route นี้อยู่ใน MainRoutes
  • หน้าใช้ MainCard permission={Permission.DASHBOARD_VIEW}
  • filter ด้านบนถูกครอบด้วย Authorize permission={Permission.DASHBOARD_VIEW}

แหล่งข้อมูลของหน้า​

  • หน้าเรียก useDashboardSummaryQuery
  • hook นี้เรียก GetDashBoardSummary(params)
  • service layer ยิง GET /dashboard/
  • parameter ที่ส่งจริงมี 2 ค่า
    • workAreaId
    • monthYear

ส่วนกรองข้อมูล (Filter)​

ตัวกรองด้านบนของหน้าถูกส่งเข้า query โดยตรง

  • พื้นที่ จะ map ไปเป็น workAreaId
  • เดือน/ปี จะ map ไปเป็น monthYear
  • ถ้าไม่เลือกค่าใหม่ ระบบจะใช้เดือนปัจจุบันจาก dayjs().format('YYYY-MM')
  • แม้หน้า UI ส่ง filter ทั้ง 2 ค่าไปทุกครั้ง แต่ไม่ใช่ทุก widget จะใช้ filter ทั้งคู่จาก backend

การ์ดสถิติด้านบน (Stat Cards)​

สี่การ์ดแรกของหน้า dashboard ใช้ field เหล่านี้จาก DashBoardSummary

การ์ดfield ที่ใช้
ลูกค้าcustomerCount
รถบริษัทcompanyVehicleCount
รถร่วมpartnerVehicleCount
ผู้ใช้งานuserCount

Widget กลุ่มงานปฏิบัติการ​

รอบรถวิ่งวันนี้​

  • ใช้ todayTripRecord.dayPercentage
  • ใช้ todayTripRecord.nightPercentage
  • หน้า UI แสดงเป็น progress 2 ช่วง
    • 06:00 - 17:59
    • 18:00 - 05:59

จำนวนเที่ยวรถรายสัปดาห์​

  • ใช้ weekTripRecord
  • แต่ละแท่งกราฟใช้ค่า count
  • backend จัดข้อมูลตามสัปดาห์ปฏิทิน จ. - อา. ของวันที่ปัจจุบัน
  • หน้า UI แสดง label ตาม day ที่ service ส่งมา เช่น จ., อ., พ.
  • widget นี้ใช้ workAreaId ได้ แต่ไม่ใช้ monthYear
  • backend จะใช้ driver.workAreaId ก่อน ถ้าไม่มีค่อย fallback ไป vehicle.workAreaId

จำนวนเที่ยวสูงสุด​

  • ใช้ driverTripCount
  • backend นับเฉพาะเที่ยวที่ isApproved = true
  • หน้า UI จะกรองคนที่มี _count.tripRecordVehicles > 0
  • จากนั้น sort จากมากไปน้อยก่อนแสดงผล
  • ถ้ามีรถผูกกับนักขับ จะแสดง vehicleCode ของคันแรก

จำนวนรถบริการ​

  • ใช้ vehicleTypeCount
  • หน้า UI จะกรองเฉพาะประเภทรถที่มีจำนวนรถมากกว่า 0
  • แล้วคำนวณ totalServiceVehicleCount เพื่อแสดงยอดรวมของ widget

Widget กลุ่มรายได้​

รายได้นักขับ​

  • ใช้ driverIncomeRevenuePerMonth
  • แกน X แสดง billingMonth
  • แกน Y แสดง amount
  • backend สรุปย้อนหลัง 3 เดือน โดยยึดเดือนที่เลือกและย้อนหลังอีก 2 เดือน
  • widget นี้ใช้ทั้ง monthYear และ workAreaId

รายได้วางบิล​

  • ใช้ mainBillingRevenuePerMonth
  • หน้า UI แปลงค่าก่อน plot เป็น Number((total * 0.99).toFixed(2))
  • แต่ค่า max ของแกน Y ยังอ้างจาก total เดิมของ backend
  • backend สรุปย้อนหลัง 3 เดือน โดยยึดเดือนที่เลือกและย้อนหลังอีก 2 เดือน
  • widget นี้ใช้ทั้ง monthYear และ workAreaId

ยอดใบวางบิลลูกค้า​

  • ใช้ mainBilling
  • ยอดรวมด้านบนของ widget มาจาก mainBilling.reduce((acc, v) => acc + v.totalAmount, 0)
  • รายการย่อยใช้ customerName และ totalAmount

รายได้รถร่วม​

  • ใช้ partnerInvoiceRevenuePerMonth
  • กราฟ plot ค่า total ตรงจาก backend
  • backend สรุปย้อนหลัง 3 เดือน โดยยึดเดือนที่เลือกและย้อนหลังอีก 2 เดือน
  • widget นี้ใช้ทั้ง monthYear และ workAreaId

ยอดใบแจ้งหนี้รถร่วม​

  • ใช้ partnerInvoice
  • ยอดรวมของ widget มาจาก partnerInvoice.reduce((acc, v) => acc + v.totalAmount, 0)
  • รายการย่อยใช้ partnerName และ totalAmount

Widget กลุ่ม KPI และข้อมูลสนับสนุน​

กราฟเปรียบเทียบค่าดาวแดง (X-Ratio)​

  • ใช้ vehicleTypeRedstartXRatio
  • หน้า UI จะกรองเฉพาะรายการที่ vehicleCount > 0
  • pie chart คำนวณ 2 ค่า
    • สัดส่วน ดาวแดง
    • สัดส่วน ปกติ
  • backend ใช้ข้อมูลเติมน้ำมันในเดือนที่เลือกจาก EnergyLog
  • widget นี้ใช้ทั้ง monthYear และ workAreaId
  • ดาวแดง หมายถึงรายการที่ค่า xRatio หลุดช่วง avgXRatio ± redStarThreshold ของประเภทรถนั้น

กราฟแสดงค่า X-Ratio​

  • ใช้ monthlyVehicleTypeXRatio
  • หน้า UI ใช้ LineGraph
  • แกน X แสดง vehicleTypeName
  • แกน Y แสดง avgXRatio
  • backend ใช้ข้อมูลเติมน้ำมันในเดือนที่เลือกจาก EnergyLog
  • widget นี้ใช้ทั้ง monthYear และ workAreaId
  • avgXRatio คือค่าเฉลี่ยของ xRatio แยกตามประเภทรถ
  • xRatio คำนวณจาก (เลขไมล์ปัจจุบัน - เลขไมล์ครั้งก่อนหน้า) / ปริมาณน้ำมัน

ราคาน้ำมัน​

  • ใช้ fuelPrices
  • รายการตัวแรกถูกแสดงเป็นราคา วันนี้
  • รายการถัดไปใช้เป็นประวัติย้อนหลังในตาราง
  • footer ระบุว่าอ้างอิงราคาตามประกาศ PTTOR
  • widget นี้ไม่ใช้ monthYear และไม่ใช้ workAreaId

เงื่อนไขการกรองของกราฟบนหน้า Dashboard​

กราฟ / Widgetfield ที่ใช้เงื่อนไขเวลาเงื่อนไขพื้นที่หมายเหตุ
รอบรถวิ่งวันนี้todayTripRecord.dayPercentage, todayTripRecord.nightPercentageใช้ข้อมูลของวันปัจจุบัน (อิงเวลา Bangkok)ไม่ใช้ workAreaIdแบ่งกลางวัน 06:00 - 17:59 และกลางคืน 18:00 - 05:59
จำนวนเที่ยวรถweekTripRecordใช้สัปดาห์ปฏิทิน จ. - อา. ของวันที่ปัจจุบันใช้ workAreaId ผ่าน TripRecordVehicle โดยอิง driver.workAreaId ก่อน vehicle.workAreaIdbackend นับเฉพาะเที่ยวที่ isApproved = true และหน้า UI แสดง label ตาม day จาก service
จำนวนเที่ยวสูงสุดdriverTripCountใช้เดือนที่เลือกใน monthYear (อิง Bangkok-based date object)ใช้ workAreaId ที่ระดับ Userbackend นับเฉพาะเที่ยวที่อนุมัติแล้ว และหน้า UI จะกรองเฉพาะคนที่จำนวนเที่ยวมากกว่า 0 ก่อนแสดง
จำนวนรถบริการvehicleTypeCountไม่ใช้ monthYearใช้ workAreaId ผ่าน Vehicleหน้า UI กรองเฉพาะประเภทรถที่มีจำนวนรถมากกว่า 0
รายได้นักขับdriverIncomeRevenuePerMonthย้อนหลัง 3 เดือนอิงจาก monthYearใช้ workAreaIdแสดง billingMonth กับ amount
รายได้วางบิลmainBillingRevenuePerMonthย้อนหลัง 3 เดือนอิงจาก monthYearใช้ workAreaId ผ่าน Customerหน้า UI plot ค่า total * 0.99
รายได้รถร่วมpartnerInvoiceRevenuePerMonthย้อนหลัง 3 เดือนอิงจาก monthYearใช้ workAreaIdplot ค่า total จาก backend ตรง ๆ
กราฟเปรียบเทียบค่าดาวแดง (X-Ratio)vehicleTypeRedstartXRatioใช้เดือนที่เลือกใน monthYearใช้ workAreaId ผ่าน Vehicleแสดงสัดส่วนดาวแดง/ปกติแยกตามประเภทรถ
กราฟแสดงค่า X-RatiomonthlyVehicleTypeXRatioใช้เดือนที่เลือกใน monthYearใช้ workAreaId ผ่าน Vehicleแสดงค่าเฉลี่ย avgXRatio ต่อประเภทรถ
ราคาน้ำมันดีเซลfuelPricesไม่ใช้ monthYearไม่ใช้ workAreaIdดึง 9 รายการล่าสุดจาก backend

สิ่งที่ควรระวังเวลาอธิบายหน้า Dashboard​

  • ความแม่นยำของเวลา: ระบบได้เปลี่ยนมาใช้ Bangkok-based date-only objects ในการจัดการข้อมูล Dashboard ทั้งหมด เพื่อป้องกันปัญหา timezone ที่อาจทำให้ข้อมูลรายวันหรือรายเดือนคลาดเคลื่อน
  • หน้า dashboard ใช้ข้อมูลสรุปจาก backend เป็นหลัก ไม่ได้ประกอบตัวเลขจากหลาย API ในหน้าเดียว
  • รายได้วางบิล มีการคูณ 0.99 ที่ชั้น UI จริง
  • SummaryBillingTable ของบิลลูกค้าและรถร่วมใช้ totalAmount จาก backend ตรง ๆ
  • todayTripRecord และ fuelPrices ไม่ได้กรองตาม workAreaId
  • weekTripRecord ใช้ workAreaId แต่ไม่ใช้ monthYear
  • กราฟ X-Ratio มี 2 ชุดข้อมูลคนละหน้าที่
    • vehicleTypeRedstartXRatio ใช้กับกราฟ pie เปรียบเทียบดาวแดง
    • monthlyVehicleTypeXRatio ใช้กับกราฟเส้นแสดงค่าเฉลี่ย X-Ratio
  • การมองเห็น filter และหน้า dashboard ต้องผ่าน dashboard:view

อ้างอิงโค้ด​

  • atp30-tos-frontend/src/views/pages/home/index.tsx
  • atp30-tos-frontend/src/hooks/useHome.ts
  • atp30-tos-frontend/src/api/home.ts
  • atp30-tos-frontend/src/types/home.ts
  • atp30-tos-frontend/src/components/shared/Authorize.tsx