Skip to content

7.5 · GraphQL queries + mutations catalog

บทนี้ทำดัชนี GraphQL operations ทั้งหมดที่ vtrc-web ใช้ — 138 queries + 41 mutations รวม 179 operations (นับจาก export default keys ใน queries.js / mutations.js; แท็ก gql มี 137 และ 42 ตามลำดับ)

เป้าหมายคือให้ค้นหา "ฟีเจอร์นี้ใช้ query ชื่ออะไร" แล้วไปดูในไฟล์ queries.js / mutations.js ได้โดยตรง


โครงสร้างไฟล์

src/graphql/
├── queries.js         4,493 บรรทัด  — 138 query definitions (export keys)
├── mutations.js       1,447 บรรทัด  — 41 mutation definitions (export keys)
└── index.js             2 บรรทัด  — re-export

src/graphql/index.js ทั้งหมด:

1:2:vtrc-web/src/graphql/index.js
export { default as Queries } from './queries'
export { default as Mutations } from './mutations'

ทุกหน้า import ผ่าน import { Queries, Mutations } from '../graphql' — ไม่ import ตรงจากไฟล์

รูปแบบการประกาศ

query และ mutation แต่ละตัวประกาศเป็น const ที่ระดับ module แล้วรวมใน export default {} ท้ายไฟล์:

js
// queries.js (ตัวอย่าง pattern)
import gql from "graphql-tag";

const fetchSlip = gql`
  query (
    $month: String!
    $year: String!
    $identityCard: String!
    $profileKey: String!
  ) {
    fetchSlip(
      month: $month
      year: $year
      identityCard: $identityCard
      profileKey: $profileKey
    ) {
      paymentDate
      income { lists { name value } total totalPerMonth totalPerYear }
      expense { total withholdingTax lists { name value } }
      baseTax406
    }
  }
`;

// ... 138 queries ...

export default {
  fetchListPost,
  fetchListPostType,
  fetchProfile,
  fetchSlip,
  // ...
};

ข้อควรระวังเกี่ยวกับ helper

utils/string.js export toGqlTypes, toGqlArgs, toGqlFields:

1:35:vtrc-web/src/utils/string.js
export const capitalizeFirstLetter = word =>
	word && word.charAt(0).toUpperCase() + word.substring(1)

export const toGqlTypes = args => {
	let gqlTypes = ''
	args.forEach((arg, index) => {
		if (index !== 0) {
			gqlTypes = gqlTypes + ' '
		}
		gqlTypes = gqlTypes + `$${arg.name}: ${arg.type}`
	})
	return gqlTypes
}

export const toGqlArgs = args => {
	let gqlArgs = ''
	args.forEach((arg, index) => {
		if (index !== 0) {
			gqlArgs = gqlArgs + ' '
		}
		gqlArgs = gqlArgs + `${arg.name}: $${arg.name}`
	})
	return gqlArgs
}

export const toGqlFields = fields => {
	let gqlFields = ''
	for (let n in fields) {
		gqlFields = gqlFields + fields[n]
		if (n !== fields.length - 1) {
			gqlFields = gqlFields + '\n'
		}
	}
	return gqlFields
}

helpers ทั้ง 3 ถูก import ใน queries.js:2 แต่ ไม่ได้ใช้จริง — ทุก query เขียนเป็น template literal ด้วยมือ เป็น helper ที่ค้างจากการวางแผน refactor ในอดีต

ถ้าจะ refactor ในอนาคต อย่าเอา helpers พวกนี้ไปใช้โดยไม่ทดสอบ — มีบั๊กในตัวเอง (เช่น toGqlFields เทียบ n !== fields.length - 1 ผิดเพราะ for...in วน key ไม่ใช่ index)


Queries — 138 ตัว จัดเป็น 12 cluster

Cluster 1 — Auth & onboarding (12 queries)

Queryหน้าที่
refreshTokenrefresh JWT (ใช้ใน errorLink บ่อยที่สุด)
verifyUserตรวจ username ก่อนใส่ password (login ขั้นที่ 1)
verifyEmpCodeLoginverify employee code
generateCaptchaขอ captcha ก่อน login
checkRequestCaptchaตรวจ captcha
requestSendingOTPขอ OTP
sendVerifyCodeส่ง verify code
setupPasswordตั้ง password ครั้งแรก
forgetPasswordลืม password
checkSMSforgetPasswordตรวจ SMS สำหรับ forget password
resetPasswordreset password
requestProfileCheckตรวจ profile ก่อน verify

Cluster 2 — Profile (10 queries)

Queryหน้าที่
fetchProfileprofile หลัก (ใช้ใน SiderLayout)
fetchProfileForLeaveprofile สำหรับ leave (subset)
fetchProfileDetaildetail ของ profile
fetchEmployeeProfileemployee profile ขยาย
fetchEmployeeDetailemployee detail
fetchEmployeeProfileHistoryประวัติการเปลี่ยนแปลง profile
checkIsEmployeeProfileHistoryActiveตรวจว่า profile history ยัง active
detchProfileListDetailprofile list detail (สะกดผิด detch แต่ใช้จริง)
fetchDetailProfileListCCprofile list CC
accordingProfileprofile ตามเงื่อนไข

Cluster 3 — Slip & tax (11 queries)

Queryหน้าที่
fetchSlipสลิปเงินเดือน (main)
fetchSlipPayDateวันที่จ่ายของ slip
fetchUrlSlipURL ดาวน์โหลด slip (PDF)
dropDownSlipPaymentdropdown ปี/เดือนของ slip
dropDownMasterSlipPaymentdropdown slip master data
fetchUrlTaxURL ดาวน์โหลดภาษี
fetchUrlTax6MonthURL ภาษี 6 เดือน
fetchUrlTaxYearsURL ภาษีรายปี
fetchTaxDrafttax draft
fetchDetailTaxAlldetail tax ทั้งหมด
templateFormTaxtemplate ของ form tax

Cluster 4 — News, policy, document (10 queries)

Queryหน้าที่
fetchListPostรายการโพสต์ (ข่าว)
fetchListPostTypeรายการโพสต์ตาม type
fetchListNotificationรายการแจ้งเตือน
fetchCountAllNotificationจำนวนแจ้งเตือนทั้งหมด (badge)
fetchNotificationdetail แจ้งเตือน
fetchPolicyLastVersionpolicy เวอร์ชันล่าสุด
fetchListDocumenรายการ document (สะกดผิด Documen แต่ใช้จริง)
fetchListDocumenListdocument list (subset)
fetchListDocumentGroupdocument group
fetchListDocumentCategoryMasterDatadocument category master data

Cluster 5 — Hospital / medical claim (10 queries)

Queryหน้าที่
fetchListWDHospitalรายการเบิกค่ารักษา
fetchListSearchWDHospitalค้นหารายการเบิก
fetchMedicalExpensesLicenseeผู้มีสิทธิเบิก
dropdownMedicalExpensesLicenseedropdown ผู้มีสิทธิ
fetchApproverMedicalapprover ทางการแพทย์
fetchOptionApproverตัวเลือก approver
fetchListWDHospitalApproverรายการที่ต้อง approve
fetchListSearchWDHospitalApproverค้นหารายการ approve
fetchWDHospitalHistoryประวัติการเบิก
fetchHospitaldetail โรงพยาบาล

Cluster 6 — Leave (15 queries)

Queryหน้าที่
fetchLeaveDocumentListรายการใบลา
fetchLeaveDocumentDetaildetail ใบลา
fetchLeaveDocumentDetailStatusstatus ใบลา
fetchLeaveDocumentDetailDrafdraft ใบลา (สะกดผิด Draf แต่ใช้จริง)
fetchLeaveDocumentHistoryประวัติใบลา
fetchListLeaveDocumentApproverรายการที่ต้อง approve
fetchApproverLeaveapprover ใบลา
fetchOptionApproverLeaveตัวเลือก approver
fetchLeaveDayจำนวนวันลา
fetchLeaveDayAllวันลาทั้งหมด
fetchLeaveHourจำนวนชั่วโมงลา
fetchLeaveShiftTimeshift time ของ leave
fetchWorkingDayวันทำการ
fetchTotalDayOffวันหยุดรวม
detailLeaveDocumentAsFlowdetail leave document flow

Cluster 7 — Leave studies (4 queries)

Queryหน้าที่
fetchListStudyLeaveRequestรายการขอลาศึกษา
fetchStudyLeaveRequestByIddetail ขอลาศึกษา
dropDownstudyLeaveYeardropdown ปีการศึกษา
fetchMasterConfigTypeLeavemaster config type leave

Cluster 8 — Welfare / fund (10 queries)

Queryหน้าที่
fetchAllProvidentFundDetailรายละเอียดกองทุนสงเคราะห์
fetchConfigChangeProvPercentageconfig % เปลี่ยนกองทุน
fetchFundChangeHistoryประวัติการเปลี่ยนแปลงกองทุน
fetchFundChangeBenefitPersonDetaildetail ผู้รับผลประโยชน์
fetchListChildTuitionsรายการค่าเล่าเรียนบุตร
fetchListChildDetailInTuitiondetail บุตรในค่าเล่าเรียน
fetchEachChildTuitionDetaildetail รายบุตร
fetchEmpwithCoAemployee with CoA
fetchEmployeeFamilyครอบครัว employee
fetchEmployeeRightsสิทธิของ employee

Cluster 9 — Master data / dropdown (12 queries)

Queryหน้าที่
fetchListDropDownMasterDatamaster data ทั่วไป
fetchDropDownMasterDatamaster data (duplicate)
fetchListDropDownDivisionCDMasterDatadivision master data
fetchListDocumentTypeMasterDatadocument type
fetchListDocumentCategoryMasterDatadocument category
dropdownListRelationความสัมพันธ์
dropdownRelationShipLabellabel ความสัมพันธ์
dropdownListTitleMaleคำนำหน้าชาย
dropdownListTitleFemaleคำนำหน้าหญิง
dropdownListProvinceจังหวัด
dropdownListAmphurอำเภอ
dropdownListDistrictตำบล

Cluster 10 — Organization / contact (5 queries)

Queryหน้าที่
fetchListOrganizationรายการหน่วยงาน
fetchListOrganizationGroupกลุ่มหน่วยงาน
fetchListContactUsติดต่อเรา
fetchListContactUsCategoryหมวดหมู่ติดต่อ
fetchListSystemระบบ

Cluster 11 — Salary certificate (5 queries)

Queryหน้าที่
fetchSalaryCertหนังสือรับรองเงินเดือน
fetchUrlSalaryCertURL ดาวน์โหลด
fetchUrlSalaryCertForBankURL สำหรับธนาคาร
fetchConditionSalaryCertTextเงื่อนไข text
fetchConditionSalaryCertForBankTextเงื่อนไขสำหรับธนาคาร

Cluster 12 — อื่น ๆ (8 queries)

Queryหน้าที่
fetchTimeAttendanceByDateเวลาเข้า-ออกงาน
fetchEmployeeBankAccountบัญชีธนาคาร
fetchEmployeeTaxภาษี employee
fetchEmployeeCompensationcompensation
fetchEmployeeProvidentFundกองทุน employee
fetchCourse, fetchCourseListหลักสูตร
fetchApplicationSettingตั้งค่าแอป
howToOpenPayrollSlipวิธีเปิด slip

Cluster 13 — Conicle + KCMH document (5 queries)

Queryหน้าที่
fetchUrlConicleAllPolicyConicle policy ทั้งหมด
fetchUrlConicleRequestPolicyConicle request
fetchUrlConicleMyPolicyConicle ของฉัน
fetchUrlConicleRedirectPathConicle redirect
fetchListKCMHDocument, fetchListKCMHDocumentList, fetchListKCMHQualityDocument, fetchListKCMHQualityDocumentListKCMH document

Cluster 14 — PMS (3 queries)

Queryหน้าที่
fetchMasterConfigTypePMSconfig type PMS
fetchCountListAllApprovingจำนวนรายการ approving
listCancelWaitingForApprovalรายการ cancel waiting

Cluster 15 — Delegate / approver proxy (3 queries)

Queryหน้าที่
fetchListDelegateApproverรายการมอบหมาย
fetchListDelegatorผู้มอบหมาย
employeeDetailProfileForLeaveรายละเอียด employee สำหรับมอบหมาย

Mutations — 41 ตัว จัดเป็น 7 cluster

Cluster M1 — Auth (6 mutations)

Mutationหน้าที่
loginlogin หลัก
logoutlogout
setupPasswordตั้ง password ครั้งแรก
changePasswordเปลี่ยน password
requestVerifyOTPandSetupPasswordขอ OTP ก่อน setup
resetPasswordreset password

Cluster M2 — Profile (6 mutations)

Mutationหน้าที่
changeCurrentProfileเปลี่ยน profile ปัจจุบัน
createConsentบันทึก consent
changePhoneNumberเปลี่ยนเบอร์โทร
createAddressเพิ่มที่อยู่
updateAddressแก้ไขที่อยู่
createPostReadทำเครื่องหมายอ่านแล้ว

Cluster M3 — Tax (2 mutations)

Mutationหน้าที่
createTaxDraftสร้าง tax draft
updateTaxDraftแก้ไข tax draft

Cluster M4 — Hospital (6 mutations)

Mutationหน้าที่
createWDHospitalสร้างคำขอเบิก
updateWDHospitalแก้ไขคำขอเบิก
destroyWDHospitalลบคำขอเบิก
destroyWDSlipลบ slip
destroyWDHospitalDocumentลบเอกสาร
cancelExportWDHospitalยกเลิก export

Cluster M5 — Leave (9 mutations)

Mutationหน้าที่
createLeaveDocumentสร้างใบลา
updateLeaveDocumentแก้ไขใบลา
multipleUpdateLeaveDocumentแก้ไขหลายใบพร้อมกัน
removeLeaveDocumentDrafลบ draft
checkRemoveLeaveDocumentAsFlowตรวจการลบตาม flow
mutipleApproveCancelLeaveDocumentAsFlowapprove cancel หลายรายการ
approveCancelLeaveDocumentAsFlowapprove cancel รายการเดียว
updateStudyLeaveRequestอัปเดตคำขอลาศึกษา
deleteAttachmentFileลบไฟล์แนบ

Cluster M6 — Delegate (2 mutations)

Mutationหน้าที่
createDelegateApproverมอบหมาย approver
revokeDelegateApproverยกเลิกการมอบหมาย

Cluster M7 — Fund (5 mutations)

Mutationหน้าที่
createFundRateChangeสร้างคำขอเปลี่ยนอัตรา
updateFundRateChangeแก้ไขคำขอ
createFundApplicationสมัครกองทุน
createFundBenefitPersonเพิ่มผู้รับผลประโยชน์
updateFundBenefitPersonแก้ไขผู้รับผลประโยชน์
createFundBenefitPersonFormPDFสร้าง PDF ผู้รับผลประโยชน์

Cluster M8 — อื่น ๆ (3 mutations)

Mutationหน้าที่
createUserReadNotificationทำเครื่องหมายอ่าน notification
createUserResultNotificationทำเครื่องหมายผลลัพธ์ notification
updateClickCountอัปเดต click count (analytics)

สัดส่วน queries : mutations

queries     138  (77%)
mutations    41  (23%)
total       179
ratio      3.37 : 1

ฐานนับ: จำนวน key ใน export default (138 queries / 41 mutations ≈ 3.37 : 1) — ไม่ใช่จำนวนแท็ก gql (137 / 42)

อัตราส่วน queries : mutations ที่ ≈ 3.37 : 1 บ่งชี้ว่าแอปเป็น read-heavy — อ่านข้อมูลมากกว่าเขียน ซึ่งสอดคล้องกับเอกลักษณ์ของ employee portal


Typos ที่ติดอยู่ใน GraphQL schema (คำเตือน)

GraphQL schema ฝั่ง vtrc-api ถูก author ด้วยมือและเผยแพร่สู่สาธารณะแล้ว เปลี่ยนชื่อไม่ได้โดยไม่ทำ breaking change typos เหล่านี้จึงคงอยู่ใน query/mutation names ตลอดไป:

Typoที่ควรเป็นที่พบ
fetchListDocumenfetchListDocumentqueries.js + ใช้ใน page
fetchLeaveDocumentDetailDraffetchLeaveDocumentDetailDraftqueries.js
detchProfileListDetailfetchProfileListDetailqueries.js
dropDownstudyLeaveYeardropDownStudyLeaveYearqueries.js (s ตัวเล็ก)

กฎเหล็ก — ถ้าเจอ query/mutation ที่ดูสะกดผิด ให้ใช้ตามที่เป็น ห้ามแก้ชื่อโดยไม่ได้รับมอบหมาย เพราะจะทำให้ request fail


เคล็ดลับตอนทำงานจริง

ตอนค้นหา query สำหรับฟีเจอร์

  1. ค้นใน queries.js ด้วยคำที่เกี่ยวข้อง (เช่น Slip, Leave, Hospital)
  2. ดูชื่อ field ที่ query คืน — ถ้าตรงกับที่ต้องการ ใช้ตัวนั้น
  3. cross-check ในฝั่ง page ที่ใช้ — grep Queries.<name> ใน pages/ เพื่อดูตัวอย่างการใช้

ตอนเพิ่ม query ใหม่

  1. เพิ่ม const newQuery = gql\...`ในตำแหน่งที่เหมาะสมในqueries.js`
  2. เพิ่ม newQuery, ใน export default {} ท้ายไฟล์
  3. cross-check ฝั่ง vtrc-api ว่า query นั้นมีอยู่จริงใน schema
  4. อย่าลืมเพิ่มใน queries_bk.js ด้วยถ้าทีมต้องการ (แต่ปกติไม่ต้อง)

ตอน debug "query ตอบ null"

  1. ตรวจ variables ที่ส่งไป — ครบตามที่ query กำหนดไหม
  2. ตรวจ extensions.code ใน response — อาจเป็น FORBIDDEN (ไม่มีสิทธิ์) หรือ BAD_USER_INPUT
  3. ถ้าทุกอย่างถูกแต่ได้ null — อาจเป็นที่ฝั่ง resolver return null เพราะไม่พบข้อมูล

ตอนใช้ query ใน page

Pattern มาตรฐาน:

js
this.props.client.query({
  query: Queries.fetchSlip,
  variables: {
    month: '01',
    year: '2568',
    identityCard: '...',
    profileKey: '...'
  },
  fetchPolicy: 'no-cache'    // optional, default อยู่แล้ว
})
.then(({ data, errors }) => {
  if (errors) {
    // errorLink จัดการให้แล้ว
    return
  }
  this.setState({ slip: data.fetchSlip })
})

หรือแบบ async/await:

js
const { data, errors } = await this.props.client.query({
  query: Queries.fetchSlip,
  variables: { ... }
})

ตอนใช้ mutation

js
this.props.client.mutate({
  mutation: Mutations.createLeaveDocument,
  variables: {
    leaveType: '...',
    startDate: '...',
    endDate: '...',
    // ...
  }
})
.then(({ data, errors }) => {
  if (errors) return
  alertMessage('success', 'บันทึกสำเร็จ')
  this.props.history.push('/leave/search')
})

ขั้นตอนถัดไป

ไป บท 6.6 Component + page architecture