dsh-niuma 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +6 -0
- package/docs/preview-light-dark.png +0 -0
- package/lib/client.js +814 -217
- package/lib/client.js.map +2 -2
- package/lib/index.js +48 -118
- package/package.json +3 -8
- package/src/client/index.js +623 -164
- package/src/core.mjs +88 -0
- package/src/holidays.mjs +90 -10
package/src/core.mjs
CHANGED
|
@@ -431,3 +431,91 @@ export function isStatutoryHoliday(key, config) {
|
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
export { DAY_MS };
|
|
434
|
+
|
|
435
|
+
/* ------------------------------------------------------------------ *
|
|
436
|
+
* 月度 / 全年视角(只影响「查看」,不影响今日计数器)
|
|
437
|
+
* ------------------------------------------------------------------ */
|
|
438
|
+
|
|
439
|
+
/** 某年某月里配置中的法定节假日日期数(按日期键前缀统计,无论是否落在周末)。 */
|
|
440
|
+
export function holidayDaysInMonth(year, monthIndex, config) {
|
|
441
|
+
const prefix = `${year}-${String(monthIndex + 1).padStart(2, '0')}-`;
|
|
442
|
+
return (config.holidays ?? DEFAULTS.holidays).filter((key) => key.startsWith(prefix)).length;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* 单月概览:工作日数、法定假日数、日/时/分/秒工资等。
|
|
447
|
+
*
|
|
448
|
+
* 口径与今日计数一致:月薪 / 当月工作日 = 日工资(节假日不算工作日 → 日工资更高)。
|
|
449
|
+
* @param {object} config
|
|
450
|
+
* @param {number} year
|
|
451
|
+
* @param {number} monthIndex 0-11
|
|
452
|
+
* @returns {object}
|
|
453
|
+
*/
|
|
454
|
+
export function monthSummary(config, year, monthIndex) {
|
|
455
|
+
const daysInMonth = new Date(year, monthIndex + 1, 0).getDate();
|
|
456
|
+
const workdays = workdaysInMonth(year, monthIndex, config);
|
|
457
|
+
const holidayDays = holidayDaysInMonth(year, monthIndex, config);
|
|
458
|
+
const monthlySalary = Number(config.monthlySalary) || 0;
|
|
459
|
+
const paidMinutes = paidMinutesPerDay(config);
|
|
460
|
+
const paidHours = paidMinutes / 60;
|
|
461
|
+
const dailyWage = workdays > 0 ? monthlySalary / workdays : 0;
|
|
462
|
+
const hourlyWage = paidHours > 0 ? dailyWage / paidHours : 0;
|
|
463
|
+
return {
|
|
464
|
+
year,
|
|
465
|
+
monthIndex,
|
|
466
|
+
month: monthIndex + 1,
|
|
467
|
+
daysInMonth,
|
|
468
|
+
workdays,
|
|
469
|
+
holidayDays,
|
|
470
|
+
restDays: daysInMonth - workdays,
|
|
471
|
+
monthlySalary,
|
|
472
|
+
paidMinutes,
|
|
473
|
+
paidHours,
|
|
474
|
+
dailyWage,
|
|
475
|
+
hourlyWage,
|
|
476
|
+
minuteWage: hourlyWage / 60,
|
|
477
|
+
secondWage: hourlyWage / 3600,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* 全年概览:12 个月汇总 + 全年平均工资 + 法定假日最多的月份。
|
|
483
|
+
*
|
|
484
|
+
* 「全年平均」口径:年收入 = 实收月薪 × 12;平均日薪 = 年收入 / 全年工作日;
|
|
485
|
+
* 平均时薪 = 平均日薪 / 日有效工时。平均月薪 = 实收月薪(不因月份浮动)。
|
|
486
|
+
* @param {object} config
|
|
487
|
+
* @param {number} year
|
|
488
|
+
* @returns {object}
|
|
489
|
+
*/
|
|
490
|
+
export function yearSummary(config, year) {
|
|
491
|
+
const months = Array.from({ length: 12 }, (_, monthIndex) => monthSummary(config, year, monthIndex));
|
|
492
|
+
const totalWorkdays = months.reduce((sum, item) => sum + item.workdays, 0);
|
|
493
|
+
const totalHolidayDays = months.reduce((sum, item) => sum + item.holidayDays, 0);
|
|
494
|
+
const monthlySalary = Number(config.monthlySalary) || 0;
|
|
495
|
+
const annualIncome = monthlySalary * 12;
|
|
496
|
+
const paidMinutes = paidMinutesPerDay(config);
|
|
497
|
+
const paidHours = paidMinutes / 60;
|
|
498
|
+
const averageDailyWage = totalWorkdays > 0 ? annualIncome / totalWorkdays : 0;
|
|
499
|
+
const averageHourlyWage = paidHours > 0 ? averageDailyWage / paidHours : 0;
|
|
500
|
+
const maxHolidayMonth = months.reduce((best, item) => {
|
|
501
|
+
if (item.holidayDays !== best.holidayDays) return item.holidayDays > best.holidayDays ? item : best;
|
|
502
|
+
if (item.workdays !== best.workdays) return item.workdays < best.workdays ? item : best;
|
|
503
|
+
return item.month < best.month ? item : best;
|
|
504
|
+
}, months[0]);
|
|
505
|
+
return {
|
|
506
|
+
year,
|
|
507
|
+
months,
|
|
508
|
+
totalWorkdays,
|
|
509
|
+
totalHolidayDays,
|
|
510
|
+
paidMinutes,
|
|
511
|
+
paidHours,
|
|
512
|
+
monthlySalary,
|
|
513
|
+
annualIncome,
|
|
514
|
+
averageMonthlyWage: monthlySalary,
|
|
515
|
+
averageDailyWage,
|
|
516
|
+
averageHourlyWage,
|
|
517
|
+
averageMinuteWage: averageHourlyWage / 60,
|
|
518
|
+
averageSecondWage: averageHourlyWage / 3600,
|
|
519
|
+
maxHolidayMonth,
|
|
520
|
+
};
|
|
521
|
+
}
|
package/src/holidays.mjs
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 中国法定节假日与调休上班日(纯数据,宿主 + 浏览器共用)。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* 数据分两部分:
|
|
5
|
+
* 1. **2026 官方数据**:国务院办公厅《关于2026年部分节假日安排的通知》(国办发明电〔2025〕7号),
|
|
6
|
+
* 发布日期 2025-11-04,逐条核对自官方原文:
|
|
7
|
+
* https://www.gov.cn/zhengce/content/202511/content_7047090.htm
|
|
8
|
+
* 2. **2027 预估数据**(`HOLIDAY_ESTIMATE_2027.estimated === true`,**官方尚未公布**):
|
|
9
|
+
* 按 2024 年修订的《全国年节及纪念日放假办法》与往年惯例推算,仅用于提前查看;
|
|
10
|
+
* 官方通知发布后(往年 11 月初)替换为正式数据并升版本。
|
|
9
11
|
*
|
|
10
12
|
* @module dsh-niuma/holidays
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
/* ------------------------------------------------------------------ *
|
|
16
|
+
* 2026 官方数据
|
|
17
|
+
* ------------------------------------------------------------------ */
|
|
18
|
+
|
|
19
|
+
/** 2026 年法定放假日期(含与周末顺连的休息日;这些日期一律不算工作日) */
|
|
20
|
+
export const OFFICIAL_HOLIDAYS_2026 = Object.freeze([
|
|
15
21
|
// 元旦:1月1日(周四)至3日(周六)
|
|
16
22
|
'2026-01-01', '2026-01-02', '2026-01-03',
|
|
17
23
|
// 春节:2月15日(周日)至23日(周一),共 9 天
|
|
@@ -31,7 +37,7 @@ export const DEFAULT_HOLIDAYS = Object.freeze([
|
|
|
31
37
|
]);
|
|
32
38
|
|
|
33
39
|
/** 2026 年调休上班日(周末补班,算工作日) */
|
|
34
|
-
export const
|
|
40
|
+
export const OFFICIAL_EXTRA_WORKDAYS_2026 = Object.freeze([
|
|
35
41
|
'2026-01-04', // 元旦调休:周日上班
|
|
36
42
|
'2026-02-14', // 春节调休:周六上班
|
|
37
43
|
'2026-02-28', // 春节调休:周六上班
|
|
@@ -40,9 +46,83 @@ export const DEFAULT_EXTRA_WORKDAYS = Object.freeze([
|
|
|
40
46
|
'2026-10-10', // 国庆调休:周六上班
|
|
41
47
|
]);
|
|
42
48
|
|
|
43
|
-
/**
|
|
49
|
+
/** 2026 年七个法定节假日区段(面板「节假日」卡片用,与上面逐段对应) */
|
|
50
|
+
export const HOLIDAY_BLOCKS = Object.freeze([
|
|
51
|
+
{ id: 'newYear', year: 2026, from: '2026-01-01', to: '2026-01-03', days: 3, estimated: false },
|
|
52
|
+
{ id: 'spring', year: 2026, from: '2026-02-15', to: '2026-02-23', days: 9, estimated: false },
|
|
53
|
+
{ id: 'qingming', year: 2026, from: '2026-04-04', to: '2026-04-06', days: 3, estimated: false },
|
|
54
|
+
{ id: 'labour', year: 2026, from: '2026-05-01', to: '2026-05-05', days: 5, estimated: false },
|
|
55
|
+
{ id: 'dragon', year: 2026, from: '2026-06-19', to: '2026-06-21', days: 3, estimated: false },
|
|
56
|
+
{ id: 'midAutumn', year: 2026, from: '2026-09-25', to: '2026-09-27', days: 3, estimated: false },
|
|
57
|
+
{ id: 'national', year: 2026, from: '2026-10-01', to: '2026-10-07', days: 7, estimated: false },
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
/** 2026 官方数据出处,面板脚注展示用 */
|
|
44
61
|
export const HOLIDAY_SOURCE = Object.freeze({
|
|
45
62
|
year: 2026,
|
|
63
|
+
estimated: false,
|
|
46
64
|
title: '国务院办公厅关于2026年部分节假日安排的通知(国办发明电〔2025〕7号)',
|
|
47
65
|
url: 'https://www.gov.cn/zhengce/content/202511/content_7047090.htm',
|
|
48
66
|
});
|
|
67
|
+
|
|
68
|
+
/* ------------------------------------------------------------------ *
|
|
69
|
+
* 2027 预估数据(官方未公布,仅按规则与惯例推算)
|
|
70
|
+
* ------------------------------------------------------------------ */
|
|
71
|
+
|
|
72
|
+
/** 2027 年放假日期(预估):元旦 3 天 / 春节 9 天 / 清明 3 天 / 劳动 5 天 / 端午 1 天 / 中秋 1 天 / 国庆 7 天 */
|
|
73
|
+
export const ESTIMATED_HOLIDAYS_2027 = Object.freeze([
|
|
74
|
+
'2027-01-01', '2027-01-02', '2027-01-03',
|
|
75
|
+
'2027-02-05', '2027-02-06', '2027-02-07', '2027-02-08', '2027-02-09',
|
|
76
|
+
'2027-02-10', '2027-02-11', '2027-02-12', '2027-02-13',
|
|
77
|
+
'2027-04-03', '2027-04-04', '2027-04-05',
|
|
78
|
+
'2027-05-01', '2027-05-02', '2027-05-03', '2027-05-04', '2027-05-05',
|
|
79
|
+
'2027-06-09',
|
|
80
|
+
'2027-09-15',
|
|
81
|
+
'2027-10-01', '2027-10-02', '2027-10-03', '2027-10-04', '2027-10-05',
|
|
82
|
+
'2027-10-06', '2027-10-07',
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
/** 2027 年调休上班日(预估,周末补班) */
|
|
86
|
+
export const ESTIMATED_EXTRA_WORKDAYS_2027 = Object.freeze([
|
|
87
|
+
'2027-01-31', // 春节调休:周日上班(预估)
|
|
88
|
+
'2027-02-14', // 春节调休:周日上班(预估)
|
|
89
|
+
'2027-05-08', // 劳动节调休:周六上班(预估)
|
|
90
|
+
'2027-09-26', // 国庆调休:周日上班(预估)
|
|
91
|
+
'2027-10-09', // 国庆调休:周六上班(预估)
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
/** 2027 年七个法定节假日区段(预估;`estimated: true` 用于面板标注) */
|
|
95
|
+
export const HOLIDAY_BLOCKS_2027_ESTIMATED = Object.freeze([
|
|
96
|
+
{ id: 'newYear', year: 2027, from: '2027-01-01', to: '2027-01-03', days: 3, estimated: true },
|
|
97
|
+
{ id: 'spring', year: 2027, from: '2027-02-05', to: '2027-02-13', days: 9, estimated: true },
|
|
98
|
+
{ id: 'qingming', year: 2027, from: '2027-04-03', to: '2027-04-05', days: 3, estimated: true },
|
|
99
|
+
{ id: 'labour', year: 2027, from: '2027-05-01', to: '2027-05-05', days: 5, estimated: true },
|
|
100
|
+
{ id: 'dragon', year: 2027, from: '2027-06-09', to: '2027-06-09', days: 1, estimated: true },
|
|
101
|
+
{ id: 'midAutumn', year: 2027, from: '2027-09-15', to: '2027-09-15', days: 1, estimated: true },
|
|
102
|
+
{ id: 'national', year: 2027, from: '2027-10-01', to: '2027-10-07', days: 7, estimated: true },
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
/** 2027 预估数据的出处与免责说明(面板必须显著标注「预估」) */
|
|
106
|
+
export const HOLIDAY_ESTIMATE_2027 = Object.freeze({
|
|
107
|
+
year: 2027,
|
|
108
|
+
estimated: true,
|
|
109
|
+
announced: false,
|
|
110
|
+
title: '2027 年放假安排(预估,官方尚未公布)',
|
|
111
|
+
note: '官方通知通常在前一年 11 月初发布;以下为按 2024 年修订的《全国年节及纪念日放假办法》与往年惯例推算,仅供参考,请以国务院通知为准。',
|
|
112
|
+
basis: [
|
|
113
|
+
'春节自除夕起放假调休,一般连休 8–9 天',
|
|
114
|
+
'国庆 7 天、劳动节 5 天',
|
|
115
|
+
'元旦 / 清明 / 端午 / 中秋各 1 天法定假,遇周末顺连',
|
|
116
|
+
],
|
|
117
|
+
url: 'https://www.gov.cn/zhengce/xxgk/',
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
/* ------------------------------------------------------------------ *
|
|
121
|
+
* 默认值(2026 官方 + 2027 预估;跨年也能算,但 2027 会标注预估)
|
|
122
|
+
* ------------------------------------------------------------------ */
|
|
123
|
+
|
|
124
|
+
/** 默认节假日:2026 官方 + 2027 预估 */
|
|
125
|
+
export const DEFAULT_HOLIDAYS = Object.freeze([...OFFICIAL_HOLIDAYS_2026, ...ESTIMATED_HOLIDAYS_2027]);
|
|
126
|
+
|
|
127
|
+
/** 默认调休上班日:2026 官方 + 2027 预估 */
|
|
128
|
+
export const DEFAULT_EXTRA_WORKDAYS = Object.freeze([...OFFICIAL_EXTRA_WORKDAYS_2026, ...ESTIMATED_EXTRA_WORKDAYS_2027]);
|