您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show daily punch in/out in a dedicated column with weekly and monthly statistics
当前为
// ==UserScript== // @name AtoZ Punch History Enhanced with Statistics // @namespace http://tampermonkey.net/ // @version 2.1 // @description Show daily punch in/out in a dedicated column with weekly and monthly statistics // @author wmehedis // @match https://atoz.amazon.work/time/balance-ledger/TimeOff_ATPLUS_DE_CF_PaidAbsenceFlexDismantlingHour // @grant none // ==/UserScript== (function () { 'use strict'; const styles = ` .punch-column-header { font-weight: bold; background-color: #f0f2f5; text-align: center; } .punch-cell { font-size: 13px; text-align: center; padding: 4px; font-family: "Amazon Ember", Arial, sans-serif; background-color: #f9f9f9; } .punch-card { display: inline-block; background-color: #fff; border: 1px solid #e0e0e0; border-radius: 4px; padding: 4px 8px; margin: 0 2px; box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); } .punch-out { color: #c62828; font-weight: bold; } .punch-in { color: #2e7d32; font-weight: bold; } .stats-panel { position: fixed; top: 20px; right: 20px; background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); z-index: 1000; max-width: 300px; } `; function injectStyles() { const styleSheet = document.createElement("style"); styleSheet.textContent = styles; document.head.appendChild(styleSheet); } async function fetchPunchData() { const employeeId = window.AtoZContext?.employee?.employeeId; if (!employeeId) return null; const endDate = new Date(); const startDate = new Date(); startDate.setMonth(startDate.getMonth() - 2); const url = `https://atoz-apps.amazon.work/apis/AtoZTimeoffService/punches?employeeId=${employeeId}&startDate=${startDate.toISOString().split('T')[0]}&endDate=${endDate.toISOString().split('T')[0]}&temporalRouting=false&usePaycodeDomainAPI=true`; const res = await fetch(url, { headers: { 'accept': '*/*', 'x-atoz-client-id': 'ATOZ_TIMEOFF_SERVICE' }, credentials: 'include' }); if (!res.ok) return null; return await res.json(); } function formatTime(dateTime) { return new Date(dateTime).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false }); } function parseDate(text) { const match = text.match(/(\d+)\.\s+(\w+\.?)\s+(\d{4})/) || text.match(/(\w+)\s+(\d+),\s+(\d{4})/); if (!match) return null; const [_, part1, part2, year] = match; const day = part1.length <= 2 ? part1 : part2; const monthName = (part1.length <= 2 ? part2 : part1).replace('.', ''); const months = { Jan: '01', January: '01', Feb: '02', February: '02', Mar: '03', March: '03', Apr: '04', April: '04', May: '05', Jun: '06', June: '06', Jul: '07', July: '07', Aug: '08', August: '08', Sep: '09', September: '09', Oct: '10', October: '10', Nov: '11', November: '11', Dec: '12', December: '12' }; const month = months[monthName]; if (!month) return null; return new Date(`${year}-${month}-${day.padStart(2, '0')}`); } function getPunchesForDate(data, date) { if (!data || !data.punchesTimeSegments) return []; return data.punchesTimeSegments.filter(p => new Date(p.startDateTime).toDateString() === date.toDateString()); } function addPunchColumnHeader(table) { const headerRow = table.querySelector('thead tr'); const th = document.createElement('th'); th.className = 'punch-column-header'; th.textContent = 'Punch Times'; headerRow.appendChild(th); } function calculateWorkHours(inTime, outTime) { const start = new Date(`2000-01-01 ${inTime}`); const end = new Date(`2000-01-01 ${outTime}`); const diff = (end - start) / (1000 * 60 * 60); // Convert to hours return Math.round(diff * 100) / 100; } function createStatsPanel(punchData) { const statsPanel = document.createElement('div'); statsPanel.className = 'stats-panel'; const now = new Date(); const weekStart = new Date(now.setDate(now.getDate() - now.getDay())); const monthStart = new Date(now.getFullYear(), now.getMonth(), 1); let weeklyHours = 0; let monthlyHours = 0; punchData.punchesTimeSegments.forEach(punch => { const punchDate = new Date(punch.startDateTime); const inTime = formatTime(punch.startDateTime); const outTime = formatTime(punch.endDateTime || punch.startDateTime); const hours = calculateWorkHours(inTime, outTime); if (punchDate >= weekStart) { weeklyHours += hours; } if (punchDate >= monthStart) { monthlyHours += hours; } }); statsPanel.innerHTML = ` <h3>Work Statistics</h3> <p>Weekly Hours: ${weeklyHours.toFixed(2)}</p> <p>Monthly Hours: ${monthlyHours.toFixed(2)}</p> `; document.body.appendChild(statsPanel); } async function processTable() { const table = document.querySelector('table[data-test-component="StencilTable"]'); if (!table) return; injectStyles(); addPunchColumnHeader(table); const punchData = await fetchPunchData(); if (!punchData) return; createStatsPanel(punchData); const rows = table.querySelectorAll('tbody tr'); rows.forEach(row => { const dateCell = row.querySelector('.css-1vslykb'); const dateText = dateCell?.querySelector('.css-1kgbsl4')?.textContent; const date = parseDate(dateText); const cell = document.createElement('td'); cell.className = 'punch-cell'; if (date) { const punches = getPunchesForDate(punchData, date); if (punches.length > 0) { const inTime = formatTime(punches[0].startDateTime); const outTime = formatTime(punches[punches.length - 1].endDateTime || punches[punches.length - 1].startDateTime); cell.innerHTML = ` <span class="punch-card"> In: <span class="punch-in">${inTime}</span> </span> <span class="punch-card"> Out: <span class="punch-out">${outTime}</span> </span> `; } else { cell.textContent = '—'; } } else { cell.textContent = 'Invalid'; } row.appendChild(cell); }); } // Wait for table to load let attempts = 0; const interval = setInterval(() => { attempts++; if (document.querySelector('table[data-test-component="StencilTable"]')) { clearInterval(interval); processTable(); } if (attempts > 20) clearInterval(interval); }, 500); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址