@hecom/codearts 0.2.1 → 0.2.3

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.
@@ -4,150 +4,208 @@ exports.workHourCommand = workHourCommand;
4
4
  const holidays_1 = require("../config/holidays");
5
5
  const business_service_1 = require("../services/business.service");
6
6
  const config_loader_1 = require("../utils/config-loader");
7
+ const csv_writer_1 = require("../utils/csv-writer");
8
+ const logger_1 = require("../utils/logger");
7
9
  /**
8
- * work-hour 命令入口
10
+ * 处理浮点数精度,保留2位小数
9
11
  */
10
- async function workHourCommand(year, cliOptions = {}) {
11
- try {
12
- const targetYear = year || new Date().getFullYear().toString();
13
- console.log(`开始获取 ${targetYear} 年工时统计...`);
14
- const { projectId, roleIds, config } = (0, config_loader_1.loadConfig)(cliOptions);
15
- const businessService = new business_service_1.BusinessService(config);
16
- // 收集所有角色的成员和工时数据
17
- const allMembers = [];
18
- const allUserStats = [];
19
- const allTypes = new Set();
20
- for (const roleId of roleIds) {
21
- const roleMembers = await businessService.getMembersByRoleId(projectId, roleId);
22
- if (roleMembers.length === 0) {
23
- console.log(`角色ID ${roleId} 未找到用户,跳过`);
24
- continue;
25
- }
26
- const roleName = roleMembers[0].role_name;
27
- allMembers.push(...roleMembers);
28
- const roleUserIds = roleMembers.map((member) => member.user_id);
29
- const stats = await businessService.getAllWorkHourStats(projectId, roleUserIds, `${targetYear}-01-01`, `${targetYear}-12-31`);
30
- // 为每个用户添加角色信息
31
- stats.userStats.forEach((userStat) => {
32
- allUserStats.push({
33
- ...userStat,
34
- roleName,
35
- roleId,
36
- });
37
- // 收集所有领域类型
38
- userStat.domainStats.forEach((domainStat) => {
39
- allTypes.add(domainStat.type);
40
- });
12
+ function roundToTwo(num) {
13
+ return Math.round(num * 100) / 100;
14
+ }
15
+ /**
16
+ * 查询年度工时数据
17
+ */
18
+ async function queryWorkHourReportData(businessService, projectId, roleIds, targetYear) {
19
+ const allMembers = [];
20
+ const allUserStats = [];
21
+ const allTypes = new Set();
22
+ for (const roleId of roleIds) {
23
+ const roleMembers = await businessService.getMembersByRoleId(projectId, roleId);
24
+ if (roleMembers.length === 0) {
25
+ logger_1.logger.warn(`角色ID ${roleId} 未找到用户,跳过`);
26
+ continue;
27
+ }
28
+ const roleName = roleMembers[0].role_name;
29
+ allMembers.push(...roleMembers);
30
+ const roleUserIds = roleMembers.map((member) => member.user_id);
31
+ const stats = await businessService.getAllWorkHourStats(projectId, roleUserIds, `${targetYear}-01-01`, `${targetYear}-12-31`);
32
+ stats.userStats.forEach((userStat) => {
33
+ allUserStats.push({
34
+ ...userStat,
35
+ roleName,
36
+ roleId,
37
+ });
38
+ userStat.domainStats.forEach((domainStat) => {
39
+ allTypes.add(domainStat.type);
41
40
  });
41
+ });
42
+ }
43
+ allUserStats.sort((a, b) => {
44
+ if (a.roleId !== b.roleId) {
45
+ return a.roleId - b.roleId;
42
46
  }
43
- if (allMembers.length === 0) {
44
- console.log('未找到任何角色的用户');
45
- return;
47
+ return a.userName.localeCompare(b.userName);
48
+ });
49
+ const expectedWorkdays = (0, holidays_1.calculateExpectedWorkdays)(targetYear);
50
+ const expectedHoursPerPerson = expectedWorkdays * 8;
51
+ const totalExpectedHours = expectedHoursPerPerson * allMembers.length;
52
+ const totalHours = roundToTwo(allUserStats.reduce((sum, userStat) => sum + userStat.totalHours, 0));
53
+ const totalEntries = allUserStats.reduce((sum, userStat) => sum + userStat.domainStats.reduce((s, d) => s + d.workHours.length, 0), 0);
54
+ const userStatsData = [];
55
+ const roleSubtotals = [];
56
+ const typeTotals = {};
57
+ allTypes.forEach((type) => {
58
+ typeTotals[type] = 0;
59
+ });
60
+ let currentRoleId = null;
61
+ let currentRoleName = '';
62
+ const roleSubtotalStats = {};
63
+ allUserStats.forEach((userStat, index) => {
64
+ if (currentRoleId !== null && currentRoleId !== userStat.roleId) {
65
+ const subtotalDomainStats = {};
66
+ let subtotal = 0;
67
+ allTypes.forEach((type) => {
68
+ subtotalDomainStats[type] = roleSubtotalStats[type] || 0;
69
+ subtotal = roundToTwo(subtotal + (roleSubtotalStats[type] || 0));
70
+ });
71
+ roleSubtotals.push({
72
+ roleName: currentRoleName,
73
+ domainStats: subtotalDomainStats,
74
+ total: subtotal,
75
+ });
76
+ Object.keys(roleSubtotalStats).forEach((key) => {
77
+ roleSubtotalStats[key] = 0;
78
+ });
46
79
  }
47
- // 按角色ID排序用户
48
- allUserStats.sort((a, b) => {
49
- if (a.roleId !== b.roleId) {
50
- return a.roleId - b.roleId;
51
- }
52
- return a.userName.localeCompare(b.userName);
53
- });
54
- const expectedWorkdays = (0, holidays_1.calculateExpectedWorkdays)(targetYear);
55
- const expectedHoursPerPerson = expectedWorkdays * 8;
56
- const totalExpectedHours = expectedHoursPerPerson * allMembers.length;
57
- // 计算总工时
58
- const totalHours = allUserStats.reduce((sum, userStat) => sum + userStat.totalHours, 0);
59
- const totalEntries = allUserStats.reduce((sum, userStat) => sum + userStat.domainStats.reduce((s, d) => s + d.workHours.length, 0), 0);
60
- console.log(`\n${targetYear}年工时统计报告`);
61
- console.log('='.repeat(80));
62
- console.log(`统计期间: ${targetYear}-01-01 至 ${targetYear}-12-31`);
63
- console.log(`统计角色: ${roleIds.length} 个角色`);
64
- console.log(`统计人数: ${allMembers.length} 人`);
65
- console.log(`应计工作日: ${expectedWorkdays} 天`);
66
- console.log(`应计工时: ${totalExpectedHours} 小时 (${expectedHoursPerPerson} 小时/人)`);
67
- console.log(`实际工时: ${totalHours} 小时`);
68
- console.log(`工时完成率: ${((totalHours / totalExpectedHours) * 100).toFixed(2)}%`);
69
- console.log(`工时条目: ${totalEntries} 条`);
70
- console.log('='.repeat(80));
71
- // 构建表格数据:人作为行,type作为列
72
- const tableData = {};
73
- const typeTotals = {};
74
- // 初始化总计
80
+ currentRoleId = userStat.roleId;
81
+ currentRoleName = userStat.roleName;
82
+ const domainStats = {};
75
83
  allTypes.forEach((type) => {
76
- typeTotals[type] = 0;
84
+ domainStats[type] = 0;
77
85
  });
78
- // 按角色分组并填充数据
79
- let currentRoleId = null;
80
- let currentRoleName = '';
81
- const roleSubtotals = {};
82
- allUserStats.forEach((userStat, index) => {
83
- // 检测角色变化,插入小计行
84
- if (currentRoleId !== null && currentRoleId !== userStat.roleId) {
85
- const subtotalRow = {};
86
- subtotalRow['角色'] = `${currentRoleName} 小计`;
87
- let subtotal = 0;
88
- allTypes.forEach((type) => {
89
- subtotalRow[type] = roleSubtotals[type] || 0;
90
- subtotal += roleSubtotals[type] || 0;
91
- });
92
- subtotalRow['合计'] = subtotal;
93
- tableData[`─ ${currentRoleName} 小计`] = subtotalRow;
94
- // 重置小计
95
- Object.keys(roleSubtotals).forEach((key) => {
96
- roleSubtotals[key] = 0;
97
- });
86
+ let userTotal = 0;
87
+ userStat.domainStats.forEach((domainStat) => {
88
+ domainStats[domainStat.type] = domainStat.totalHours;
89
+ userTotal = roundToTwo(userTotal + domainStat.totalHours);
90
+ typeTotals[domainStat.type] = roundToTwo(typeTotals[domainStat.type] + domainStat.totalHours);
91
+ if (!roleSubtotalStats[domainStat.type]) {
92
+ roleSubtotalStats[domainStat.type] = 0;
98
93
  }
99
- // 更新当前角色
100
- currentRoleId = userStat.roleId;
101
- currentRoleName = userStat.roleName;
102
- // 填充用户数据
103
- const row = {};
104
- row['角色'] = userStat.roleName;
105
- // 初始化所有类型为0
94
+ roleSubtotalStats[domainStat.type] = roundToTwo(roleSubtotalStats[domainStat.type] + domainStat.totalHours);
95
+ });
96
+ userStatsData.push({
97
+ userName: userStat.userName,
98
+ roleName: userStat.roleName,
99
+ roleId: userStat.roleId,
100
+ domainStats,
101
+ total: userTotal,
102
+ });
103
+ if (index === allUserStats.length - 1) {
104
+ const subtotalDomainStats = {};
105
+ let subtotal = 0;
106
106
  allTypes.forEach((type) => {
107
- row[type] = 0;
107
+ subtotalDomainStats[type] = roleSubtotalStats[type] || 0;
108
+ subtotal = roundToTwo(subtotal + (roleSubtotalStats[type] || 0));
108
109
  });
109
- // 填充实际工时
110
- let userTotal = 0;
111
- userStat.domainStats.forEach((domainStat) => {
112
- row[domainStat.type] = domainStat.totalHours;
113
- userTotal += domainStat.totalHours;
114
- typeTotals[domainStat.type] += domainStat.totalHours;
115
- // 累加到角色小计
116
- if (!roleSubtotals[domainStat.type]) {
117
- roleSubtotals[domainStat.type] = 0;
118
- }
119
- roleSubtotals[domainStat.type] += domainStat.totalHours;
110
+ roleSubtotals.push({
111
+ roleName: currentRoleName,
112
+ domainStats: subtotalDomainStats,
113
+ total: subtotal,
120
114
  });
121
- row['合计'] = userTotal;
122
- tableData[userStat.userName] = row;
123
- // 如果是最后一个用户,添加最后一个角色的小计
124
- if (index === allUserStats.length - 1) {
125
- const subtotalRow = {};
126
- subtotalRow['角色'] = `${currentRoleName} 小计`;
127
- let subtotal = 0;
128
- allTypes.forEach((type) => {
129
- subtotalRow[type] = roleSubtotals[type] || 0;
130
- subtotal += roleSubtotals[type] || 0;
131
- });
132
- subtotalRow['合计'] = subtotal;
133
- tableData[`─ ${currentRoleName} 小计`] = subtotalRow;
134
- }
135
- });
136
- // 添加总计行
137
- const totalRow = {};
138
- totalRow['角色'] = '━ 总计';
139
- let grandTotal = 0;
140
- allTypes.forEach((type) => {
141
- totalRow[type] = typeTotals[type];
142
- grandTotal += typeTotals[type];
143
- });
144
- totalRow['合计'] = grandTotal;
145
- tableData['━━ 总计'] = totalRow;
146
- console.log('\n工时统计表:');
147
- console.table(tableData);
115
+ }
116
+ });
117
+ const grandTotalDomainStats = {};
118
+ let grandTotal = 0;
119
+ allTypes.forEach((type) => {
120
+ grandTotalDomainStats[type] = typeTotals[type];
121
+ grandTotal = roundToTwo(grandTotal + typeTotals[type]);
122
+ });
123
+ return {
124
+ year: targetYear,
125
+ roleCount: roleIds.length,
126
+ memberCount: allMembers.length,
127
+ expectedWorkdays,
128
+ expectedHours: totalExpectedHours,
129
+ actualHours: totalHours,
130
+ completionRate: (totalHours / totalExpectedHours) * 100,
131
+ entryCount: totalEntries,
132
+ userStats: userStatsData,
133
+ roleSubtotals,
134
+ grandTotal: {
135
+ domainStats: grandTotalDomainStats,
136
+ total: grandTotal,
137
+ },
138
+ };
139
+ }
140
+ /**
141
+ * 控制台输出工时统计
142
+ */
143
+ function outputConsole(data) {
144
+ logger_1.logger.info(`\n${data.year}年工时统计 [${data.roleSubtotals.map((r) => r.roleName).join(', ')}]`);
145
+ logger_1.logger.info('='.repeat(80));
146
+ logger_1.logger.info(`统计人数: ${data.memberCount} 人`);
147
+ logger_1.logger.info(`应计工作日: ${data.expectedWorkdays} 天`);
148
+ logger_1.logger.info(`应计工时: ${data.expectedHours} 小时`);
149
+ logger_1.logger.info(`实际工时: ${data.actualHours} 小时`);
150
+ logger_1.logger.info(`工时完成率: ${data.completionRate.toFixed(2)}%`);
151
+ logger_1.logger.info('='.repeat(80));
152
+ // 构建表格数据
153
+ const tableData = {};
154
+ data.userStats.forEach((userStat) => {
155
+ const row = {
156
+ ...userStat.domainStats,
157
+ 合计: userStat.total,
158
+ };
159
+ tableData[userStat.userName] = row;
160
+ });
161
+ // 添加总计行
162
+ tableData['总计'] = {
163
+ ...data.grandTotal.domainStats,
164
+ 合计: data.grandTotal.total,
165
+ };
166
+ logger_1.logger.table(tableData);
167
+ }
168
+ /**
169
+ * CSV 文件输出
170
+ */
171
+ function outputCsv(data, targetYear) {
172
+ const domains = Object.keys(data.grandTotal.domainStats);
173
+ const csvLines = [];
174
+ csvLines.push(`用户,角色,${domains.join(',')},合计`);
175
+ data.userStats.forEach((userStat) => {
176
+ const domainValues = domains.map((domain) => userStat.domainStats[domain] || 0);
177
+ csvLines.push(`${userStat.userName},${userStat.roleName},${domainValues.join(',')},${userStat.total}`);
178
+ });
179
+ const filename = `work-hour-${targetYear}.csv`;
180
+ (0, csv_writer_1.writeCsvFile)(filename, csvLines, logger_1.logger);
181
+ }
182
+ /**
183
+ * JSON 输出(直接打印到控制台,供编程调用)
184
+ */
185
+ function outputJson(data) {
186
+ logger_1.logger.json(data);
187
+ }
188
+ /**
189
+ * work-hour 命令入口
190
+ */
191
+ async function workHourCommand(year, cliOptions = {}) {
192
+ try {
193
+ const targetYear = year || new Date().getFullYear().toString();
194
+ const { projectId, roleIds, config, outputFormat } = (0, config_loader_1.loadConfig)(cliOptions);
195
+ const businessService = new business_service_1.BusinessService(config);
196
+ const reportData = await queryWorkHourReportData(businessService, projectId, roleIds, targetYear);
197
+ if (outputFormat === 'console') {
198
+ outputConsole(reportData);
199
+ }
200
+ else if (outputFormat === 'csv') {
201
+ outputCsv(reportData, targetYear);
202
+ }
203
+ else if (outputFormat === 'json') {
204
+ outputJson(reportData);
205
+ }
148
206
  }
149
207
  catch (error) {
150
- console.error('执行过程中发生错误:', error);
208
+ logger_1.logger.error(`执行过程中发生错误:`, error);
151
209
  process.exit(1);
152
210
  }
153
211
  }
@@ -0,0 +1 @@
1
+ export declare function showLogo(): void;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.showLogo = showLogo;
4
+ const logger_1 = require("../utils/logger");
5
+ const LOGO_LINES = [
6
+ '██╗ ██╗███████╗ ██████╗ ██████╗ ███╗ ███╗',
7
+ '██║ ██║██╔════╝██╔════╝██╔═══██╗████╗ ████║',
8
+ '███████║█████╗ ██║ ██║ ██║██╔████╔██║',
9
+ '██╔══██║██╔══╝ ██║ ██║ ██║██║╚██╔╝██║',
10
+ '██║ ██║███████╗╚██████╗╚██████╔╝██║ ╚═╝ ██║',
11
+ '╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝',
12
+ ];
13
+ const RESET = '\x1b[0m';
14
+ // 256-color middle grays - visible on both light and dark backgrounds
15
+ const GRAYS = [
16
+ '\x1b[38;5;250m', // lighter gray
17
+ '\x1b[38;5;248m',
18
+ '\x1b[38;5;245m', // mid gray
19
+ '\x1b[38;5;243m',
20
+ '\x1b[38;5;240m',
21
+ '\x1b[38;5;238m', // darker gray
22
+ ];
23
+ function showLogo() {
24
+ logger_1.logger.info();
25
+ LOGO_LINES.forEach((line, i) => {
26
+ logger_1.logger.info(`${GRAYS[i]}${line}${RESET}`);
27
+ });
28
+ logger_1.logger.info();
29
+ }
@@ -564,3 +564,7 @@ export type ConfigMap = {
564
564
  * 部分配置映射(用于读取配置文件)
565
565
  */
566
566
  export type PartialConfigMap = Partial<ConfigMap>;
567
+ /**
568
+ * 输出格式类型
569
+ */
570
+ export type OutputFormat = 'console' | 'csv' | 'json';
@@ -1,32 +1,35 @@
1
- import { HuaweiCloudConfig, PartialConfigMap } from '../types';
1
+ import { HuaweiCloudConfig, OutputFormat, PartialConfigMap } from '../types';
2
2
  /**
3
3
  * 获取全局配置文件路径
4
4
  */
5
- export declare function getGlobalConfigPath(): string;
5
+ export declare function getConfigPath(): string;
6
6
  /**
7
7
  * 检查全局配置文件是否存在
8
8
  */
9
- export declare function globalConfigExists(): boolean;
9
+ export declare function configExists(): boolean;
10
10
  /**
11
11
  * 读取全局配置
12
12
  */
13
- export declare function readGlobalConfig(): PartialConfigMap;
13
+ export declare function readConfig(): PartialConfigMap;
14
14
  /**
15
15
  * 写入全局配置
16
16
  * 支持动态配置项,自动按分组组织配置文件
17
17
  */
18
- export declare function writeGlobalConfig(config: PartialConfigMap): void;
18
+ export declare function writeConfig(config: PartialConfigMap): void;
19
19
  /**
20
20
  * 删除全局配置
21
21
  */
22
- export declare function deleteGlobalConfig(): void;
22
+ export declare function deleteConfig(): void;
23
23
  export interface CliOptions {
24
24
  roleId?: string;
25
+ output?: string;
26
+ report?: boolean;
25
27
  }
26
28
  export interface LoadedConfig {
27
29
  projectId: string;
28
30
  roleIds: number[];
29
31
  config: HuaweiCloudConfig;
32
+ outputFormat: OutputFormat;
30
33
  }
31
34
  /**
32
35
  * 加载配置,优先级:命令行参数 > 全局配置
@@ -33,11 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getGlobalConfigPath = getGlobalConfigPath;
37
- exports.globalConfigExists = globalConfigExists;
38
- exports.readGlobalConfig = readGlobalConfig;
39
- exports.writeGlobalConfig = writeGlobalConfig;
40
- exports.deleteGlobalConfig = deleteGlobalConfig;
36
+ exports.getConfigPath = getConfigPath;
37
+ exports.configExists = configExists;
38
+ exports.readConfig = readConfig;
39
+ exports.writeConfig = writeConfig;
40
+ exports.deleteConfig = deleteConfig;
41
41
  exports.loadConfig = loadConfig;
42
42
  exports.getConfig = getConfig;
43
43
  const fs = __importStar(require("fs"));
@@ -61,20 +61,20 @@ function ensureConfigDir() {
61
61
  /**
62
62
  * 获取全局配置文件路径
63
63
  */
64
- function getGlobalConfigPath() {
64
+ function getConfigPath() {
65
65
  return CONFIG_FILE;
66
66
  }
67
67
  /**
68
68
  * 检查全局配置文件是否存在
69
69
  */
70
- function globalConfigExists() {
70
+ function configExists() {
71
71
  return fs.existsSync(CONFIG_FILE);
72
72
  }
73
73
  /**
74
74
  * 读取全局配置
75
75
  */
76
- function readGlobalConfig() {
77
- if (!globalConfigExists()) {
76
+ function readConfig() {
77
+ if (!configExists()) {
78
78
  return {};
79
79
  }
80
80
  const config = {};
@@ -127,7 +127,7 @@ const CONFIG_GROUPS = [
127
127
  * 写入全局配置
128
128
  * 支持动态配置项,自动按分组组织配置文件
129
129
  */
130
- function writeGlobalConfig(config) {
130
+ function writeConfig(config) {
131
131
  ensureConfigDir();
132
132
  // 构建配置文件头部
133
133
  let content = `# Hecom CodeArts 全局配置文件`;
@@ -161,8 +161,8 @@ function writeGlobalConfig(config) {
161
161
  /**
162
162
  * 删除全局配置
163
163
  */
164
- function deleteGlobalConfig() {
165
- if (globalConfigExists()) {
164
+ function deleteConfig() {
165
+ if (configExists()) {
166
166
  try {
167
167
  fs.unlinkSync(CONFIG_FILE);
168
168
  }
@@ -172,7 +172,7 @@ function deleteGlobalConfig() {
172
172
  }
173
173
  }
174
174
  // 加载全局配置
175
- const globalConfig = globalConfigExists() ? readGlobalConfig() : {};
175
+ const globalConfig = configExists() ? readConfig() : {};
176
176
  /**
177
177
  * 加载配置,优先级:命令行参数 > 全局配置
178
178
  * @param cliOptions 命令行选项
@@ -201,6 +201,11 @@ function loadConfig(cliOptions = {}) {
201
201
  if (!username || !password || !domain || !iamEndpoint || !region || !endpoint) {
202
202
  throw new Error('缺少华为云认证信息,请先运行 `npx @hecom/codearts config` 创建配置');
203
203
  }
204
+ // 处理输出格式
205
+ const outputFormat = (cliOptions.output || 'console');
206
+ if (!['console', 'csv', 'json'].includes(outputFormat)) {
207
+ throw new Error('输出格式必须是 console、csv 或 json 之一');
208
+ }
204
209
  const config = {
205
210
  iamEndpoint,
206
211
  region,
@@ -209,7 +214,7 @@ function loadConfig(cliOptions = {}) {
209
214
  password,
210
215
  domainName: domain,
211
216
  };
212
- return { projectId, roleIds, config };
217
+ return { projectId, roleIds, config, outputFormat };
213
218
  }
214
219
  /**
215
220
  * 获取最终合并后的配置(用于显示)
@@ -0,0 +1,12 @@
1
+ import { Logger } from './logger';
2
+ /**
3
+ * CSV 转义函数:处理双引号
4
+ */
5
+ export declare function escapeCsv(value: string): string;
6
+ /**
7
+ * 写入 CSV 文件到当前工作目录
8
+ * @param filename 文件名
9
+ * @param lines CSV 行数组
10
+ * @param logger 日志记录器(可选)
11
+ */
12
+ export declare function writeCsvFile(filename: string, lines: string[], logger?: Logger): void;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.escapeCsv = escapeCsv;
37
+ exports.writeCsvFile = writeCsvFile;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ /**
41
+ * CSV 转义函数:处理双引号
42
+ */
43
+ function escapeCsv(value) {
44
+ if (!value)
45
+ return '';
46
+ return value.replace(/"/g, '""');
47
+ }
48
+ /**
49
+ * 写入 CSV 文件到当前工作目录
50
+ * @param filename 文件名
51
+ * @param lines CSV 行数组
52
+ * @param logger 日志记录器(可选)
53
+ */
54
+ function writeCsvFile(filename, lines, logger) {
55
+ const filepath = path.join(process.cwd(), filename);
56
+ fs.writeFileSync(filepath, lines.join('\n'), 'utf-8');
57
+ if (logger) {
58
+ logger.success(`CSV 文件已生成: ${filepath}`);
59
+ }
60
+ }
@@ -0,0 +1,62 @@
1
+ export type OutputFormat = 'console' | 'csv' | 'json';
2
+ /**
3
+ * 日志工具类(单例模式)
4
+ * 根据输出格式自动控制日志输出:
5
+ * - console/csv: 正常输出所有日志
6
+ * - json: 静默所有用户日志,只输出纯 JSON
7
+ */
8
+ export declare class Logger {
9
+ private static instance;
10
+ private silent;
11
+ private constructor();
12
+ /**
13
+ * 获取 Logger 单例实例
14
+ */
15
+ static getInstance(): Logger;
16
+ /**
17
+ * 设置输出格式,更新静默状态
18
+ * @param outputFormat 输出格式
19
+ */
20
+ setOutputFormat(outputFormat: string | null | undefined): void;
21
+ /**
22
+ * 信息日志(输出到 stdout)
23
+ * json 模式下会被静默
24
+ */
25
+ info(message?: string, ...optionalParams: any[]): void;
26
+ /**
27
+ * 警告日志(输出到 stdout)
28
+ * json 模式下会被静默
29
+ */
30
+ warn(message: string, ...optionalParams: any[]): void;
31
+ /**
32
+ * 成功日志(输出到 stdout)
33
+ * json 模式下会被静默
34
+ */
35
+ success(message: string): void;
36
+ /**
37
+ * 错误日志(输出到 stderr)
38
+ * 始终输出,不受 silent 影响
39
+ */
40
+ error(message: string, ...optionalParams: any[]): void;
41
+ /**
42
+ * 调试日志(输出到 stdout)
43
+ * json 模式下会被静默
44
+ */
45
+ debug(message: string): void;
46
+ /**
47
+ * JSON 数据输出(输出到 stdout)
48
+ * 输出格式化的 JSON 字符串
49
+ * @param data 要输出的数据对象
50
+ */
51
+ json(data: any): void;
52
+ /**
53
+ * 表格输出(输出到 stdout)
54
+ * json 模式下会被静默
55
+ */
56
+ table(data: any): void;
57
+ /**
58
+ * 检查是否处于静默模式
59
+ */
60
+ isSilent(): boolean;
61
+ }
62
+ export declare const logger: Logger;