@dreamor/atlas-cli 0.7.11 → 0.7.13

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.
@@ -146,6 +146,17 @@ function registerProjectCommands(program) {
146
146
  .option('--json', '输出 JSON 信封')
147
147
  .option('--refresh', '刷新字典/部门/项目缓存')
148
148
  .option('--limit <n>', '最多返回 N 个候选(默认 20)')
149
+ .addHelpText('after', `
150
+ kind 说明:
151
+
152
+ project 搜索有权限的项目列表(从 API 实时查询)
153
+ department 搜索部门树中的部门名称(1500+ 部门节点)
154
+ mp-type 搜索人力类型字典值(例: "商机后-研发项目立项通过"、"研发相关" 等)
155
+ line-plan-type 搜索人力基线角色字典值(例: "开发"、"产品"、"测试"、"PM" 等)
156
+ area-code 搜索地域字典值(仅有: "北上杭"、"合肥"、"武汉"、"西南" 四条)
157
+
158
+ 注意: mp-type / line-plan-type / area-code 为字典数据,来源于同一字典 API,
159
+ 搜索范围是该字典所有条目的 attrName 字段。`)
149
160
  .action(async (kind, query, opts) => {
150
161
  try {
151
162
  await findCmd(kind, query, opts);
@@ -49,15 +49,18 @@ export async function monthCmd(opts) {
49
49
  log(`月 ${m} 拉取失败: ${e instanceof Error ? e.message : e}`);
50
50
  }
51
51
  }
52
+ // Apply --department / --role filter
53
+ const filtered = all.filter(p => (!opts.department || (p.departmentName && p.departmentName.includes(opts.department)))
54
+ && (!opts.role || (p.role && p.role.includes(opts.role))));
52
55
  if (opts.json || isJsonMode()) {
53
- jsonOk({ projectId: pid, entries: all }, { failedMonths });
56
+ jsonOk({ projectId: pid, entries: filtered }, { failedMonths });
54
57
  return;
55
58
  }
56
- if (all.length === 0) {
59
+ if (filtered.length === 0) {
57
60
  log('无实际工时数据');
58
61
  return;
59
62
  }
60
- for (const p of all) {
63
+ for (const p of filtered) {
61
64
  log(` ${p.staffName}: ${p.manpower.toFixed(2)} (${p.role ?? ''})`);
62
65
  }
63
66
  }
@@ -77,8 +80,11 @@ export async function summaryCmd(opts) {
77
80
  log(`月 ${m} 拉取失败: ${e instanceof Error ? e.message : e}`);
78
81
  }
79
82
  }
83
+ // Apply --department / --role filter
84
+ const filtered = all.filter(p => (!opts.department || (p.departmentName && p.departmentName.includes(opts.department)))
85
+ && (!opts.role || (p.role && p.role.includes(opts.role))));
80
86
  const axis = (opts.by ?? 'month');
81
- const rows = aggregateByAxis(all, axis);
87
+ const rows = aggregateByAxis(filtered, axis);
82
88
  if (opts.json || isJsonMode()) {
83
89
  jsonOk({ rows }, { failedMonths });
84
90
  return;
@@ -104,14 +110,17 @@ export async function exportCmd(opts) {
104
110
  log(`月 ${m} 拉取失败: ${e instanceof Error ? e.message : e}`);
105
111
  }
106
112
  }
113
+ // Apply --department / --role filter
114
+ const filteredRows = rows.filter(p => (!opts.department || (p.departmentName && p.departmentName.includes(opts.department)))
115
+ && (!opts.role || (p.role && p.role.includes(opts.role))));
107
116
  const content = opts.format === 'csv'
108
- ? (await import('papaparse')).default.unparse(rows)
109
- : JSON.stringify(rows, null, 2);
117
+ ? (await import('papaparse')).default.unparse(filteredRows)
118
+ : JSON.stringify(filteredRows, null, 2);
110
119
  enforceOutputLimit(content);
111
120
  const safePath = resolveSecureExportPath(opts.out);
112
121
  await secureWriteFile(safePath, content);
113
- log(`已导出 ${rows.length} 条记录`);
122
+ log(`已导出 ${filteredRows.length} 条记录`);
114
123
  if (opts.json || isJsonMode()) {
115
- jsonOk({ exported: rows.length, format: opts.format, out: safePath }, { failedMonths });
124
+ jsonOk({ exported: filteredRows.length, format: opts.format, out: safePath }, { failedMonths });
116
125
  }
117
126
  }
@@ -47,9 +47,12 @@ export async function monthCmd(opts) {
47
47
  }
48
48
  }
49
49
  }
50
+ // Apply --department / --role filter
51
+ const filtered = allDetails.filter(d => (!opts.department || (d.departmentName && d.departmentName.includes(opts.department)))
52
+ && (!opts.role || (d.role && d.role.includes(opts.role))));
50
53
  // 聚合
51
54
  const byMonth = new Map();
52
- for (const d of allDetails) {
55
+ for (const d of filtered) {
53
56
  byMonth.set(d.month, (byMonth.get(d.month) ?? 0) + d.manpower);
54
57
  }
55
58
  const monthKeys = [...byMonth.keys()].sort();
@@ -78,9 +81,12 @@ export async function summaryCmd(opts) {
78
81
  }
79
82
  }
80
83
  }
84
+ // Apply --department / --role filter
85
+ const filtered = allDetails.filter(d => (!opts.department || (d.departmentName && d.departmentName.includes(opts.department)))
86
+ && (!opts.role || (d.role && d.role.includes(opts.role))));
81
87
  const axis = opts.by ?? 'month';
82
88
  const groups = new Map();
83
- for (const d of allDetails) {
89
+ for (const d of filtered) {
84
90
  const k = axis === 'month' ? d.month : axis === 'department' ? (d.departmentName ?? '其他') : (d.role ?? '其他');
85
91
  groups.set(k, (groups.get(k) ?? 0) + d.manpower);
86
92
  }
@@ -1,7 +1,7 @@
1
1
  import { createClient } from '../../http/client.js';
2
2
  import { isJsonMode, jsonOk, log } from '../../util/output.js';
3
3
  import { ConfigError, SessionExpiredError } from '../../util/errors.js';
4
- import { expandMonths } from '../../util/months.js';
4
+ import { expandMonths, expandMonthsDefault } from '../../util/months.js';
5
5
  import { monthTsToKey } from '../../util/time.js';
6
6
  import { groupByAxis, mergeBaselineActual, } from './_logic.js';
7
7
  import { resolveProjectId, resolveProjectInfo } from '../../util/env.js';
@@ -10,7 +10,7 @@ function getProjectId(opts) {
10
10
  }
11
11
  export async function compareCmd(opts) {
12
12
  const pid = getProjectId(opts);
13
- const months = opts.month ? [opts.month] : expandMonths(opts.from, opts.to);
13
+ const months = opts.month ? [opts.month] : (opts.from || opts.to ? expandMonths(opts.from, opts.to) : expandMonthsDefault());
14
14
  const allBl = [];
15
15
  const allAc = [];
16
16
  const client = createClient();
@@ -74,13 +74,13 @@ export async function findCmd(kind, query, opts) {
74
74
  }
75
75
  else if (kind === 'department') {
76
76
  const data = await client.post('/yuntu-service/department/tree/select.json', {});
77
- // 需要确认实际响应格式
78
77
  const nodes = Array.isArray(data) ? data : [];
79
78
  const flatten = (items) => {
80
79
  const r = [];
81
80
  for (const n of items) {
82
- if (n.name.includes(query))
83
- r.push({ id: n.id, name: n.name, kind: 'department' });
81
+ const name = n.deptName ?? '';
82
+ if (name.includes(query))
83
+ r.push({ id: String(n.id ?? n.deptCode ?? ''), name, kind: 'department' });
84
84
  if (n.children)
85
85
  r.push(...flatten(n.children));
86
86
  }
@@ -1 +1 @@
1
- export const ATLAS_VERSION = '0.7.11';
1
+ export const ATLAS_VERSION = '0.7.13';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamor/atlas-cli",
3
- "version": "0.7.11",
3
+ "version": "0.7.13",
4
4
  "description": "Atlas CLI - 斑马云图人力基线管理工具",
5
5
  "type": "module",
6
6
  "bin": {