工時填寫助手
語言規範:本文件使用繁體中文撰寫。
前置需求
本技能使用 agent-browser 進行瀏覽器自動化,請先閱讀 agent-browser/SKILL.md。
核心原則
- •必須用程式碼驗證星期幾 - 絕不靠觀察或猜測日期對應的星期
- •自動決策 - 主動排除假日,信任使用者會提出修正
- •一次性確認 - 生成完整計畫後一次確認,不分步驟詢問
- •表格化呈現 - 日期清單用表格展示
工作流程
1. 初始確認與登入
步驟 1:開啟瀏覽器並檢查登入狀態
agent-browser close 2>/dev/null; sleep 1; agent-browser open https://gaweb.nutn.edu.tw/workhour/Budget --headed
agent-browser snapshot -i
檢查 snapshot 結果:
- •如果看到「計畫管理」連結 → 已登入,繼續步驟 2
- •如果看到「登入」按鈕和帳號密碼欄位 → 未登入,執行步驟 1-2
步驟 1-2:自動登入
# 點擊登入連結(如果在首頁)
agent-browser click @e2 # 登入連結的 ref
# 取得表單元素
agent-browser snapshot -i
# 填寫帳號密碼(預設都是身份證字號)
agent-browser fill @e5 "身份證字號"; agent-browser fill @e6 "身份證字號"
# 點擊登入按鈕(使用 eval 更穩定)
agent-browser eval "document.querySelector('input[type=submit], button[type=submit]').click()"
# 等待頁面載入
agent-browser wait 2000; agent-browser get url
登入成功後 URL 會變成 /workhour/Budget。
處理登入後的 Modal 提示
系統可能會顯示提示訊息的 Modal,用 eval 關閉:
agent-browser eval "document.querySelector('#myModal button[data-dismiss=modal]')?.click()"
2. 收集計畫資訊
詢問使用者:
- •計畫編號(例如:D115-03)
- •填寫時間範圍(例如:115/1/1 到 115/1/31)
- •是否有行事曆圖片(用於排除假日)
3. 選擇計畫並檢查歷史紀錄
# 取得計畫列表
agent-browser eval "
Array.from(document.querySelectorAll('table tbody tr')).slice(1).map(r => ({
id: r.cells[0]?.textContent?.trim(),
name: r.cells[1]?.textContent?.trim(),
period: r.cells[2]?.textContent?.trim(),
status: r.cells[3]?.textContent?.trim()
}));
"
# 點擊對應計畫的「選擇」連結 agent-browser click @eXX # 根據 snapshot 結果找到對應的 ref # 等待頁面載入 agent-browser wait 1500; agent-browser snapshot
分析歷史紀錄
關鍵:必須用程式碼計算星期幾(禁止觀察猜測)
agent-browser eval "
// 取得歷史紀錄
const rows = Array.from(document.querySelectorAll('table tbody tr')).slice(1);
const history = rows.map(r => ({
date: r.cells[0]?.textContent?.trim(),
start: r.cells[1]?.textContent?.trim(),
end: r.cells[2]?.textContent?.trim(),
hours: r.cells[3]?.textContent?.trim()
})).filter(h => h.date && h.date.includes('/'));
// 用程式碼計算星期幾
const weekdays = ['日', '一', '二', '三', '四', '五', '六'];
const analyzed = history.map(h => {
const parts = h.date.split('/').map(Number);
if (parts.length === 3) {
const [rocYear, month, day] = parts;
const adYear = rocYear + 1911;
const date = new Date(adYear, month - 1, day);
return {
...h,
weekday: date.getDay(),
weekdayName: weekdays[date.getDay()]
};
}
return h;
});
// 統計工作日模式
const weekdayCounts = {};
analyzed.forEach(item => {
if (item.weekdayName) {
weekdayCounts[item.weekdayName] = (weekdayCounts[item.weekdayName] || 0) + 1;
}
});
// 統計時段模式
const timeSlots = {};
analyzed.forEach(item => {
const slot = item.start + '-' + item.end;
timeSlots[slot] = (timeSlots[slot] || 0) + 1;
});
JSON.stringify({
recentRecords: analyzed.slice(0, 20),
weekdayCounts,
timeSlots,
total: analyzed.length
}, null, 2);
"
- •禁止:直接觀察日期就說「看起來是星期X」
- •必須:用程式碼計算後才能確認工作日模式
- •分析歷史記錄的時間區間
- •向使用者展示分析結果(用表格呈現)
如果目標計畫沒有歷史紀錄(新計畫或新年度)
重要:查找同名的舊計畫歷史紀錄作為參考。
例如:D115-03 沒有歷史,但 D114-03 有相同名稱「【B版】回流教育學位班經費(碩士班)」
- •
回到計畫列表頁面:
bashagent-browser open https://gaweb.nutn.edu.tw/workhour/Budget
- •
找出同名舊計畫並選擇:
bashagent-browser click @eXX # 舊計畫的選擇連結
- •
分析舊計畫的歷史紀錄(使用上方相同的 eval 程式碼)
- •
取得工作模式後,再切回新計畫進行填寫
如果找不到任何相關歷史紀錄:詢問使用者以下資訊:
- •工作日(星期幾)
- •每日時間區間(可以有多個,例如:17:40-20:40 和 21:10-23:10)
4. 檢查頁面預設值
agent-browser eval "
const checkedBoxes = Array.from(document.querySelectorAll('input[type=\"checkbox\"]'))
.map(cb => ({id: cb.id, name: cb.name, checked: cb.checked, label: cb.parentElement?.textContent?.trim()}))
.filter(item => item.checked);
const wcontent = document.getElementById('Wcontent')?.value || '';
const wother = document.getElementById('Wother')?.value || '';
({checkedBoxes, wcontent, wother});
"
如果頁面有預設勾選和內容:記錄預設狀態,直接採用(不詢問使用者)。
如果頁面沒有任何勾選:詢問使用者工作內容分類:
- •研究學習 (checkbox1)
- •資料處理 (checkbox2)
- •統計調查 (checkbox3)
- •實地考察 (checkbox4)
- •行政事務 (checkbox5)
- •其他 (checkbox6) - 需填寫具體內容
5. 處理假日
重要:必須載入 academic-calendar 技能取得假日資訊
如果使用者提供日曆資料(圖片):
- •分析日曆,識別紅色標記的放假日
- •自動排除這些日期(不詢問使用者)
- •在最終確認時列出已排除的日期
如果沒有日曆資料:
- •載入
academic-calendar/SKILL.md取得學校行事曆 - •從行事曆識別寒假、暑假、國定假日等日期
- •自動排除這些日期
- •在最終確認時列出已排除的日期並詢問是否還有需要排除的
6. 生成填寫計畫
自動生成日期清單
agent-browser eval "
function generateWorkDates(startRoc, endRoc, workWeekdays, holidays = []) {
const results = [];
const weekdayNames = ['日', '一', '二', '三', '四', '五', '六'];
const [startY, startM, startD] = startRoc.split('/').map(Number);
const [endY, endM, endD] = endRoc.split('/').map(Number);
let current = new Date(startY + 1911, startM - 1, startD);
const end = new Date(endY + 1911, endM - 1, endD);
while (current <= end) {
const rocDate = (current.getFullYear() - 1911) + '/' + (current.getMonth() + 1) + '/' + current.getDate();
const weekday = current.getDay();
if (workWeekdays.includes(weekday) && !holidays.includes(rocDate)) {
results.push({
date: rocDate,
weekday: weekday,
weekdayName: weekdayNames[weekday]
});
}
current.setDate(current.getDate() + 1);
}
return results;
}
// 範例:星期一(1)和星期四(4),排除假日
const dates = generateWorkDates('115/1/1', '115/1/31', [1, 4], ['115/1/1', '115/1/11']);
JSON.stringify(dates, null, 2);
"
7. 一次性最終確認
用表格呈現完整計畫,一次確認所有資訊:
## 填寫計畫確認 ### 基本資訊 - **計畫**:D115-03 【B版】回流教育學位班經費(碩士班) - **工作日模式**:星期一、星期四(從 D114-03 歷史分析) - **工作類別**:其他 - 協助管理榮譽校區教室 ### 填寫清單 | # | 日期 | 星期 | 時段 1 | 時段 2 | |---|------|------|--------|--------| | 1 | 115/1/5 | 一 | 17:40-20:40 | 21:10-23:10 | | 2 | 115/1/8 | 四 | 17:40-20:40 | 21:10-23:10 | | ... | ... | ... | ... | ... | ### 已排除日期 - **國定假日**:115/1/1 開國紀念日 - **寒假**:115/1/11 起 ### 統計 - **總天數**:X 天 - **總筆數**:X 筆(每天 2 個時段) - **總時數**:X 小時 --- 確認以上資訊無誤後開始填寫?
注意:不分步驟詢問,一次呈現所有資訊讓使用者確認。
8. 批次填寫
重要:eval 中的 async/await 不可靠,必須逐筆執行並加入 wait:
# 第 1 筆
agent-browser eval "
document.getElementById('WorkDay').value = '115/1/5';
document.getElementById('StartT').value = '17:40';
document.getElementById('EndT').value = '20:40';
document.getElementById('buttonID').click();
"
agent-browser wait 1500
# 第 2 筆
agent-browser eval "
document.getElementById('WorkDay').value = '115/1/5';
document.getElementById('StartT').value = '21:10';
document.getElementById('EndT').value = '23:10';
document.getElementById('buttonID').click();
"
agent-browser wait 1500
# 繼續...
填寫進度:每填寫 5 筆,報告進度。
9. 完成驗證
agent-browser eval "
const rows = Array.from(document.querySelectorAll('table tbody tr')).slice(1);
const records = rows.map(r => ({
date: r.cells[0]?.textContent?.trim(),
start: r.cells[1]?.textContent?.trim(),
end: r.cells[2]?.textContent?.trim(),
hours: r.cells[3]?.textContent?.trim()
})).filter(h => h.date && h.date.includes('/'));
const totalHours = records.reduce((sum, r) => sum + parseFloat(r.hours || 0), 0);
JSON.stringify({ records, count: records.length, totalHours }, null, 2);
"
確認所有記錄都已成功新增,向使用者報告完成狀態(包含成功新增的筆數和總時數)。
10. 下載 PDF 工時紀錄表
填寫完成後,下載 PDF 工時紀錄表。
重要:必須透過正常流程(選擇計畫 → 列印按鈕 → 選擇年月)來設定 session 狀態,直接用 URL 跳轉會導致顯示計畫選擇頁而非工時紀錄表。
使用 agent-browser 下載(推薦)
如果已在 /Hours/Create 頁面(填寫工時後):
# 點擊「列印工時紀錄表」按鈕 agent-browser snapshot -i # 找到列印按鈕的 ref agent-browser click @eXX # 列印工時紀錄表按鈕 # 進入年月選擇頁 /Hours/Report2 agent-browser wait 1500 agent-browser snapshot -i # 找到年月的「選擇」連結 agent-browser click @eXX # 選擇對應年月 # 進入報表頁 /Hours/Report agent-browser wait 1500 # 下載 PDF agent-browser pdf ~/Downloads/workhour_115_01.pdf
完整流程(從頭開始)
如果需要從頭開始下載特定計畫的工時紀錄表:
# 1. 開啟並登入 agent-browser close 2>/dev/null; sleep 1 agent-browser open https://gaweb.nutn.edu.tw/workhour/Budget --headed # (執行登入流程...) # 2. 選擇計畫(在 /Budget 頁面) agent-browser snapshot -i agent-browser click @eXX # 點擊目標計畫的「選擇」連結 # 3. 點擊列印按鈕(在 /Hours/Create 頁面) agent-browser wait 1500 agent-browser snapshot -i agent-browser click @eXX # 「列印工時紀錄表」按鈕 # 4. 選擇年月(在 /Hours/Report2 頁面) agent-browser wait 1500 agent-browser snapshot -i agent-browser click @eXX # 選擇對應年月 # 5. 下載 PDF(在 /Hours/Report 頁面) agent-browser wait 1500 agent-browser pdf ~/Downloads/workhour_115_01.pdf
頁面流程說明
/Budget (計畫列表)
↓ 點擊「選擇」
/Hours/Create (工時填寫頁)
↓ 點擊「列印工時紀錄表」
/Hours/Report2 (年月選擇頁)
↓ 點擊年月的「選擇」
/Hours/Report (工時紀錄表) ← 在此頁面下載 PDF
注意:不可直接用 URL 跳到 /Hours/Report 或 /Hours/SetYM,系統需要 session 狀態才能顯示正確的工時紀錄表。
刪除工時記錄
系統的刪除功能需要確認對話框,使用 eval 繞過:
步驟 1:取得記錄 ID
agent-browser eval "
Array.from(document.querySelectorAll('a')).filter(a => a.textContent.includes('刪除')).map(a => ({
id: a.name,
onclick: a.getAttribute('onclick')
}));
"
步驟 2:執行刪除
# 設定要刪除的 ID 並調用刪除函數
agent-browser eval "document.querySelector('#hiddenEmployeeId').value = '455930'; DeleteEmployee();"
agent-browser wait 1500
# 繼續刪除下一筆...
工作類別特殊規則
| 工作類別 | 排除條件 |
|---|---|
| 夜間值班(協助普通教室夜間值班、協助管理榮譽校區教室) | 寒假、暑假、國定假日 |
套用邏輯
- •識別工作內容關鍵字(如「夜間值班」「教室」)
- •比對特殊規則表
- •載入
academic-calendar技能取得寒假、暑假日期 - •自動排除對應日期範圍
日期計算備忘
民國年 → 西元年:+1911 西元年 → 民國年:-1911 JavaScript Date.getDay(): 0=日, 1=一, 2=二, 3=三, 4=四, 5=五, 6=六 Python datetime.weekday(): 0=一, 1=二, 2=三, 3=四, 4=五, 5=六, 6=日
重要注意事項
- •必須用程式碼驗證星期幾:分析歷史記錄時,絕對不能靠觀察猜測,必須用 JavaScript 計算
- •空計畫查舊計畫:如果目標計畫沒有歷史紀錄,要找同名的舊計畫(如 D114-03 → D115-03)分析工作模式
- •必須處理假日:載入 academic-calendar 技能取得放假日資訊
- •套用特殊規則:夜間值班需排除寒假、暑假、國定假日
- •優先使用預設值:除非使用者明確要求修改或完全沒有預設勾選,否則保留頁面預設的工作類別和內容
- •必須勾選工作類別:系統要求至少選擇一個工作類別,否則會報錯
- •日期格式:使用民國年格式(例如:115/1/5)
- •時間格式:24 小時制,使用冒號分隔(例如:17:40)
- •批次操作:逐筆執行 + wait 1500ms,不要用 async/await
- •一次性確認:用表格呈現完整計畫,不分步驟詢問
- •自動排除假日:有行事曆資料時自動排除,不詢問使用者
- •ref 不穩定時:改用
eval直接操作 DOM - •下載 PDF 需正常流程:必須透過選擇計畫 → 列印按鈕 → 選擇年月的流程,直接用 URL 會失敗
- •完成後關閉瀏覽器:任務完成後執行
agent-browser close釋放資源
系統資訊
| 頁面 | URL | 備註 |
|---|---|---|
| 登入頁面 | https://gaweb.nutn.edu.tw/workhour/Home/Login | |
| 計畫選擇 | https://gaweb.nutn.edu.tw/workhour/Budget | 登入後首頁 |
| 新增工時 | https://gaweb.nutn.edu.tw/workhour/Hours/Create | 選擇計畫後進入 |
| 報表年月選擇 | https://gaweb.nutn.edu.tw/workhour/Hours/Report2 | 點擊「列印工時紀錄表」後進入 |
| 報表頁面 | https://gaweb.nutn.edu.tw/workhour/Hours/Report | 選擇年月後進入,需 session 狀態 |
重要:報表頁面 /Hours/Report 必須透過正常流程進入,直接用 URL 會顯示計畫選擇頁。
表單欄位對應
| 欄位 ID | 用途 |
|---|---|
| WorkDay | 工作日期 |
| StartT | 開始時間 |
| EndT | 結束時間 |
| checkbox1 | 研究學習 |
| checkbox2 | 資料處理 |
| checkbox3 | 統計調查 |
| checkbox4 | 實地考察 |
| checkbox5 | 行政事務 |
| checkbox6 | 其他 |
| Wcontent | 工作內容(勾選非「其他」類別時使用) |
| Wother | 其他工作內容(勾選「其他」時使用) |
| buttonID | 提交按鈕 |
| hiddenEmployeeId | 刪除用的隱藏 ID 欄位 |