Compare commits

..

4 Commits

Author SHA1 Message Date
7a2ea27a25 查上上月和查上上上月改为基于当前显示月的偏移导航
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 11:25:47 +08:00
9fc1e8633d 动态月份导航:查上月/查下月基于当前显示月翻页,新增年月选择器
- currentMonthOffset 追踪当前显示月份的偏移量
- navigateMonth(delta) 支持逐月翻看历史,可反复点击跨年
- 查当月重置偏移为 0
- 新增年月选择器(年份 + 月份下拉 + 查询按钮),放在按钮末尾
- queryByYearMonth 根据选中年月计算考勤周期并查询

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 11:20:18 +08:00
b9f41191ab 新增查下月按钮,优化按钮悬停效果
- 新增"查下月"按钮(getCustomMonthRange(-1))
- 按钮按逻辑排列:查当下 → 查下月 → 查上月 → 查上上月 → 查上上上月
- 按钮 hover 时颜色变亮 + 底部淡白底线,增加 transition 过渡
- 增大 padding 到 14px,按钮间距更舒适

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 21:47:30 +08:00
c35b60b496 添加 @updateURL/@downloadURL,支持脚本猫/Tampermonkey 自动更新
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 20:08:13 +08:00
2 changed files with 242 additions and 16 deletions

129
main.js
View File

@@ -1,10 +1,12 @@
// ==UserScript==
// @name 复旦微加班时间统计
// @namespace http://start.fengbohan.com/
// @version 2026-01-28
// @description 更新2026年的节假日数据
// @version 2026-05-22
// @description 更新2026年的节假日数据新增查当周、MyTools联动
// @author bhfeng
// @match http://192.168.36.67:7888/shr/dynamic.do?uipk=com.kingdee.eas.hr.ats.app.WorkCalendarItem*
// @updateURL https://gitea.fengbohan.com/fengbh/FM-OHS/raw/branch/main/main.js
// @downloadURL https://gitea.fengbohan.com/fengbh/FM-OHS/raw/branch/main/main.js
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAdVBMVEX///////7+/v4kVZ729/lafbO2xd3x8/f5+vz8/Pzd4+4tW6GSp8xnh7nP2OgxXqLK1OZ1kb/s7/UgUZytvdhKcKw+aKgaTZlhgrbU3eqar9Dm6fFVd7CEnsZwjb4VSZfAy+BCbKq3xd58l8OXrM6nudaMo8kyjkGlAAABfklEQVQokT1Si5arIBCLDIqCiogP8FHtWvv/n3iH7vZyDjDMQAIJwLdlpVIlz0L8T0FAxDaTy5JBrWn52ZhxoO6tQ+ZyjT7fJSqRpYJAJte8qbDPmxKPY4vgXOqdhramwzp6B1GTKRJahjjVVdlQI3FauiTahkOmFfHyJ9qJduC2lHf4o69weiZYyLyAYvLWFe3O1apHa80AsZOpGfdhZrLHDfSDwpumFuVO5HqI8xot3xvrM5Qy+DGiqo3fTgbvteRRT36AHmlk2J/R26vlbHmuiMVrWtOlpoGPX2a2wV3BMjQiNSXakezVA50zfvbHyGTMQlcFnRNtRQXEl3u4lklWVRi6FNRuyTRD/5E7sXehvIlCBM6c3zBed3E/dNKqCdlg/bRIlENj/XHMxztphdUGxNxTKNhAPbz3/edjlEC0uRTLc6b81syu5K8fPOhxKtAvm5/NMw/vNRNfy1U9hUKpbnFNsyh8v0Pa0A/O1SyE+LrxV6mSdjH2gsPf/D//7BjTQny+YwAAAABJRU5ErkJggg==
// @grant none
// @run-at document-idle
@@ -22115,6 +22117,9 @@ const workDayData = {
const QUERY_DELAY_MS = 500;
const MYTOOLS_BASE = 'https://mytools.fengbohan.com';
// 当前显示月份的偏移量0=当月周期,正数=往前翻,负数=往后翻)
let currentMonthOffset = 0;
// 加班配置(默认值,启动时尝试从 MyTools 拉取)
let overtimeConfig = { overtime_start: '17:20', weekly_target: 18 };
@@ -22251,13 +22256,26 @@ const workDayData = {
display: "block",
lineHeight: "60px",
height: "60px",
padding: "0px 10px",
padding: "0px 14px",
textDecoration: "none",
color: "#e5e5e5",
cursor: "pointer",
border: "none",
borderBottom: "2px solid transparent",
transition: "color 0.15s, border-bottom-color 0.15s",
outline: "none",
};
Object.assign(button.style, copiedStyles);
button.addEventListener('mouseenter', () => {
button.style.color = "#fff";
button.style.borderBottomColor = "rgba(255,255,255,0.4)";
});
button.addEventListener('mouseleave', () => {
button.style.color = "#e5e5e5";
button.style.borderBottomColor = "transparent";
});
// 处理点击事件回调
if (typeof options.onClick === 'function') {
button.addEventListener('click', options.onClick);
@@ -22304,6 +22322,52 @@ const workDayData = {
};
}
// 基于当前偏移量动态导航月份(反复点击可逐月翻看历史)
function navigateMonth(delta) {
currentMonthOffset += delta;
const range = getCustomMonthRange(currentMonthOffset);
console.log(`navigateMonth offset=${currentMonthOffset}: ${range.firstDay} ~ ${range.lastDay}`);
simulateDateInput('beginDate', range.firstDay);
simulateDateInput('endDate', range.lastDay);
queryButton.click();
setTimeout(() => get_work_time(), QUERY_DELAY_MS);
}
// 根据指定年月查询考勤周期上月21 ~ 本月20
function queryByYearMonth(year, month) {
const formatLocal = (date) => {
return date.toLocaleDateString('en-CA', {
year: 'numeric', month: '2-digit', day: '2-digit'
}).replace(/\//g, '-');
};
// 考勤周期当月21日 至 次月20日
let startMonth = month - 1; // JS month: 0-indexed
let startYear = year;
const firstDay = new Date(startYear, startMonth, 21);
let endYear = year, endMonth = month;
if (endMonth > 11) { endMonth -= 12; endYear++; }
const lastDay = new Date(endYear, endMonth, 20);
// 推算偏移量,让后续 navigateMonth 能正确工作
const now = new Date();
const currentCycleStart = getCustomMonthRange(0).firstDay;
const targetFirst = formatLocal(firstDay);
// 近似:计算目标月与当前月的月份差
const monthDiff = (now.getFullYear() - year) * 12 + (now.getMonth() + 1) - month;
const day = now.getDate();
if (day >= 21) {
currentMonthOffset = monthDiff;
} else {
currentMonthOffset = monthDiff - 1;
}
console.log(`queryByYearMonth ${year}-${month}: ${targetFirst} ~ ${formatLocal(lastDay)}`);
simulateDateInput('beginDate', targetFirst);
simulateDateInput('endDate', formatLocal(lastDay));
queryButton.click();
setTimeout(() => get_work_time(), QUERY_DELAY_MS);
}
// 查询工作时间
function get_work_time() {
const totalSum = sumOfSecondColumn('grid');
@@ -22333,10 +22397,14 @@ const workDayData = {
}
});
const button4 = createQueryButton('查当周', getCurrentWeekRange);
const button0 = createQueryButton('查当月', () => getCustomMonthRange(0));
const button1 = createQueryButton('查上月', () => getCustomMonthRange(1));
const button2 = createQueryButton('查上上月', () => getCustomMonthRange(2));
const button3 = createQueryButton('查上上上月', () => getCustomMonthRange(3));
const button0 = createQueryButton('查当月', () => {
currentMonthOffset = 0;
navigateMonth(0);
});
const buttonNext = createQueryButton('查下月', () => navigateMonth(-1));
const buttonPrev = createQueryButton('查上月', () => navigateMonth(1));
const button2 = createQueryButton('查上上月', () => navigateMonth(2));
const button3 = createQueryButton('查上上上月', () => navigateMonth(3));
// 获取要将按钮添加到其中的容器
let container = document.getElementById('seclevelmenu');
@@ -22346,9 +22414,54 @@ const workDayData = {
container.appendChild(button);
container.appendChild(button4);
container.appendChild(button0);
container.appendChild(button1);
container.appendChild(buttonNext);
container.appendChild(buttonPrev);
container.appendChild(button2);
container.appendChild(button3);
// 年月选择器
(function createYearMonthSelector() {
const wrapper = document.createElement('span');
wrapper.style.cssText = 'display:inline-flex;align-items:center;gap:4px;margin:0 8px;';
const yearSel = document.createElement('select');
yearSel.id = 'fmohs-year';
const thisYear = new Date().getFullYear();
for (let y = 2024; y <= thisYear + 1; y++) {
const opt = document.createElement('option');
opt.value = y; opt.textContent = y + '年';
if (y === thisYear) opt.selected = true;
yearSel.appendChild(opt);
}
yearSel.style.cssText = 'padding:2px 6px;font-size:12px;border:1px solid #666;border-radius:3px;background:#333;color:#e5e5e5;font-family:inherit;cursor:pointer;';
const monthSel = document.createElement('select');
monthSel.id = 'fmohs-month';
for (let m = 1; m <= 12; m++) {
const opt = document.createElement('option');
opt.value = m; opt.textContent = m + '月';
if (m === new Date().getMonth() + 1) opt.selected = true;
monthSel.appendChild(opt);
}
monthSel.style.cssText = yearSel.style.cssText;
const queryBtn = document.createElement('button');
queryBtn.textContent = '查询';
queryBtn.style.cssText = 'padding:2px 12px;font-size:12px;color:#e5e5e5;background:transparent;border:1px solid #666;border-radius:3px;cursor:pointer;font-family:inherit;transition:color 0.15s,border-color 0.15s;';
queryBtn.addEventListener('mouseenter', () => { queryBtn.style.color = '#fff'; queryBtn.style.borderColor = '#999'; });
queryBtn.addEventListener('mouseleave', () => { queryBtn.style.color = '#e5e5e5'; queryBtn.style.borderColor = '#666'; });
queryBtn.addEventListener('click', () => {
const y = parseInt(yearSel.value);
const m = parseInt(monthSel.value);
queryByYearMonth(y, m);
});
wrapper.appendChild(yearSel);
wrapper.appendChild(monthSel);
wrapper.appendChild(queryBtn);
container.appendChild(wrapper);
})();
console.log("复旦微加班时间统计脚本已加载");
console.log("点击按钮后会统计加班时间");

View File

@@ -1,10 +1,12 @@
// ==UserScript==
// @name 复旦微加班时间统计
// @namespace http://start.fengbohan.com/
// @version 2026-01-28
// @description 更新2026年的节假日数据
// @version 2026-05-22
// @description 更新2026年的节假日数据新增查当周、MyTools联动
// @author bhfeng
// @match http://192.168.36.67:7888/shr/dynamic.do?uipk=com.kingdee.eas.hr.ats.app.WorkCalendarItem*
// @updateURL https://gitea.fengbohan.com/fengbh/FM-OHS/raw/branch/main/main.js
// @downloadURL https://gitea.fengbohan.com/fengbh/FM-OHS/raw/branch/main/main.js
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAdVBMVEX///////7+/v4kVZ729/lafbO2xd3x8/f5+vz8/Pzd4+4tW6GSp8xnh7nP2OgxXqLK1OZ1kb/s7/UgUZytvdhKcKw+aKgaTZlhgrbU3eqar9Dm6fFVd7CEnsZwjb4VSZfAy+BCbKq3xd58l8OXrM6nudaMo8kyjkGlAAABfklEQVQokT1Si5arIBCLDIqCiogP8FHtWvv/n3iH7vZyDjDMQAIJwLdlpVIlz0L8T0FAxDaTy5JBrWn52ZhxoO6tQ+ZyjT7fJSqRpYJAJte8qbDPmxKPY4vgXOqdhramwzp6B1GTKRJahjjVVdlQI3FauiTahkOmFfHyJ9qJduC2lHf4o69weiZYyLyAYvLWFe3O1apHa80AsZOpGfdhZrLHDfSDwpumFuVO5HqI8xot3xvrM5Qy+DGiqo3fTgbvteRRT36AHmlk2J/R26vlbHmuiMVrWtOlpoGPX2a2wV3BMjQiNSXakezVA50zfvbHyGTMQlcFnRNtRQXEl3u4lklWVRi6FNRuyTRD/5E7sXehvIlCBM6c3zBed3E/dNKqCdlg/bRIlENj/XHMxztphdUGxNxTKNhAPbz3/edjlEC0uRTLc6b81syu5K8fPOhxKtAvm5/NMw/vNRNfy1U9hUKpbnFNsyh8v0Pa0A/O1SyE+LrxV6mSdjH2gsPf/D//7BjTQny+YwAAAABJRU5ErkJggg==
// @grant none
// @run-at document-idle
@@ -192,6 +194,9 @@
const QUERY_DELAY_MS = 500;
const MYTOOLS_BASE = 'https://mytools.fengbohan.com';
// 当前显示月份的偏移量0=当月周期,正数=往前翻,负数=往后翻)
let currentMonthOffset = 0;
// 加班配置(默认值,启动时尝试从 MyTools 拉取)
let overtimeConfig = { overtime_start: '17:20', weekly_target: 18 };
@@ -328,13 +333,26 @@
display: "block",
lineHeight: "60px",
height: "60px",
padding: "0px 10px",
padding: "0px 14px",
textDecoration: "none",
color: "#e5e5e5",
cursor: "pointer",
border: "none",
borderBottom: "2px solid transparent",
transition: "color 0.15s, border-bottom-color 0.15s",
outline: "none",
};
Object.assign(button.style, copiedStyles);
button.addEventListener('mouseenter', () => {
button.style.color = "#fff";
button.style.borderBottomColor = "rgba(255,255,255,0.4)";
});
button.addEventListener('mouseleave', () => {
button.style.color = "#e5e5e5";
button.style.borderBottomColor = "transparent";
});
// 处理点击事件回调
if (typeof options.onClick === 'function') {
button.addEventListener('click', options.onClick);
@@ -381,6 +399,52 @@
};
}
// 基于当前偏移量动态导航月份(反复点击可逐月翻看历史)
function navigateMonth(delta) {
currentMonthOffset += delta;
const range = getCustomMonthRange(currentMonthOffset);
console.log(`navigateMonth offset=${currentMonthOffset}: ${range.firstDay} ~ ${range.lastDay}`);
simulateDateInput('beginDate', range.firstDay);
simulateDateInput('endDate', range.lastDay);
queryButton.click();
setTimeout(() => get_work_time(), QUERY_DELAY_MS);
}
// 根据指定年月查询考勤周期上月21 ~ 本月20
function queryByYearMonth(year, month) {
const formatLocal = (date) => {
return date.toLocaleDateString('en-CA', {
year: 'numeric', month: '2-digit', day: '2-digit'
}).replace(/\//g, '-');
};
// 考勤周期当月21日 至 次月20日
let startMonth = month - 1; // JS month: 0-indexed
let startYear = year;
const firstDay = new Date(startYear, startMonth, 21);
let endYear = year, endMonth = month;
if (endMonth > 11) { endMonth -= 12; endYear++; }
const lastDay = new Date(endYear, endMonth, 20);
// 推算偏移量,让后续 navigateMonth 能正确工作
const now = new Date();
const currentCycleStart = getCustomMonthRange(0).firstDay;
const targetFirst = formatLocal(firstDay);
// 近似:计算目标月与当前月的月份差
const monthDiff = (now.getFullYear() - year) * 12 + (now.getMonth() + 1) - month;
const day = now.getDate();
if (day >= 21) {
currentMonthOffset = monthDiff;
} else {
currentMonthOffset = monthDiff - 1;
}
console.log(`queryByYearMonth ${year}-${month}: ${targetFirst} ~ ${formatLocal(lastDay)}`);
simulateDateInput('beginDate', targetFirst);
simulateDateInput('endDate', formatLocal(lastDay));
queryButton.click();
setTimeout(() => get_work_time(), QUERY_DELAY_MS);
}
// 查询工作时间
function get_work_time() {
const totalSum = sumOfSecondColumn('grid');
@@ -410,10 +474,14 @@
}
});
const button4 = createQueryButton('查当周', getCurrentWeekRange);
const button0 = createQueryButton('查当月', () => getCustomMonthRange(0));
const button1 = createQueryButton('查上月', () => getCustomMonthRange(1));
const button2 = createQueryButton('查上上月', () => getCustomMonthRange(2));
const button3 = createQueryButton('查上上上月', () => getCustomMonthRange(3));
const button0 = createQueryButton('查当月', () => {
currentMonthOffset = 0;
navigateMonth(0);
});
const buttonNext = createQueryButton('查下月', () => navigateMonth(-1));
const buttonPrev = createQueryButton('查上月', () => navigateMonth(1));
const button2 = createQueryButton('查上上月', () => navigateMonth(2));
const button3 = createQueryButton('查上上上月', () => navigateMonth(3));
// 获取要将按钮添加到其中的容器
let container = document.getElementById('seclevelmenu');
@@ -423,9 +491,54 @@
container.appendChild(button);
container.appendChild(button4);
container.appendChild(button0);
container.appendChild(button1);
container.appendChild(buttonNext);
container.appendChild(buttonPrev);
container.appendChild(button2);
container.appendChild(button3);
// 年月选择器
(function createYearMonthSelector() {
const wrapper = document.createElement('span');
wrapper.style.cssText = 'display:inline-flex;align-items:center;gap:4px;margin:0 8px;';
const yearSel = document.createElement('select');
yearSel.id = 'fmohs-year';
const thisYear = new Date().getFullYear();
for (let y = 2024; y <= thisYear + 1; y++) {
const opt = document.createElement('option');
opt.value = y; opt.textContent = y + '年';
if (y === thisYear) opt.selected = true;
yearSel.appendChild(opt);
}
yearSel.style.cssText = 'padding:2px 6px;font-size:12px;border:1px solid #666;border-radius:3px;background:#333;color:#e5e5e5;font-family:inherit;cursor:pointer;';
const monthSel = document.createElement('select');
monthSel.id = 'fmohs-month';
for (let m = 1; m <= 12; m++) {
const opt = document.createElement('option');
opt.value = m; opt.textContent = m + '月';
if (m === new Date().getMonth() + 1) opt.selected = true;
monthSel.appendChild(opt);
}
monthSel.style.cssText = yearSel.style.cssText;
const queryBtn = document.createElement('button');
queryBtn.textContent = '查询';
queryBtn.style.cssText = 'padding:2px 12px;font-size:12px;color:#e5e5e5;background:transparent;border:1px solid #666;border-radius:3px;cursor:pointer;font-family:inherit;transition:color 0.15s,border-color 0.15s;';
queryBtn.addEventListener('mouseenter', () => { queryBtn.style.color = '#fff'; queryBtn.style.borderColor = '#999'; });
queryBtn.addEventListener('mouseleave', () => { queryBtn.style.color = '#e5e5e5'; queryBtn.style.borderColor = '#666'; });
queryBtn.addEventListener('click', () => {
const y = parseInt(yearSel.value);
const m = parseInt(monthSel.value);
queryByYearMonth(y, m);
});
wrapper.appendChild(yearSel);
wrapper.appendChild(monthSel);
wrapper.appendChild(queryBtn);
container.appendChild(wrapper);
})();
console.log("复旦微加班时间统计脚本已加载");
console.log("点击按钮后会统计加班时间");