wukong-gitlog-cli 0.0.8 → 0.0.10

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 CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [0.0.10](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v0.0.9...v0.0.10) (2025-11-28)
6
+
7
+
8
+ ### Features
9
+
10
+ * 🎸 each hour percent ([4f1a7e7](https://github.com/tomatobybike/wukong-gitlog-cli/commit/4f1a7e75a1c0d83c92aabf42e97932421c349b8d))
11
+ * 🎸 hourline ([9035ecb](https://github.com/tomatobybike/wukong-gitlog-cli/commit/9035ecb33295fa5f4ff64bbd9b9281c543247683))
12
+
13
+ ### [0.0.9](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v0.0.8...v0.0.9) (2025-11-28)
14
+
5
15
  ### [0.0.8](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v0.0.7...v0.0.8) (2025-11-28)
6
16
 
7
17
 
package/README.md CHANGED
@@ -92,20 +92,20 @@ Command-line options:
92
92
  You can generate per-month and per-week outputs under `output/month/` and `output/week/` using the `--per-period-formats` option. Example:
93
93
 
94
94
  ```bash
95
- node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab
95
+ wukong-gitlog-cli ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab
96
96
  ```
97
97
 
98
98
  Want per-period Excel outputs? Use `xlsx` along with `--per-period-excel-mode` for `sheets` or `files`:
99
99
 
100
100
  ```bash
101
- node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab,xlsx --per-period-excel-mode sheets
102
- node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats xlsx --per-period-excel-mode files
101
+ wukong-gitlog-cli ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab,xlsx --per-period-excel-mode sheets
102
+ wukong-gitlog-cli ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats xlsx --per-period-excel-mode files
103
103
  ```
104
104
 
105
105
  If you'd like only per-period outputs and not the combined monthly/weekly summary files, add `--per-period-only`:
106
106
 
107
107
  ```bash
108
- node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab,xlsx --per-period-only
108
+ wukong-gitlog-cli ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab,xlsx --per-period-only
109
109
  ```
110
110
 
111
111
 
@@ -188,132 +188,12 @@ wukong-gitlog-cli --out-dir ../output --format text --limit 5 --out custom1.txt
188
188
 
189
189
  ---
190
190
 
191
- ## Quick demo (npm scripts)
192
191
 
193
- We provided a few convenient npm scripts to quickly run common scenarios. Run them from the project root:
194
-
195
- ```bash
196
- # show help
197
- npm run cli:help
198
-
199
- # simple text export (commits.txt in ./output)
200
- npm run cli:text-demo
201
-
202
- # Excel export with stats (commits.xlsx + commits.txt in ./output)
203
- npm run cli:excel-demo
204
-
205
- # JSON export (commits.json in ./output)
206
- npm run cli:json-demo
207
-
208
- # Gerrit text export demo
209
- npm run cli:gerrit-demo
210
- # Gerrit Change-Id demo (use commit Change-Id to build Gerrit URLs when present)
211
- npm run cli:gerrit-changeid-demo
212
- ```
213
-
214
- If you prefer to write output outside the project (e.g., a parent `output/` folder), we also provide `npm` scripts that run with `--out-parent`:
215
-
216
- ```bash
217
- # text export to parent `output/`
218
- npm run cli:text-demo-parent
219
-
220
- # excel export to parent `output/`
221
- npm run cli:excel-demo-parent
222
- ```
223
-
224
- Example text output (from `npm run cli:text-demo`):
225
-
226
- ```text
227
- Hash | Author | Date | Message
228
- ---------------------------------------------------------------------------------------------------------------------
229
- c5bdf9d4 | tom | 2025-11-25 | feat: 🎸 增加output目录
230
-
231
- ea82531 | tom | 2025-11-25 | feat: 🎸 init
232
-
233
- 741de50 | tom | 2025-11-25 | first commit
234
- ```
235
-
236
- You can also analyze overtime culture with the `--overtime` flag to get overall and per-person overtime submission rates (default work window is 09:00-18:00). Example:
237
192
 
238
193
  ```bash
239
194
  wukong-gitlog-cli --overtime --limit 500
240
195
  ```
241
196
 
242
- ## Overtime demo scripts (npm)
243
-
244
- Below are helpful npm scripts added for quickly running the overtime analysis with commonly used configurations. They are already present in `package.json` and can be run from the project root.
245
-
246
- ```bash
247
- # Run a US-focused overtime text report using 10:00-19:00 work hours and a 12:00-13:00 lunch break
248
- npm run cli:overtime-text-us
249
-
250
- # Run a US-focused overtime text report and write the outputs into the project parent's output folder
251
- npm run cli:overtime-text-us-parent
252
-
253
- # Run a US-focused overtime text report and write the output into ../output (explicit --out-dir)
254
- npm run cli:overtime-text-us-outdir
255
-
256
- # Run a CN-focused overtime Excel report (default 9:00-18:00 work hours and 12:00-14:00 lunch)
257
- npm run cli:overtime-excel-cn
258
-
259
- # Run a CN-focused overtime Excel report and write outputs to parent output folder
260
- npm run cli:overtime-excel-cn-parent
261
-
262
- # Run a CN-focused overtime Excel report and write outputs to ../output via --out-dir
263
- npm run cli:overtime-excel-cn-outdir
264
- # Per-period CSV/Tab export: write per-period files to output/month/ and output/week/
265
- npm run cli:overtime-per-period-csv-tab
266
- # Per-period Excel export with sheet-per-period workbook
267
- npm run cli:overtime-per-period-xlsx-sheets
268
- # Per-period Excel export with one file per period
269
- npm run cli:overtime-per-period-xlsx-files
270
- # Per-period only (no consolidated monthly/weekly files)
271
- npm run cli:overtime-per-period-only
272
- ```
273
-
274
- Notes:
275
-
276
- - Output files are written into `output/` by default. Use `--out-dir` or `--out-parent` to change output location.
277
- - If you prefer different working hours or country codes, either modify the script in `package.json` or run the CLI manually with flags (e.g. `--work-start`, `--work-end`, `--lunch-start`, `--lunch-end`, `--country`).
278
-
279
- Formatting note:
280
-
281
- - The text report is formatted to align columns correctly even when commit messages or author names contain mixed Chinese and English characters (uses `string-width` for display-aware padding).
282
-
283
- Example JSON output (from `npm run cli:json-demo`):
284
-
285
- ```json
286
- [
287
- {
288
- "hash": "c5bdf9d4f52f39bd7d580318bafc8ba4b6c129bc",
289
- "author": "tom",
290
- "email": "",
291
- "date": "2025-11-25 17:24:32 +0800",
292
- "message": "feat: 🎸 增加output目录"
293
- }
294
- /* truncated... */
295
- ]
296
- ```
297
-
298
- Example JSON output including `changeId`/`gerrit` when `--gerrit` uses `{{changeId}}` (if present in commit):
299
-
300
- ```json
301
- [
302
- {
303
- "hash": "Iabc...",
304
- "author": "tom",
305
- "email": "",
306
- "date": "2025-11-25 17:24:32 +0800",
307
- "message": "feat: add feature",
308
- "body": "feat: add feature\n\nChange-Id: Iabcd123456789",
309
- "changeId": "Iabcd123456789",
310
- "gerrit": "https://gerrit.example.com/c/project/+/Iabcd123456789"
311
- }
312
- ]
313
- ```
314
-
315
- ---
316
-
317
197
  ## Notes & Developer Info
318
198
 
319
199
  - The CLI prints helpful messages after exporting files and writes outputs to the `output/` folder in the repo root.
package/doc/help.md ADDED
@@ -0,0 +1,194 @@
1
+ ### Per-period outputs
2
+
3
+ You can generate per-month and per-week outputs under `output/month/` and `output/week/` using the `--per-period-formats` option. Example:
4
+
5
+ ```bash
6
+ node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab
7
+ ```
8
+
9
+ Want per-period Excel outputs? Use `xlsx` along with `--per-period-excel-mode` for `sheets` or `files`:
10
+
11
+ ```bash
12
+ node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab,xlsx --per-period-excel-mode sheets
13
+ node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats xlsx --per-period-excel-mode files
14
+ ```
15
+
16
+ If you'd like only per-period outputs and not the combined monthly/weekly summary files, add `--per-period-only`:
17
+
18
+ ```bash
19
+ node ./src/cli.mjs --overtime --limit 200 --format text --out commits.txt --per-period-formats csv,tab,xlsx --per-period-only
20
+ ```
21
+
22
+ ---
23
+
24
+ ## Gerrit support
25
+
26
+ Use the `--gerrit` option to include a Gerrit link for each commit. You can provide a template containing `{{hash}}` to place the full commit hash into the URL, for example:
27
+
28
+ ```bash
29
+ wukong-gitlog-cli --gerrit "https://gerrit.example.com/c/project/+/{{hash}}" --limit 5 --format text
30
+ ```
31
+
32
+ If `{{hash}}` is not present, the CLI will append the commit hash to the prefix with a `/` separator.
33
+
34
+ You can also use `{{changeId}}` in the template to reference Gerrit change id. The tool will try to extract a `Change-Id: I...` value from the commit body and replace `{{changeId}}` with it. If it can't find a `Change-Id`, the CLI will fall back to using the commit `hash`.
35
+
36
+ The Gerrit link will show up in:
37
+
38
+ - The text output if `--format text` (as a new `Gerrit` column)
39
+ - The Excel export as a `Gerrit` column if `--format excel`
40
+ - JSON output will include a `gerrit` field for each record when `--gerrit` is used
41
+ - JSON output will include a `gerrit` field for each record when `--gerrit` is used
42
+ - When `--gerrit` uses `{{changeId}}`, the CLI will try to extract `Change-Id:` from the commit body and include `changeId` and `body` in the JSON record. If no `Change-Id` is present, the CLI falls back to `hash` when forming the Gerrit URL.
43
+
44
+ Note: `--out <file>` is the filename only and the directory used to store that file depends on:
45
+
46
+ - The default directory `./output/` in the current working directory
47
+ - `--out-dir <dir>` to override the target folder (relative or absolute)
48
+ - `--out-parent` to write to the parent repository folder `../output/` (same as `--out-dir ../output`)
49
+
50
+ For example:
51
+
52
+ ```bash
53
+ # using globally installed CLI
54
+ wukong-gitlog-cli --out parent.json --out-parent
55
+ wukong-gitlog-cli --out demo.txt --out-dir ../temp
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Examples
61
+
62
+ Export as text, grouped by month, with Gerrit links:
63
+
64
+ ```bash
65
+ wukong-gitlog-cli --format text --group-by month --gerrit "https://gerrit.example.com/c/project/+/{{hash}}"
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Quick demo (npm scripts)
71
+
72
+ We provided a few convenient npm scripts to quickly run common scenarios. Run them from the project root:
73
+
74
+ ```bash
75
+ # show help
76
+ npm run cli:help
77
+
78
+ # simple text export (commits.txt in ./output)
79
+ npm run cli:text-demo
80
+
81
+ # Excel export with stats (commits.xlsx + commits.txt in ./output)
82
+ npm run cli:excel-demo
83
+
84
+ # JSON export (commits.json in ./output)
85
+ npm run cli:json-demo
86
+
87
+ # Gerrit text export demo
88
+ npm run cli:gerrit-demo
89
+ # Gerrit Change-Id demo (use commit Change-Id to build Gerrit URLs when present)
90
+ npm run cli:gerrit-changeid-demo
91
+ ```
92
+
93
+ If you prefer to write output outside the project (e.g., a parent `output/` folder), we also provide `npm` scripts that run with `--out-parent`:
94
+
95
+ ```bash
96
+ # text export to parent `output/`
97
+ npm run cli:text-demo-parent
98
+
99
+ # excel export to parent `output/`
100
+ npm run cli:excel-demo-parent
101
+ ```
102
+
103
+ Example text output (from `npm run cli:text-demo`):
104
+
105
+ ```text
106
+ Hash | Author | Date | Message
107
+ ---------------------------------------------------------------------------------------------------------------------
108
+ c5bdf9d4 | tom | 2025-11-25 | feat: 🎸 增加output目录
109
+
110
+ ea82531 | tom | 2025-11-25 | feat: 🎸 init
111
+
112
+ 741de50 | tom | 2025-11-25 | first commit
113
+ ```
114
+
115
+ You can also analyze overtime culture with the `--overtime` flag to get overall and per-person overtime submission rates (default work window is 09:00-18:00). Example:
116
+
117
+ ```bash
118
+ wukong-gitlog-cli --overtime --limit 500
119
+ ```
120
+
121
+ ## Overtime demo scripts (npm)
122
+
123
+ Below are helpful npm scripts added for quickly running the overtime analysis with commonly used configurations. They are already present in `package.json` and can be run from the project root.
124
+
125
+ ```bash
126
+ # Run a US-focused overtime text report using 10:00-19:00 work hours and a 12:00-13:00 lunch break
127
+ npm run cli:overtime-text-us
128
+
129
+ # Run a US-focused overtime text report and write the outputs into the project parent's output folder
130
+ npm run cli:overtime-text-us-parent
131
+
132
+ # Run a US-focused overtime text report and write the output into ../output (explicit --out-dir)
133
+ npm run cli:overtime-text-us-outdir
134
+
135
+ # Run a CN-focused overtime Excel report (default 9:00-18:00 work hours and 12:00-14:00 lunch)
136
+ npm run cli:overtime-excel-cn
137
+
138
+ # Run a CN-focused overtime Excel report and write outputs to parent output folder
139
+ npm run cli:overtime-excel-cn-parent
140
+
141
+ # Run a CN-focused overtime Excel report and write outputs to ../output via --out-dir
142
+ npm run cli:overtime-excel-cn-outdir
143
+ # Per-period CSV/Tab export: write per-period files to output/month/ and output/week/
144
+ npm run cli:overtime-per-period-csv-tab
145
+ # Per-period Excel export with sheet-per-period workbook
146
+ npm run cli:overtime-per-period-xlsx-sheets
147
+ # Per-period Excel export with one file per period
148
+ npm run cli:overtime-per-period-xlsx-files
149
+ # Per-period only (no consolidated monthly/weekly files)
150
+ npm run cli:overtime-per-period-only
151
+ ```
152
+
153
+ Notes:
154
+
155
+ - Output files are written into `output/` by default. Use `--out-dir` or `--out-parent` to change output location.
156
+ - If you prefer different working hours or country codes, either modify the script in `package.json` or run the CLI manually with flags (e.g. `--work-start`, `--work-end`, `--lunch-start`, `--lunch-end`, `--country`).
157
+
158
+ Formatting note:
159
+
160
+ - The text report is formatted to align columns correctly even when commit messages or author names contain mixed Chinese and English characters (uses `string-width` for display-aware padding).
161
+
162
+ Example JSON output (from `npm run cli:json-demo`):
163
+
164
+ ```json
165
+ [
166
+ {
167
+ "hash": "c5bdf9d4f52f39bd7d580318bafc8ba4b6c129bc",
168
+ "author": "tom",
169
+ "email": "",
170
+ "date": "2025-11-25 17:24:32 +0800",
171
+ "message": "feat: 🎸 增加output目录"
172
+ }
173
+ /* truncated... */
174
+ ]
175
+ ```
176
+
177
+ Example JSON output including `changeId`/`gerrit` when `--gerrit` uses `{{changeId}}` (if present in commit):
178
+
179
+ ```json
180
+ [
181
+ {
182
+ "hash": "Iabc...",
183
+ "author": "tom",
184
+ "email": "",
185
+ "date": "2025-11-25 17:24:32 +0800",
186
+ "message": "feat: add feature",
187
+ "body": "feat: add feature\n\nChange-Id: Iabcd123456789",
188
+ "changeId": "Iabcd123456789",
189
+ "gerrit": "https://gerrit.example.com/c/project/+/Iabcd123456789"
190
+ }
191
+ ]
192
+ ```
193
+
194
+ ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wukong-gitlog-cli",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "Advanced Git commit log exporter with Excel/JSON/TXT output, grouping, stats and CLI.",
5
5
  "keywords": [
6
6
  "git",
package/src/overtime.mjs CHANGED
@@ -64,6 +64,8 @@ export function analyzeOvertime(records, opts = {}) {
64
64
  hd.init('CN');
65
65
  }
66
66
 
67
+ // 新增:每小时分布统计
68
+ const hourlyCommits = Array(24).fill(0);
67
69
  records.forEach((r) => {
68
70
  const dt = parseCommitDate(r.date);
69
71
  if (!dt || !dt.isValid()) return; // skip
@@ -72,6 +74,12 @@ export function analyzeOvertime(records, opts = {}) {
72
74
  const isHoliday = !!hd.isHoliday(dt.toDate());
73
75
  const isNonWork = isWeekend(dt) || isHoliday;
74
76
 
77
+ // 每小时分布
78
+ const hour = dt.hour();
79
+ if (hour >= 0 && hour < 24) {
80
+ hourlyCommits[hour]++;
81
+ }
82
+
75
83
  if (outside) {
76
84
  outsideWorkCount++;
77
85
  // 记录最新的加班提交
@@ -134,6 +142,8 @@ export function analyzeOvertime(records, opts = {}) {
134
142
  // sort perAuthor by outsideWorkRate desc
135
143
  perAuthor.sort((a, b) => b.outsideWorkRate - a.outsideWorkRate || b.total - a.total);
136
144
 
145
+ // 新增:每小时分布百分比
146
+ const hourlyPercent = hourlyCommits.map(v => total ? +(v / total).toFixed(3) : 0);
137
147
  return {
138
148
  total,
139
149
  outsideWorkCount,
@@ -148,16 +158,18 @@ export function analyzeOvertime(records, opts = {}) {
148
158
  latestOutsideCommit: latestOutsideCommit || null,
149
159
  startHour,
150
160
  endHour,
151
- lunchStart,
152
- lunchEnd,
153
- country,
154
- holidayCount,
155
- holidayRate: total ? +(holidayCount / total).toFixed(3) : 0,
161
+ lunchStart,
162
+ lunchEnd,
163
+ country,
164
+ holidayCount,
165
+ holidayRate: total ? +(holidayCount / total).toFixed(3) : 0,
166
+ hourlyCommits,
167
+ hourlyPercent,
156
168
  };
157
169
  }
158
170
 
159
171
  export function renderOvertimeText(stats) {
160
- const { total, outsideWorkCount, nonWorkdayCount, holidayCount, outsideWorkRate, nonWorkdayRate, holidayRate, perAuthor, startHour, endHour, lunchStart, lunchEnd, country } = stats;
172
+ const { total, outsideWorkCount, nonWorkdayCount, holidayCount, outsideWorkRate, nonWorkdayRate, holidayRate, perAuthor, startHour, endHour, lunchStart, lunchEnd, country, hourlyCommits = [], hourlyPercent = [] } = stats;
161
173
  const { startCommit, endCommit, latestCommit, latestOutsideCommit } = stats;
162
174
  const lines = [];
163
175
 
@@ -206,6 +218,18 @@ export function renderOvertimeText(stats) {
206
218
  lines.push(`下班时间(工作时间外)提交数:${outsideWorkCount},占比:${(outsideWorkRate * 100).toFixed(1)}%`);
207
219
  lines.push(`非工作日(周末)提交数:${nonWorkdayCount},占比:${(nonWorkdayRate * 100).toFixed(1)}%`);
208
220
  lines.push('');
221
+ lines.push('每小时分布(提交数/占比):');
222
+ const hourLine = ' Hour | Count | Percent';
223
+ lines.push(hourLine);
224
+ lines.push(' -----|-------|--------');
225
+ for (let h = 0; h < 24; h++) {
226
+ const cnt = hourlyCommits[h] || 0;
227
+ if (cnt > 0) {
228
+ const pct = hourlyPercent[h] ? (hourlyPercent[h] * 100).toFixed(1) : '0.0';
229
+ lines.push(` ${String(h).padStart(2, '0')} | ${String(cnt).padStart(5, ' ')} | ${pct.padStart(6, ' ')}%`);
230
+ }
231
+ }
232
+ lines.push('');
209
233
  lines.push('按人员统计:');
210
234
  // header
211
235
  const header = ` ${padDisplayEnd('Name', cols.name)} | ${padDisplayStart('总数', cols.total)} | ${padDisplayStart('下班外数', cols.outside)} | ${padDisplayStart('下班外占比', cols.outsideRate)} | ${padDisplayStart('非工作日数', cols.nonWork)} | ${padDisplayStart('非工作日占比', cols.nonWorkRate)} | ${padDisplayStart('假日数', cols.holiday)} | ${padDisplayStart('假日占比', cols.holidayRate)}`;
@@ -224,7 +248,7 @@ export function renderOvertimeText(stats) {
224
248
  }
225
249
 
226
250
  export function renderOvertimeTab(stats) {
227
- const { total, outsideWorkCount, nonWorkdayCount, holidayCount, outsideWorkRate, nonWorkdayRate, holidayRate, perAuthor, startHour, endHour, lunchStart, lunchEnd, country } = stats;
251
+ const { total, outsideWorkCount, nonWorkdayCount, holidayCount, outsideWorkRate, nonWorkdayRate, holidayRate, perAuthor, startHour, endHour, lunchStart, lunchEnd, country, hourlyCommits = [], hourlyPercent = [] } = stats;
228
252
  const { startCommit, endCommit, latestCommit, latestOutsideCommit } = stats;
229
253
  const rows = [];
230
254
  rows.push(`总提交数:\t${total}`);
@@ -236,6 +260,16 @@ export function renderOvertimeTab(stats) {
236
260
  rows.push(`下班时间(工作时间外)提交数:\t${outsideWorkCount}\t占比:\t${(outsideWorkRate * 100).toFixed(1)}%`);
237
261
  rows.push(`非工作日(周末)提交数:\t${nonWorkdayCount}\t占比:\t${(nonWorkdayRate * 100).toFixed(1)}%`);
238
262
  rows.push('');
263
+ rows.push('每小时分布(提交数/占比):');
264
+ rows.push(['Hour', 'Count', 'Percent'].join('\t'));
265
+ for (let h = 0; h < 24; h++) {
266
+ const cnt = hourlyCommits[h] || 0;
267
+ if (cnt > 0) {
268
+ const pct = hourlyPercent[h] ? (hourlyPercent[h] * 100).toFixed(1) : '0.0';
269
+ rows.push([String(h).padStart(2, '0'), cnt, `${pct}%`].join('\t'));
270
+ }
271
+ }
272
+ rows.push('');
239
273
  rows.push(['Name', '总数', '下班外数', '下班外占比', '非工作日数', '非工作日占比', '假日数', '假日占比'].join('\t'));
240
274
  perAuthor.forEach((p) => {
241
275
  rows.push([p.name || '-', p.total, p.outsideWorkCount, `${(p.outsideWorkRate * 100).toFixed(1)}%`, p.nonWorkdayCount, `${(p.nonWorkdayRate * 100).toFixed(1)}%`, p.holidayCount || 0, `${((p.holidayCount || 0) / p.total * 100).toFixed(1)}%`].join('\t'));
@@ -252,12 +286,22 @@ function escapeCsv(v) {
252
286
  }
253
287
 
254
288
  export function renderOvertimeCsv(stats) {
255
- const { perAuthor, latestOutsideCommit, country } = stats;
289
+ const { perAuthor, latestOutsideCommit, country, hourlyCommits = [], hourlyPercent = [], total = 0 } = stats;
256
290
  const rows = [];
257
291
  if (latestOutsideCommit) {
258
292
  rows.push(`# 加班最晚的一次提交,Hash,Author,Date,Message`);
259
293
  rows.push(`# ,${escapeCsv(latestOutsideCommit.hash)},${escapeCsv(latestOutsideCommit.author)},${escapeCsv(formatDateForCountry(latestOutsideCommit.date, country))},${escapeCsv(latestOutsideCommit.message)}`);
260
294
  }
295
+ rows.push('');
296
+ rows.push('Hour,Count,Percent');
297
+ for (let h = 0; h < 24; h++) {
298
+ const cnt = hourlyCommits[h] || 0;
299
+ if (cnt > 0) {
300
+ const pct = hourlyPercent[h] ? (hourlyPercent[h] * 100).toFixed(1) : '0.0';
301
+ rows.push(`${h.toString().padStart(2, '0')},${cnt},${pct}%`);
302
+ }
303
+ }
304
+ rows.push('');
261
305
  rows.push('Name,Total,OutsideCount,OutsideRate,NonWorkdayCount,NonWorkdayRate,HolidayCount,HolidayRate');
262
306
  perAuthor.forEach((p) => {
263
307
  rows.push(`${escapeCsv(p.name)},${p.total},${p.outsideWorkCount},${(p.outsideWorkRate * 100).toFixed(1)}%,${p.nonWorkdayCount},${(p.nonWorkdayRate * 100).toFixed(1)}%,${p.holidayCount || 0},${((p.holidayCount || 0) / p.total * 100).toFixed(1)}%`);