UNPKG

code996

Version:

通过分析 Git commit 的时间分布,计算出项目的'996指数'

287 lines 13 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.printCoreResults = printCoreResults; exports.printTimeDistribution = printTimeDistribution; exports.printWorkTimeSummary = printWorkTimeSummary; exports.printWeekdayOvertime = printWeekdayOvertime; exports.printWeekendOvertime = printWeekendOvertime; exports.printLateNightAnalysis = printLateNightAnalysis; const chalk_1 = __importDefault(require("chalk")); const terminal_1 = require("../../../utils/terminal"); const formatter_1 = require("../../../utils/formatter"); /** 打印核心指标(整合统计信息,统一表格展示) */ function printCoreResults(result, rawData, options, since, until, rangeMode = 'custom') { console.log(chalk_1.default.blue('📊 核心结果:')); console.log(); const terminalWidth = Math.min((0, terminal_1.getTerminalWidth)(), 80); const resultTable = (0, terminal_1.createAdaptiveTable)(terminalWidth, 'core'); const indexColor = (0, formatter_1.getIndexColor)(result.index996); const radioColor = result.overTimeRadio > 0 ? chalk_1.default.red : chalk_1.default.green; // 构建时间范围文本 let periodText = ''; if (options.since && options.until) { periodText = `${options.since}${options.until}`; } else if (options.since) { periodText = `从 ${options.since} 开始`; } else if (options.until) { periodText = `截至 ${options.until}`; } else if (options.allTime) { periodText = '所有时间'; } else if (rangeMode === 'auto-last-commit' && since && until) { periodText = `${since}${until}(按最后一次提交回溯365天)`; } else if (rangeMode === 'fallback' && since && until) { periodText = `${since}${until}(按当前日期回溯365天)`; } else if (since && until) { periodText = `${since}${until}`; } else { periodText = '最近一年'; } resultTable.push([ { content: chalk_1.default.bold('996指数'), colSpan: 1 }, { content: indexColor(result.index996.toFixed(1)), colSpan: 1 }, ], [ { content: chalk_1.default.bold('整体评价'), colSpan: 1 }, { content: result.index996Str, colSpan: 1 }, ], [ { content: chalk_1.default.bold('分析时段'), colSpan: 1 }, { content: periodText, colSpan: 1 }, ], [ { content: chalk_1.default.bold('加班比例'), colSpan: 1 }, { content: radioColor(`${result.overTimeRadio.toFixed(1)}%`), colSpan: 1 }, ], [ { content: chalk_1.default.bold('总提交数'), colSpan: 1 }, { content: `${rawData.totalCommits}`, colSpan: 1 }, ]); console.log(resultTable.toString()); console.log(); // 在核心结果表格下方添加996指数说明 console.log(chalk_1.default.gray('* 996指数:为 0 则不加班,值越大代表加班越严重,996 工作制对应的值为 100。')); console.log(); } /** 打印 24 小时提交分布与星期分布图形 */ function printTimeDistribution(parsedData) { const barLength = 20; console.log(chalk_1.default.blue('🕐 24小时分布:')); const maxCount = Math.max(0, ...parsedData.hourData.map((item) => item.count)); if (maxCount === 0) { console.log('暂无提交数据'); console.log(); } else { parsedData.hourData.forEach((hour) => { if (hour.count === 0) { return; } const percentage = (hour.count / maxCount) * barLength; const filledLength = Math.min(barLength, Math.max(1, Math.round(percentage))); const bar = '█'.repeat(filledLength) + ' '.repeat(barLength - filledLength); const countText = hour.count.toString().padStart(3); console.log(`${hour.time}: ${bar} ${countText}`); }); console.log(); } console.log(chalk_1.default.blue('📅 星期分布:')); const weekDayNames = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; const maxDayCount = Math.max(0, ...parsedData.dayData.map((item) => item.count)); const totalDayCount = parsedData.dayData.reduce((sum, item) => sum + item.count, 0); if (totalDayCount === 0) { console.log('暂无星期提交数据'); console.log(); return; } parsedData.dayData.forEach((day) => { const dayIndex = parseInt(day.time, 10) - 1; // 1-7 转换为 0-6 const dayName = weekDayNames[dayIndex] || '未知'; const percentage = totalDayCount > 0 ? ((day.count / totalDayCount) * 100).toFixed(1) : '0.0'; if (maxDayCount === 0) { console.log(`${dayName}: ${''.padEnd(barLength)} 0 (0.0%)`); } else { const barPercentage = (day.count / maxDayCount) * barLength; const filledLength = Math.min(barLength, Math.max(0, Math.round(barPercentage))); const bar = '█'.repeat(filledLength) + ' '.repeat(barLength - filledLength); const countText = day.count.toString().padStart(3); console.log(`${dayName}: ${bar} ${countText} (${percentage}%)`); } }); console.log(); } /** 打印上班与下班时间的推测信息 */ function printWorkTimeSummary(parsedData) { console.log(chalk_1.default.blue('⌛ 工作时间推测:')); const detection = parsedData.detectedWorkTime; if (!detection) { console.log('暂无可用的工作时间推测数据'); console.log(); return; } const startClock = (0, formatter_1.formatStartClock)(detection); const endClock = (0, formatter_1.formatEndClock)(detection); const terminalWidth = Math.min((0, terminal_1.getTerminalWidth)(), 80); const workTimeTable = (0, terminal_1.createAdaptiveTable)(terminalWidth, 'core'); workTimeTable.push([ { content: chalk_1.default.bold('上班时间推测'), colSpan: 1 }, { content: startClock, colSpan: 1 }, ], [ { content: chalk_1.default.bold('下班时间推测'), colSpan: 1 }, { content: endClock, colSpan: 1 }, ], [ { content: chalk_1.default.bold('可信度'), colSpan: 1 }, { content: `${detection.confidence}%(样本天数: ${detection.sampleCount})`, colSpan: 1 }, ]); console.log(workTimeTable.toString()); console.log(); } /** 打印工作日加班分布 */ function printWeekdayOvertime(parsedData) { if (!parsedData.weekdayOvertime) { return; } console.log(chalk_1.default.blue('💼 工作日加班分布:')); console.log(); const overtime = parsedData.weekdayOvertime; const weekdays = [ { name: '周一', key: 'monday' }, { name: '周二', key: 'tuesday' }, { name: '周三', key: 'wednesday' }, { name: '周四', key: 'thursday' }, { name: '周五', key: 'friday' }, ]; // 找出最大值用于计算条形图长度 const maxCount = Math.max(overtime.monday, overtime.tuesday, overtime.wednesday, overtime.thursday, overtime.friday); if (maxCount === 0) { console.log('暂无工作日加班数据'); console.log(); return; } const barLength = 20; // 计算加班高峰阈值(最大值的90%) const peakThreshold = maxCount * 0.9; weekdays.forEach(({ name, key }) => { const count = overtime[key]; const percentage = maxCount > 0 ? (count / maxCount) * barLength : 0; const filledLength = Math.min(barLength, Math.max(0, Math.round(percentage))); const bar = '█'.repeat(filledLength) + ' '.repeat(barLength - filledLength); const countText = count.toString().padStart(3); // 如果加班次数 >= 90% 的最大值,标注为加班高峰 const isPeak = count >= peakThreshold && count > 0; const peakLabel = isPeak ? chalk_1.default.red(' ⚠️ 加班高峰') : ''; console.log(`${name}: ${bar} ${countText}${peakLabel}`); }); console.log(); } /** 打印周末加班分布 */ function printWeekendOvertime(parsedData) { if (!parsedData.weekendOvertime) { return; } const weekend = parsedData.weekendOvertime; const totalDays = weekend.saturdayDays + weekend.sundayDays; // 如果没有周末工作,不显示 if (totalDays === 0) { return; } console.log(chalk_1.default.blue('📅 周末加班分析:')); console.log(); const weekendDays = [ { name: '周六', count: weekend.saturdayDays }, { name: '周日', count: weekend.sundayDays }, ]; const barLength = 20; const maxCount = Math.max(weekend.saturdayDays, weekend.sundayDays); weekendDays.forEach(({ name, count }) => { if (count === 0) return; const percentage = maxCount > 0 ? (count / maxCount) * barLength : 0; const filledLength = Math.min(barLength, Math.max(0, Math.round(percentage))); const bar = '█'.repeat(filledLength) + ' '.repeat(barLength - filledLength); const countText = count.toString().padStart(3); const percentOfTotal = totalDays > 0 ? ((count / totalDays) * 100).toFixed(1) : '0.0'; console.log(`${name}: ${bar} ${countText}天 (${percentOfTotal}%)`); }); console.log(); // 显示加班类型分布 const totalWorkDays = weekend.realOvertimeDays + weekend.casualFixDays; const realOvertimeColor = weekend.realOvertimeDays > 15 ? chalk_1.default.red : weekend.realOvertimeDays > 8 ? chalk_1.default.yellow : chalk_1.default.green; console.log('加班类型:'); console.log(` 真正加班: ${realOvertimeColor(chalk_1.default.bold(weekend.realOvertimeDays.toString()))}天 (提交时间跨度>=3小时)`); console.log(` 临时修复: ${chalk_1.default.gray(weekend.casualFixDays.toString())}天 (提交时间跨度<3小时)`); console.log(` 加班占比: ${realOvertimeColor(((weekend.realOvertimeDays / totalWorkDays) * 100).toFixed(1) + '%')}`); console.log(); } /** 打印深夜加班分析 */ function printLateNightAnalysis(parsedData) { if (!parsedData.lateNightAnalysis) { return; } console.log(chalk_1.default.blue('🌙 深夜加班分析:')); console.log(); const analysis = parsedData.lateNightAnalysis; const endHour = parsedData.detectedWorkTime?.endHour || 18; // 计算最大值用于条形图 const maxCount = Math.max(analysis.evening, analysis.lateNight, analysis.midnight, analysis.dawn); if (maxCount === 0) { console.log('暂无深夜加班数据'); console.log(); return; } const barLength = 20; const timeRanges = [ { label: `${Math.ceil(endHour).toString().padStart(2, '0')}:00-21:00`, count: analysis.evening, description: '晚间提交', isWarning: false, }, { label: '21:00-23:00', count: analysis.lateNight, description: '加班晚期', isWarning: false, }, { label: '23:00-02:00', count: analysis.midnight, description: '深夜加班', isWarning: analysis.midnight > 0, }, { label: '02:00-06:00', count: analysis.dawn, description: '凌晨编程', isWarning: analysis.dawn > 0, }, ]; timeRanges.forEach(({ label, count, description, isWarning }) => { if (count === 0) return; const percentage = maxCount > 0 ? (count / maxCount) * barLength : 0; const filledLength = Math.min(barLength, Math.max(0, Math.round(percentage))); const bar = '█'.repeat(filledLength) + ' '.repeat(barLength - filledLength); const countText = count.toString().padStart(3); const warningLabel = isWarning ? chalk_1.default.red(' ⚠️') : ''; // 计算该时段的频率(这里的count是天数,不是提交数) const weeklyAvg = (count / analysis.totalWeeks).toFixed(1); const monthlyAvg = (count / analysis.totalMonths).toFixed(1); const freqText = chalk_1.default.gray(` 平均每周${weeklyAvg}天 每月${monthlyAvg}天`); console.log(`${label}: ${bar} ${countText}天 (${description})${warningLabel}${freqText}`); }); console.log(); // 显示深夜加班天数和占比 if (analysis.midnightDays > 0) { const rateColor = analysis.midnightRate > 10 ? chalk_1.default.red : analysis.midnightRate > 5 ? chalk_1.default.yellow : chalk_1.default.green; console.log(`深夜/凌晨加班天数: ${chalk_1.default.bold(analysis.midnightDays.toString())}天 / ${analysis.totalWorkDays}天工作日 (${rateColor(analysis.midnightRate.toFixed(1) + '%')})`); console.log(); } } //# sourceMappingURL=printer.js.map