这是第一个包含完整工作区的提交,也是后续「拆 SFC / 上 Vite」的回滚基线。 此前的提交均为 index.html 单文件历史快照,由 .bak 文件重建。 当前状态(提交前已实测): - index.html 内联薪酬算法已删除,改调 WHTPayroll - shared/payroll.js 为唯一薪酬实现,浏览器与 Node 共用 - 对外接口未变:aggregateMonth / isCutEdge / payDayKind 等保留同名薄包装 未入库内容见 .gitignore:依赖、Chrome 验证 profile、验证截图、 运行时 sqlite 数据与日志、时间戳备份、.trash。
230 lines
7.4 KiB
JavaScript
230 lines
7.4 KiB
JavaScript
// 测试场景库 —— payroll 模块、index.html 基准、重构后对照三方共用同一批数据。
|
|
//
|
|
// 为什么单独一个文件:基准快照与重构后的实测必须喂**完全相同**的输入,
|
|
// 否则对不上时分不清是「代码变了」还是「测试数据变了」。
|
|
'use strict';
|
|
|
|
const W = (h, extra) => Object.assign({
|
|
status: 'work', shift_type: 'day', hours: h,
|
|
contraband_found: 0, contraband_missed: 0, other_penalty: null, penalty_reason: ''
|
|
}, extra || {});
|
|
|
|
const FINAL = (mk, amount) => ({
|
|
[mk]: { status: 'final', finalAmount: amount, note: '', finalizedAt: '2026-10-01T09:00:00.000Z' }
|
|
});
|
|
const DRAFT = (mk, amount) => ({
|
|
[mk]: { status: 'draft', finalAmount: amount, note: '', finalizedAt: '' }
|
|
});
|
|
|
|
/** 满勤月:1–N 日全上白班 8h */
|
|
function fullMonth(days, hours) {
|
|
const rec = {};
|
|
for (let d = 1; d <= days; d++) rec[`2026-09-${String(d).padStart(2, '0')}`] = W(hours === undefined ? 8 : hours);
|
|
return rec;
|
|
}
|
|
|
|
// 冻结的「现在」:不冻结的话 payDayAPassed / isCurrentMonth / 今日高亮
|
|
// 每天跑出来都不一样,基准 JSON 根本没法比。
|
|
// 取 2026-09-20 是刻意的:已过 payDayA(22)? 没过 —— 正好覆盖「上半月待发」这一支。
|
|
const NOW = '2026-09-20T10:00:00+08:00';
|
|
|
|
/**
|
|
* 每个场景都会被喂给三方:纯模块、重构前的 index.html、重构后的 index.html。
|
|
* 覆盖目标:12 个薪酬 computed 的全部分支。
|
|
*/
|
|
const SCENARIOS = [
|
|
{
|
|
name: '基础分段·上下半月各2天无奖惩',
|
|
records: { '2026-09-03': W(8), '2026-09-14': W(8), '2026-09-20': W(10), '2026-09-28': W(10) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '边界·15日算上半月/16日算下半月',
|
|
records: { '2026-09-15': W(12), '2026-09-16': W(12) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '夜班跨天·15日夜班10h整段进上半月',
|
|
records: { '2026-09-15': W(10, { shift_type: 'night' }) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '满勤达标·27天×8h',
|
|
records: fullMonth(27),
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '差1天不满勤·26天×8h',
|
|
records: fullMonth(26),
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '奖惩四项归集·未定稿只记录',
|
|
records: {
|
|
'2026-09-05': W(8, { contraband_found: 3 }),
|
|
'2026-09-20': W(8, { contraband_missed: 2 }),
|
|
'2026-09-25': W(8, { other_penalty: 50, penalty_reason: '迟到' })
|
|
},
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '奖惩已定稿-60',
|
|
records: {
|
|
'2026-09-05': W(8, { contraband_found: 3 }),
|
|
'2026-09-20': W(8, { contraband_missed: 2 }),
|
|
'2026-09-25': W(8, { other_penalty: 50, penalty_reason: '迟到' })
|
|
},
|
|
year: 2026, month: 8, adjust: FINAL('2026-09', -60)
|
|
},
|
|
{
|
|
name: '草稿不生效·draft+30',
|
|
records: { '2026-09-05': W(8, { contraband_found: 3 }) },
|
|
year: 2026, month: 8, adjust: DRAFT('2026-09', 30)
|
|
},
|
|
{
|
|
name: '审核改数·累计+30只认+20',
|
|
records: { '2026-09-05': W(8, { contraband_found: 3 }) },
|
|
year: 2026, month: 8, adjust: FINAL('2026-09', 20)
|
|
},
|
|
{
|
|
name: '跨月结转·8月未定稿',
|
|
records: {
|
|
'2026-08-10': W(8),
|
|
'2026-08-18': W(10), '2026-08-22': W(10),
|
|
'2026-08-27': W(10, { contraband_found: 5, contraband_missed: 1 }),
|
|
'2026-09-02': W(8), '2026-09-09': W(8)
|
|
},
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '跨月结转·8月已定稿+30',
|
|
records: {
|
|
'2026-08-10': W(8),
|
|
'2026-08-18': W(10), '2026-08-22': W(10),
|
|
'2026-08-27': W(10, { contraband_found: 5, contraband_missed: 1 }),
|
|
'2026-09-02': W(8), '2026-09-09': W(8)
|
|
},
|
|
year: 2026, month: 8, adjust: FINAL('2026-08', 30)
|
|
},
|
|
{
|
|
name: '跨年边界·2026年1月取2025年12月',
|
|
records: {
|
|
'2025-12-20': W(10), '2025-12-28': W(10, { contraband_found: 2 }),
|
|
'2026-01-05': W(8)
|
|
},
|
|
year: 2026, month: 0
|
|
},
|
|
{
|
|
name: '跨年边界·2025-12已定稿+20',
|
|
records: {
|
|
'2025-12-20': W(10), '2025-12-28': W(10, { contraband_found: 2 }),
|
|
'2026-01-05': W(8)
|
|
},
|
|
year: 2026, month: 0, adjust: FINAL('2025-12', 20)
|
|
},
|
|
{
|
|
name: '处罚超过下半月工资·未定稿',
|
|
records: { '2026-09-20': W(6, { contraband_missed: 10, other_penalty: 200 }) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '处罚超过下半月工资·定稿-400触发地板0',
|
|
records: { '2026-09-20': W(6, { contraband_missed: 10, other_penalty: 200 }) },
|
|
year: 2026, month: 8, adjust: FINAL('2026-09', -400)
|
|
},
|
|
{
|
|
name: '休息请假不计工时',
|
|
records: {
|
|
'2026-09-03': W(8),
|
|
'2026-09-04': { status: 'rest' },
|
|
'2026-09-05': { status: 'leave' },
|
|
'2026-09-06': { status: 'rest' }
|
|
},
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '脏数据·其他扣款负数夹为0',
|
|
records: { '2026-09-20': W(8, { other_penalty: -500 }) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '月份隔离·不串月',
|
|
records: { '2026-08-05': W(12), '2026-10-05': W(12), '2026-09-05': W(8) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '自定义设置·时薪30/满勤20/单价2/截止10/发薪25与5',
|
|
records: (() => {
|
|
const rec = {};
|
|
for (let d = 1; d <= 20; d++) rec[`2026-09-${String(d).padStart(2, '0')}`] = W(10);
|
|
return rec;
|
|
})(),
|
|
year: 2026, month: 8,
|
|
settings: { rate: 30, fullDays: 20, fullBonusPerHour: 2, cutoff: 10, payDayA: 25, payDayB: 5 }
|
|
},
|
|
{
|
|
name: '非法设置全部回落默认',
|
|
records: { '2026-09-05': W(8) },
|
|
year: 2026, month: 8,
|
|
settings: { rate: null, fullDays: 0, fullBonusPerHour: undefined, cutoff: 99, foundBonus: -5, missedPenalty: NaN }
|
|
},
|
|
{
|
|
name: '处罚明细排序与原因',
|
|
records: {
|
|
'2026-09-25': W(8, { other_penalty: 50, penalty_reason: '迟到' }),
|
|
'2026-09-08': W(8, { contraband_missed: 2 }),
|
|
'2026-09-12': W(8, { contraband_missed: 1, other_penalty: 30 }),
|
|
'2026-09-15': W(8)
|
|
},
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '空数据不崩',
|
|
records: {},
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '越界旧值原样保留·14h与4h',
|
|
records: { '2026-09-05': W(14), '2026-09-06': W(4), '2026-09-07': W(8.5) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '用户实测场景·3天22h含查获1件未定稿',
|
|
records: { '2026-09-01': W(8), '2026-09-02': W(8), '2026-09-03': W(6, { contraband_found: 1 }) },
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '用户实测场景·同上已定稿+10',
|
|
records: { '2026-09-01': W(8), '2026-09-02': W(8), '2026-09-03': W(6, { contraband_found: 1 }) },
|
|
year: 2026, month: 8, adjust: FINAL('2026-09', 10)
|
|
},
|
|
{
|
|
name: '满勤+查获5件未定稿·满勤计奖惩不计',
|
|
records: Object.assign(fullMonth(27), { '2026-09-05': W(8, { contraband_found: 5 }) }),
|
|
year: 2026, month: 8
|
|
},
|
|
{
|
|
name: '满勤+查获5件已定稿+50·两项全计',
|
|
records: Object.assign(fullMonth(27), { '2026-09-05': W(8, { contraband_found: 5 }) }),
|
|
year: 2026, month: 8, adjust: FINAL('2026-09', 50)
|
|
},
|
|
{
|
|
name: '历史月份·看8月(payDayA 已过)',
|
|
records: { '2026-08-05': W(8), '2026-08-20': W(10) },
|
|
year: 2026, month: 7
|
|
},
|
|
{
|
|
name: '未来月份·看10月(payDayA 未过)',
|
|
records: { '2026-10-05': W(8), '2026-10-20': W(10) },
|
|
year: 2026, month: 9
|
|
},
|
|
{
|
|
name: '班次默认工时越界·白班2h夜班20h',
|
|
records: {},
|
|
year: 2026, month: 8,
|
|
settings: { dayHours: 2, nightHours: 20 }
|
|
}
|
|
];
|
|
|
|
module.exports = { W, FINAL, DRAFT, fullMonth, SCENARIOS, NOW };
|