wukong-gitlog-cli 1.0.20 → 1.0.22
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 +9 -0
- package/package.json +3 -2
- package/web/app.js +180 -51
- package/bin/wukong-gitlog-cli +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
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
|
+
### [1.0.22](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.21...v1.0.22) (2025-12-08)
|
|
6
|
+
|
|
7
|
+
### [1.0.21](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.20...v1.0.21) (2025-12-08)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* 🎸 weekly rangeMap ([8389e5e](https://github.com/tomatobybike/wukong-gitlog-cli/commit/8389e5e700640273906a4e616333e318a5961d12))
|
|
13
|
+
|
|
5
14
|
### [1.0.20](https://github.com/tomatobybike/wukong-gitlog-cli/compare/v1.0.19...v1.0.20) (2025-12-05)
|
|
6
15
|
|
|
7
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wukong-gitlog-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Advanced Git commit log exporter with Excel/JSON/TXT output, grouping, stats and CLI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|
|
@@ -116,5 +116,6 @@
|
|
|
116
116
|
"prettier-plugin-packagejson": "2.5.19",
|
|
117
117
|
"sort-package-json": "3.4.0",
|
|
118
118
|
"standard-version": "9.5.0"
|
|
119
|
-
}
|
|
119
|
+
},
|
|
120
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
120
121
|
}
|
package/web/app.js
CHANGED
|
@@ -16,6 +16,34 @@ function getIsoWeekKey(dStr) {
|
|
|
16
16
|
return `${year}-W${String(weekNo).padStart(2, '0')}`
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function formatDateYMD(d) {
|
|
20
|
+
const yyyy = d.getFullYear()
|
|
21
|
+
const mm = String(d.getMonth() + 1).padStart(2, '0')
|
|
22
|
+
const dd = String(d.getDate()).padStart(2, '0')
|
|
23
|
+
return `${yyyy}-${mm}-${dd}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getISOWeekRange(isoYear, isoWeek) {
|
|
27
|
+
// 找到 ISO 年的第一个周一
|
|
28
|
+
// ISO 年的第 1 周包含 1 月 4 日
|
|
29
|
+
const simple = new Date(isoYear, 0, 4)
|
|
30
|
+
const dayOfWeek = simple.getDay() || 7 // Sunday=7
|
|
31
|
+
const firstMonday = new Date(simple)
|
|
32
|
+
firstMonday.setDate(simple.getDate() - dayOfWeek + 1)
|
|
33
|
+
|
|
34
|
+
// 计算目标周的周一
|
|
35
|
+
const monday = new Date(firstMonday)
|
|
36
|
+
monday.setDate(firstMonday.getDate() + (isoWeek - 1) * 7)
|
|
37
|
+
|
|
38
|
+
const sunday = new Date(monday)
|
|
39
|
+
sunday.setDate(monday.getDate() + 6)
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
start: formatDateYMD(monday),
|
|
43
|
+
end: formatDateYMD(sunday)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
19
47
|
async function loadData() {
|
|
20
48
|
try {
|
|
21
49
|
const [
|
|
@@ -42,7 +70,15 @@ async function loadData() {
|
|
|
42
70
|
const latestByDay = latestByDayModule.default || []
|
|
43
71
|
const config = configModule.default || {}
|
|
44
72
|
const authorChanges = authorChangesModule.default || {}
|
|
45
|
-
return {
|
|
73
|
+
return {
|
|
74
|
+
commits,
|
|
75
|
+
stats,
|
|
76
|
+
weekly,
|
|
77
|
+
monthly,
|
|
78
|
+
latestByDay,
|
|
79
|
+
config,
|
|
80
|
+
authorChanges
|
|
81
|
+
}
|
|
46
82
|
} catch (err) {
|
|
47
83
|
console.error('Load data failed', err)
|
|
48
84
|
return { commits: [], stats: {}, weekly: [], monthly: [], latestByDay: [] }
|
|
@@ -60,8 +96,6 @@ function renderCommitsTablePage() {
|
|
|
60
96
|
const start = (page - 1) * pageSize
|
|
61
97
|
const end = start + pageSize
|
|
62
98
|
filtered.slice(start, end).forEach((c) => {
|
|
63
|
-
// FIXME: remove debug log before production
|
|
64
|
-
console.log('❌', 'c', c);
|
|
65
99
|
const tr = document.createElement('tr')
|
|
66
100
|
tr.innerHTML = `<td>${c.hash.slice(0, 8)}</td><td>${c.author}</td><td>${formatDate(c.date)}</td><td>${c.message}</td><td>${c.changed}</td>`
|
|
67
101
|
tbody.appendChild(tr)
|
|
@@ -1244,7 +1278,6 @@ function groupCommitsByHour(commits) {
|
|
|
1244
1278
|
return byHour
|
|
1245
1279
|
}
|
|
1246
1280
|
|
|
1247
|
-
|
|
1248
1281
|
// 基于 latestByDay + cutoff/endHour 统计「最晚加班的一天 / 一周 / 一月」
|
|
1249
1282
|
function computeAndRenderLatestOvertime(latestByDay) {
|
|
1250
1283
|
if (!Array.isArray(latestByDay) || latestByDay.length === 0) return
|
|
@@ -1337,21 +1370,21 @@ function computeAndRenderLatestOvertime(latestByDay) {
|
|
|
1337
1370
|
}
|
|
1338
1371
|
|
|
1339
1372
|
function buildDataset(stats, type) {
|
|
1340
|
-
const dataMap = stats[type]
|
|
1373
|
+
const dataMap = stats[type] // { author: { period: changed } }
|
|
1341
1374
|
|
|
1342
|
-
const authors = Object.keys(dataMap)
|
|
1343
|
-
const allPeriods = Array.from(
|
|
1344
|
-
authors.flatMap(a => Object.keys(dataMap[a]))
|
|
1345
|
-
)
|
|
1375
|
+
const authors = Object.keys(dataMap)
|
|
1376
|
+
const allPeriods = Array.from(
|
|
1377
|
+
new Set(authors.flatMap((a) => Object.keys(dataMap[a])))
|
|
1378
|
+
).sort()
|
|
1346
1379
|
|
|
1347
|
-
const series = authors.map(a => ({
|
|
1380
|
+
const series = authors.map((a) => ({
|
|
1348
1381
|
name: a,
|
|
1349
1382
|
type: 'line',
|
|
1350
1383
|
smooth: true,
|
|
1351
|
-
data: allPeriods.map(p => dataMap[a][p] || 0)
|
|
1352
|
-
}))
|
|
1384
|
+
data: allPeriods.map((p) => dataMap[a][p] || 0)
|
|
1385
|
+
}))
|
|
1353
1386
|
|
|
1354
|
-
return { authors, allPeriods, series }
|
|
1387
|
+
return { authors, allPeriods, series }
|
|
1355
1388
|
}
|
|
1356
1389
|
|
|
1357
1390
|
const drawChangeTrends = (stats) => {
|
|
@@ -1361,6 +1394,7 @@ const drawChangeTrends = (stats) => {
|
|
|
1361
1394
|
|
|
1362
1395
|
function render(t) {
|
|
1363
1396
|
const { authors, allPeriods, series } = buildDataset(stats, t)
|
|
1397
|
+
|
|
1364
1398
|
chart.setOption({
|
|
1365
1399
|
tooltip: { trigger: 'axis' },
|
|
1366
1400
|
legend: { data: authors },
|
|
@@ -1387,13 +1421,7 @@ const drawChangeTrends = (stats) => {
|
|
|
1387
1421
|
}
|
|
1388
1422
|
|
|
1389
1423
|
// ========= 开发者加班趋势(基于 commits 现场计算) =========
|
|
1390
|
-
function buildAuthorOvertimeDataset(
|
|
1391
|
-
commits,
|
|
1392
|
-
type,
|
|
1393
|
-
startHour,
|
|
1394
|
-
endHour,
|
|
1395
|
-
cutoff
|
|
1396
|
-
) {
|
|
1424
|
+
function buildAuthorOvertimeDataset(commits, type, startHour, endHour, cutoff) {
|
|
1397
1425
|
const byAuthor = new Map()
|
|
1398
1426
|
const periods = new Set()
|
|
1399
1427
|
|
|
@@ -1428,7 +1456,7 @@ function buildAuthorOvertimeDataset(
|
|
|
1428
1456
|
name: a,
|
|
1429
1457
|
type: 'line',
|
|
1430
1458
|
smooth: true,
|
|
1431
|
-
data: allPeriods.map((p) =>
|
|
1459
|
+
data: allPeriods.map((p) => byAuthor.get(a)[p] || 0)
|
|
1432
1460
|
}))
|
|
1433
1461
|
return { authors, allPeriods, series }
|
|
1434
1462
|
}
|
|
@@ -1456,8 +1484,45 @@ function drawAuthorOvertimeTrends(commits, stats) {
|
|
|
1456
1484
|
endHour,
|
|
1457
1485
|
cutoff
|
|
1458
1486
|
)
|
|
1487
|
+
ds.rangeMap = {}
|
|
1488
|
+
|
|
1489
|
+
for (const period of ds.allPeriods) {
|
|
1490
|
+
if (period.includes('-W')) {
|
|
1491
|
+
const [yy, ww] = period.split('-W')
|
|
1492
|
+
ds.rangeMap[period] = getISOWeekRange(Number(yy), Number(ww))
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1459
1495
|
chart.setOption({
|
|
1460
|
-
tooltip: {
|
|
1496
|
+
tooltip: {
|
|
1497
|
+
trigger: 'axis',
|
|
1498
|
+
formatter(params) {
|
|
1499
|
+
if (!params || !params.length) return ''
|
|
1500
|
+
|
|
1501
|
+
const p = params[0]
|
|
1502
|
+
const label = p.axisValue
|
|
1503
|
+
const isWeekly = type === 'weekly'
|
|
1504
|
+
|
|
1505
|
+
let extra = ''
|
|
1506
|
+
if (isWeekly && ds.rangeMap && ds.rangeMap[label]) {
|
|
1507
|
+
const { start, end } = ds.rangeMap[label]
|
|
1508
|
+
extra = `<div style="margin-top:4px;color:#999;font-size:12px">
|
|
1509
|
+
周区间:${start} ~ ${end}
|
|
1510
|
+
</div>`
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
const lines = params
|
|
1514
|
+
.map(
|
|
1515
|
+
(item) => `${item.marker}${item.seriesName}: ${item.data} 小时`
|
|
1516
|
+
)
|
|
1517
|
+
.join('<br/>')
|
|
1518
|
+
|
|
1519
|
+
return `
|
|
1520
|
+
<div>${label}</div>
|
|
1521
|
+
${extra}
|
|
1522
|
+
${lines}
|
|
1523
|
+
`
|
|
1524
|
+
}
|
|
1525
|
+
},
|
|
1461
1526
|
legend: { data: ds.authors },
|
|
1462
1527
|
xAxis: { type: 'category', data: ds.allPeriods },
|
|
1463
1528
|
yAxis: { type: 'value' },
|
|
@@ -1533,7 +1598,9 @@ function renderWeeklyRiskSummary(
|
|
|
1533
1598
|
const curTotal = Array.from(curMap.values()).reduce((a, b) => a + b, 0)
|
|
1534
1599
|
const prevTotal = Array.from(prevMap.values()).reduce((a, b) => a + b, 0)
|
|
1535
1600
|
const delta =
|
|
1536
|
-
prevTotal > 0
|
|
1601
|
+
prevTotal > 0
|
|
1602
|
+
? Math.round(((curTotal - prevTotal) / prevTotal) * 100)
|
|
1603
|
+
: null
|
|
1537
1604
|
|
|
1538
1605
|
// 找当前周最“活跃”的人(加班提交最多),并统计他加班的自然日数
|
|
1539
1606
|
let topAuthor = null
|
|
@@ -1596,7 +1663,9 @@ function computeAuthorDailyMaxOvertime(commits, startHour, endHour, cutoff) {
|
|
|
1596
1663
|
dayKey = d.toISOString().slice(0, 10)
|
|
1597
1664
|
} else if (h >= 0 && h < cutoff && h < startHour) {
|
|
1598
1665
|
overtime = 24 - endHour + h
|
|
1599
|
-
const cur = new Date(
|
|
1666
|
+
const cur = new Date(
|
|
1667
|
+
Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())
|
|
1668
|
+
)
|
|
1600
1669
|
cur.setUTCDate(cur.getUTCDate() - 1)
|
|
1601
1670
|
dayKey = cur.toISOString().slice(0, 10)
|
|
1602
1671
|
}
|
|
@@ -1618,7 +1687,12 @@ function renderWeeklyDurationRiskSummary(
|
|
|
1618
1687
|
if (!box) return
|
|
1619
1688
|
const now = new Date()
|
|
1620
1689
|
const curWeek = getIsoWeekKey(now.toISOString().slice(0, 10))
|
|
1621
|
-
const byAuthorDay = computeAuthorDailyMaxOvertime(
|
|
1690
|
+
const byAuthorDay = computeAuthorDailyMaxOvertime(
|
|
1691
|
+
commits,
|
|
1692
|
+
startHour,
|
|
1693
|
+
endHour,
|
|
1694
|
+
cutoff
|
|
1695
|
+
)
|
|
1622
1696
|
const sums = []
|
|
1623
1697
|
byAuthorDay.forEach((dayMap, author) => {
|
|
1624
1698
|
let total = 0
|
|
@@ -1639,7 +1713,9 @@ function renderWeeklyDurationRiskSummary(
|
|
|
1639
1713
|
let level = '轻度'
|
|
1640
1714
|
if (total >= 12) level = '严重'
|
|
1641
1715
|
else if (total >= 6) level = '中度'
|
|
1642
|
-
lines.push(
|
|
1716
|
+
lines.push(
|
|
1717
|
+
`${author} 本周累计加班 ${total.toFixed(2)} 小时(${level})。`
|
|
1718
|
+
)
|
|
1643
1719
|
})
|
|
1644
1720
|
}
|
|
1645
1721
|
box.innerHTML = `
|
|
@@ -1663,7 +1739,12 @@ function renderMonthlyDurationRiskSummary(
|
|
|
1663
1739
|
if (!box) return
|
|
1664
1740
|
const now = new Date()
|
|
1665
1741
|
const curMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`
|
|
1666
|
-
const byAuthorDay = computeAuthorDailyMaxOvertime(
|
|
1742
|
+
const byAuthorDay = computeAuthorDailyMaxOvertime(
|
|
1743
|
+
commits,
|
|
1744
|
+
startHour,
|
|
1745
|
+
endHour,
|
|
1746
|
+
cutoff
|
|
1747
|
+
)
|
|
1667
1748
|
const sums = []
|
|
1668
1749
|
byAuthorDay.forEach((dayMap, author) => {
|
|
1669
1750
|
let total = 0
|
|
@@ -1684,7 +1765,9 @@ function renderMonthlyDurationRiskSummary(
|
|
|
1684
1765
|
let level = '轻度'
|
|
1685
1766
|
if (total >= 20) level = '严重'
|
|
1686
1767
|
else if (total >= 10) level = '中度'
|
|
1687
|
-
lines.push(
|
|
1768
|
+
lines.push(
|
|
1769
|
+
`${author} 本月累计加班 ${total.toFixed(2)} 小时(${level})。`
|
|
1770
|
+
)
|
|
1688
1771
|
})
|
|
1689
1772
|
}
|
|
1690
1773
|
box.innerHTML = `
|
|
@@ -1707,11 +1790,18 @@ function renderRolling30DurationRiskSummary(
|
|
|
1707
1790
|
const box = document.getElementById('rolling30DurationRiskSummary')
|
|
1708
1791
|
if (!box) return
|
|
1709
1792
|
const now = new Date()
|
|
1710
|
-
const utcToday = new Date(
|
|
1793
|
+
const utcToday = new Date(
|
|
1794
|
+
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
|
|
1795
|
+
)
|
|
1711
1796
|
utcToday.setUTCDate(utcToday.getUTCDate() - 29)
|
|
1712
1797
|
const startKey = utcToday.toISOString().slice(0, 10)
|
|
1713
1798
|
|
|
1714
|
-
const byAuthorDay = computeAuthorDailyMaxOvertime(
|
|
1799
|
+
const byAuthorDay = computeAuthorDailyMaxOvertime(
|
|
1800
|
+
commits,
|
|
1801
|
+
startHour,
|
|
1802
|
+
endHour,
|
|
1803
|
+
cutoff
|
|
1804
|
+
)
|
|
1715
1805
|
const sums = []
|
|
1716
1806
|
byAuthorDay.forEach((dayMap, author) => {
|
|
1717
1807
|
let total = 0
|
|
@@ -1731,7 +1821,9 @@ function renderRolling30DurationRiskSummary(
|
|
|
1731
1821
|
let level = '轻度'
|
|
1732
1822
|
if (total >= 20) level = '严重'
|
|
1733
1823
|
else if (total >= 10) level = '中度'
|
|
1734
|
-
lines.push(
|
|
1824
|
+
lines.push(
|
|
1825
|
+
`${author} 最近30天累计加班 ${total.toFixed(2)} 小时(${level})。`
|
|
1826
|
+
)
|
|
1735
1827
|
})
|
|
1736
1828
|
}
|
|
1737
1829
|
box.innerHTML = `
|
|
@@ -1766,7 +1858,8 @@ function renderMonthlyRiskSummary(
|
|
|
1766
1858
|
const d = new Date(c.date)
|
|
1767
1859
|
if (Number.isNaN(d.valueOf())) return
|
|
1768
1860
|
const h = d.getHours()
|
|
1769
|
-
const isOT =
|
|
1861
|
+
const isOT =
|
|
1862
|
+
(h >= endHour && h < 24) || (h >= 0 && h < cutoff && h < startHour)
|
|
1770
1863
|
if (!isOT) return
|
|
1771
1864
|
|
|
1772
1865
|
const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`
|
|
@@ -1785,14 +1878,18 @@ function renderMonthlyRiskSummary(
|
|
|
1785
1878
|
const mm = monthMax.get(key)
|
|
1786
1879
|
const cur = mm.get(author)
|
|
1787
1880
|
const dateStr = d.toISOString().slice(0, 10)
|
|
1788
|
-
if (!cur || overtime > cur.max)
|
|
1881
|
+
if (!cur || overtime > cur.max)
|
|
1882
|
+
mm.set(author, { max: overtime, date: dateStr })
|
|
1789
1883
|
})
|
|
1790
1884
|
|
|
1791
1885
|
const curMap = monthAuthor.get(curKey) || new Map()
|
|
1792
1886
|
const prevMap = monthAuthor.get(prevKey) || new Map()
|
|
1793
1887
|
const curTotal = Array.from(curMap.values()).reduce((a, b) => a + b, 0)
|
|
1794
1888
|
const prevTotal = Array.from(prevMap.values()).reduce((a, b) => a + b, 0)
|
|
1795
|
-
const delta =
|
|
1889
|
+
const delta =
|
|
1890
|
+
prevTotal > 0
|
|
1891
|
+
? Math.round(((curTotal - prevTotal) / prevTotal) * 100)
|
|
1892
|
+
: null
|
|
1796
1893
|
|
|
1797
1894
|
let topAuthor = null
|
|
1798
1895
|
let top = { max: -1, date: null }
|
|
@@ -1830,7 +1927,9 @@ function renderMonthlyRiskSummary(
|
|
|
1830
1927
|
else if (top.max < prevMax) trend2 = '较上月提前'
|
|
1831
1928
|
else trend2 = '与上月持平'
|
|
1832
1929
|
}
|
|
1833
|
-
lines.push(
|
|
1930
|
+
lines.push(
|
|
1931
|
+
`${topAuthor} 本月最晚超出下班 ${top.max.toFixed(2)} 小时(${top.date}),${trend2}。`
|
|
1932
|
+
)
|
|
1834
1933
|
if (top.max >= 2) lines.push('已超过 2 小时,存在严重加班风险。')
|
|
1835
1934
|
else if (top.max >= 1) lines.push('已超过 1 小时,存在中度加班风险。')
|
|
1836
1935
|
}
|
|
@@ -1850,13 +1949,7 @@ function renderMonthlyRiskSummary(
|
|
|
1850
1949
|
}
|
|
1851
1950
|
|
|
1852
1951
|
// ========= 开发者加班“最晚”趋势(每期取最大超时) =========
|
|
1853
|
-
function buildAuthorLatestDataset(
|
|
1854
|
-
commits,
|
|
1855
|
-
type,
|
|
1856
|
-
startHour,
|
|
1857
|
-
endHour,
|
|
1858
|
-
cutoff
|
|
1859
|
-
) {
|
|
1952
|
+
function buildAuthorLatestDataset(commits, type, startHour, endHour, cutoff) {
|
|
1860
1953
|
const byAuthor = new Map()
|
|
1861
1954
|
const periods = new Set()
|
|
1862
1955
|
|
|
@@ -1867,8 +1960,7 @@ function buildAuthorLatestDataset(
|
|
|
1867
1960
|
|
|
1868
1961
|
let overtime = null
|
|
1869
1962
|
if (h >= endHour && h < 24) overtime = h - endHour
|
|
1870
|
-
else if (h >= 0 && h < cutoff && h < startHour)
|
|
1871
|
-
overtime = 24 - endHour + h
|
|
1963
|
+
else if (h >= 0 && h < cutoff && h < startHour) overtime = 24 - endHour + h
|
|
1872
1964
|
if (overtime == null) return
|
|
1873
1965
|
|
|
1874
1966
|
let key
|
|
@@ -1889,6 +1981,7 @@ function buildAuthorLatestDataset(
|
|
|
1889
1981
|
})
|
|
1890
1982
|
|
|
1891
1983
|
const allPeriods = Array.from(periods).sort()
|
|
1984
|
+
|
|
1892
1985
|
const authors = Array.from(byAuthor.keys()).sort()
|
|
1893
1986
|
const series = authors.map((a) => ({
|
|
1894
1987
|
name: a,
|
|
@@ -1922,8 +2015,45 @@ function drawAuthorLatestOvertimeTrends(commits, stats) {
|
|
|
1922
2015
|
endHour,
|
|
1923
2016
|
cutoff
|
|
1924
2017
|
)
|
|
2018
|
+
ds.rangeMap = {}
|
|
2019
|
+
|
|
2020
|
+
for (const period of ds.allPeriods) {
|
|
2021
|
+
if (period.includes('-W')) {
|
|
2022
|
+
const [yy, ww] = period.split('-W')
|
|
2023
|
+
ds.rangeMap[period] = getISOWeekRange(Number(yy), Number(ww))
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
1925
2026
|
chart.setOption({
|
|
1926
|
-
tooltip: {
|
|
2027
|
+
tooltip: {
|
|
2028
|
+
trigger: 'axis',
|
|
2029
|
+
formatter(params) {
|
|
2030
|
+
if (!params || !params.length) return ''
|
|
2031
|
+
|
|
2032
|
+
const p = params[0]
|
|
2033
|
+
const label = p.axisValue
|
|
2034
|
+
const isWeekly = type === 'weekly'
|
|
2035
|
+
|
|
2036
|
+
let extra = ''
|
|
2037
|
+
if (isWeekly && ds.rangeMap && ds.rangeMap[label]) {
|
|
2038
|
+
const { start, end } = ds.rangeMap[label]
|
|
2039
|
+
extra = `<div style="margin-top:4px;color:#999;font-size:12px">
|
|
2040
|
+
周区间:${start} ~ ${end}
|
|
2041
|
+
</div>`
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
const lines = params
|
|
2045
|
+
.map(
|
|
2046
|
+
(item) => `${item.marker}${item.seriesName}: ${item.data} 小时`
|
|
2047
|
+
)
|
|
2048
|
+
.join('<br/>')
|
|
2049
|
+
|
|
2050
|
+
return `
|
|
2051
|
+
<div>${label}</div>
|
|
2052
|
+
${extra}
|
|
2053
|
+
${lines}
|
|
2054
|
+
`
|
|
2055
|
+
}
|
|
2056
|
+
},
|
|
1927
2057
|
legend: { data: ds.authors },
|
|
1928
2058
|
xAxis: { type: 'category', data: ds.allPeriods },
|
|
1929
2059
|
yAxis: {
|
|
@@ -1974,8 +2104,7 @@ function renderLatestRiskSummary(
|
|
|
1974
2104
|
const h = d.getHours()
|
|
1975
2105
|
let overtime = null
|
|
1976
2106
|
if (h >= endHour && h < 24) overtime = h - endHour
|
|
1977
|
-
else if (h >= 0 && h < cutoff && h < startHour)
|
|
1978
|
-
overtime = 24 - endHour + h
|
|
2107
|
+
else if (h >= 0 && h < cutoff && h < startHour) overtime = 24 - endHour + h
|
|
1979
2108
|
if (overtime == null) return
|
|
1980
2109
|
|
|
1981
2110
|
const wKey = getIsoWeekKey(d.toISOString().slice(0, 10))
|
|
@@ -2107,7 +2236,9 @@ function renderLatestMonthlyRiskSummary(
|
|
|
2107
2236
|
else if (top.max < prevMax) trend = '较上月提前'
|
|
2108
2237
|
else trend = '与上月持平'
|
|
2109
2238
|
}
|
|
2110
|
-
lines.push(
|
|
2239
|
+
lines.push(
|
|
2240
|
+
`${topAuthor} 本月最晚超出下班 ${top.max.toFixed(2)} 小时(${top.date}),${trend}。`
|
|
2241
|
+
)
|
|
2111
2242
|
if (top.max >= 2) {
|
|
2112
2243
|
lines.push('已超过 2 小时,存在严重加班风险,请关注工作节奏。')
|
|
2113
2244
|
} else if (top.max >= 1) {
|
|
@@ -2137,8 +2268,7 @@ async function main() {
|
|
|
2137
2268
|
latestByDay,
|
|
2138
2269
|
config,
|
|
2139
2270
|
authorChanges
|
|
2140
|
-
} =
|
|
2141
|
-
await loadData()
|
|
2271
|
+
} = await loadData()
|
|
2142
2272
|
commitsAll = commits
|
|
2143
2273
|
filtered = commitsAll.slice()
|
|
2144
2274
|
window.__overtimeEndHour =
|
|
@@ -2185,7 +2315,6 @@ async function main() {
|
|
|
2185
2315
|
renderKpi(stats)
|
|
2186
2316
|
}
|
|
2187
2317
|
|
|
2188
|
-
|
|
2189
2318
|
// 抽屉关闭交互(按钮 + 点击遮罩)
|
|
2190
2319
|
document.getElementById('sidebarClose').onclick = () => {
|
|
2191
2320
|
document.getElementById('dayDetailSidebar').classList.remove('show')
|
package/bin/wukong-gitlog-cli
DELETED