แอปบันทึกความก้าวหน้างานประจำวัน

บันทึกงานวันนี้

กดเพิ่มทันทีตอนทำเสร็จ

progress เฉลี่ย
0
งานเสร็จ 100%
:
:
👷 ยอดคนงาน รวม 0 คน
ความคืบหน้างานวันนี้
ยังไม่มีงาน
เพิ่มจากแผนงาน หรือกรอกด้านล่าง
🏗️ เครื่องจักรที่ใช้วันนี้
ยังไม่มีรายการ — เพิ่มเครื่องจักรได้ที่แท็บจัดการ
📋 แผนงานวันถัดไป
/ รายการ
บันทึกเพิ่มเติม / ติดปัญหา
📷 อัพโหลดรูปภาพ
📊 สรุปสัปดาห์นี้
☁️ Google Sheets & Drive

วาง URL ของ Google Apps Script Web App เพื่อส่งรายงานไป Google Sheets และอัพโหลด PDF ไป Drive อัตโนมัติ

🤖 AI ตรวจรูปภาพ

วิเคราะห์รูปไซต์งานก่อนส่งลูกค้า — ตรวจ PPE · มาตรฐานงาน · ความเรียบร้อย

📎 รับ API Key
📋 ข้อมูลโครงการ
🖨️ หัวกระดาษ PDF
กดเพื่ออัปโหลด
กดเพื่ออัปโหลด
🏗️ รายการเครื่องจักร
🔄 Restore จาก Google Sheets
ดึงค่าสะสมล่าสุดกลับมา กรณี browser ถูกล้าง

➕ สร้างงานใหม่

🔗 วิธีเชื่อม Google Sheets

1

เปิด Google Sheets → สร้าง Spreadsheet ใหม่ (ตั้งชื่ออะไรก็ได้)

2

คลิกเมนู Extensions → Apps Script

3

ลบโค้ดเดิมออกทั้งหมด แล้ววางโค้ดนี้แทน (มีทั้ง doPost สำหรับบันทึก และ doGet สำหรับแท็บประวัติ):

// ═══════════════════════════════════════════════════ // Progress Report — Apps Script Backend (v3) // - doPost : บันทึก progress rows / PDF / sync state // - doGet : โหลดประวัติ / sync state // ═══════════════════════════════════════════════════ // ── helpers ───────────────────────────────────────── function getOrCreateFolder(name) { const iter = DriveApp.getFoldersByName(name); return iter.hasNext() ? iter.next() : DriveApp.createFolder(name); } function getSyncSheet(ss) { let sh = ss.getSheetByName('_Sync'); if (!sh) { sh = ss.insertSheet('_Sync'); sh.hideSheet(); } return sh; } // ── doPost ────────────────────────────────────────── function doPost(e) { try { const data = JSON.parse(e.postData.contents); // 1) PDF → Google Drive if (data.type === 'pdf') { const folder = getOrCreateFolder('Progress Reports PDF'); const bytes = Utilities.base64Decode(data.content); const blob = Utilities.newBlob(bytes, 'application/pdf', data.filename || 'report.pdf'); const file = folder.createFile(blob); return ContentService .createTextOutput(JSON.stringify({ ok: true, id: file.getId() })) .setMimeType(ContentService.MimeType.JSON); } // 2) Sync state (cross-device) if (data.type === 'sync-save') { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sh = getSyncSheet(ss); const json = JSON.stringify(data.state || {}); sh.getRange('A1').setValue(json); sh.getRange('B1').setValue(new Date().toISOString()); return ContentService.createTextOutput('ok'); } // 3) Progress rows → Sheets const ss = SpreadsheetApp.getActiveSpreadsheet(); let sheet = ss.getSheetByName('Progress'); if (!sheet) { sheet = ss.insertSheet('Progress'); sheet.appendRow(['เลขที่เอกสาร','วันที่','โครงการ','ชื่องาน','หน่วย', 'ปริมาณวันนี้','สะสม','เป้าหมาย','%','อากาศ','เวลา']); sheet.setFrozenRows(1); } const all = sheet.getDataRange().getValues(); const headers = all[0]; const colDate = headers.indexOf('วันที่'); const colName = headers.indexOf('ชื่องาน'); const idx = {}; for (let i = 1; i < all.length; i++) { const key = all[i][colDate] + '|' + all[i][colName]; idx[key] = i + 1; } (data.rows||[]).forEach(r => { const row = [r.docno||'', r.date, r.project, r.name, r.unit, r.todayQty, r.cumulative, r.target, r.pct, r.weather, new Date().toLocaleString('th-TH')]; const key = r.date + '|' + r.name; if (idx[key]) { sheet.getRange(idx[key], 1, 1, row.length).setValues([row]); } else { sheet.appendRow(row); idx[key] = sheet.getLastRow(); } }); return ContentService.createTextOutput('ok'); } catch(err) { return ContentService.createTextOutput('error:' + err.message); } } // ── doGet ─────────────────────────────────────────── function doGet(e) { try { const ss = SpreadsheetApp.getActiveSpreadsheet(); // sync-load : ส่ง state ล่าสุดกลับมา if (e.parameter.action === 'sync-load') { const sh = getSyncSheet(ss); const val = sh.getRange('A1').getValue(); const ts = sh.getRange('B1').getValue(); const state = val ? JSON.parse(val) : null; return ContentService .createTextOutput(JSON.stringify({ state, serverTs: ts ? String(ts) : null })) .setMimeType(ContentService.MimeType.JSON); } // default : ส่ง Progress rows ทั้งหมด const sheet = ss.getSheetByName('Progress'); if (!sheet) return ContentService.createTextOutput('[]').setMimeType(ContentService.MimeType.JSON); const all = sheet.getDataRange().getValues(); if (all.length < 2) return ContentService.createTextOutput('[]').setMimeType(ContentService.MimeType.JSON); const headers = all[0]; const rows = all.slice(1).map(row => { const obj = {}; headers.forEach((h, i) => { obj[String(h)] = row[i]; }); return obj; }); return ContentService.createTextOutput(JSON.stringify(rows)) .setMimeType(ContentService.MimeType.JSON); } catch(err) { return ContentService .createTextOutput(JSON.stringify({ error: err.message })) .setMimeType(ContentService.MimeType.JSON); } } // ── ทดสอบ DriveApp permission ───────────────────── function testDrive() { const folder = getOrCreateFolder('Progress Reports PDF'); Logger.log('Folder ID: ' + folder.getId()); }
4

กด Save (💾) แล้วคลิก Deploy → New deployment
⚠️ ถ้าเคย deploy แล้ว ให้ไปที่ Deploy → Manage deployments → Edit (✏️) → New version → Deploy แทน เพื่อให้ URL เดิมใช้ได้กับฟังก์ชัน doGet() ด้วย

5

ตั้งค่าดังนี้:
• Type: Web app
• Execute as: Me
• Who has access: Anyone
แล้วกด Deploy → อนุญาต permission

6

Copy Web app URL ที่ได้ แล้วนำมาวางในช่อง URL ในแอพนี้

✏️ แก้ค่า Quick Chip

hold ค้างที่ chip เพื่อแก้ค่า

ระบุขนาด / รายละเอียดเพิ่มเติม (ไม่บังคับ)
🤖 ผลวิเคราะห์รูปภาพ
⏳ กำลังวิเคราะห์...
ประวัติงาน
➕ เพิ่มรายการ (ย้อนหลังได้)
เลือกงาน

แก้ไขงาน

🔄 Restore ค่าสะสมจาก Google Sheets

⚙️ ตั้งค่าเลขที่เอกสาร

จำนวนหลัก:
ตัวอย่าง:
🤖 เลือกรูปส่ง AI ตรวจ
เลือก 0 รูป