byteplan-cli 1.3.5 → 1.3.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "byteplan-cli",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "BytePlan CLI - Command line tool for BytePlan API",
5
5
  "keywords": [
6
6
  "byteplan",
@@ -627,34 +627,26 @@ export async function queryModels(token, options = {}) {
627
627
  * @param {Object} params.customQuery - 自定义查询条件
628
628
  * @param {string[]} params.groupFields - 分组字段
629
629
  * @param {Array} params.functions - 聚合函数
630
+ * @param {number} params.page - 页码(从 0 开始)
631
+ * @param {number} params.pageSize - 每页条数
630
632
  * @param {object} options - 可选配置
631
633
  * @param {object} options.menuHeaders - 自定义 menu headers
632
- * @returns {Promise<any>}
634
+ * @returns {Promise<{data: Array}>} 返回数据数组,无 total 字段
633
635
  */
634
636
  export async function getModelData(token, modelCode, params = {}, options = {}) {
635
- const { customQuery, groupFields, functions } = params;
637
+ const { customQuery, groupFields, functions, page = 0, pageSize = 100 } = params;
636
638
  const { menuHeaders = {} } = options;
637
639
 
638
640
  // CLI 模式(仅支持简单查询)
639
641
  if (useCliMode && !token && !customQuery && !groupFields && !functions) {
640
642
  await ensureCliInstalled();
641
- const pageNum = params.pageNum || 0;
642
- const pageSize = params.pageSize || 100;
643
643
  try {
644
- const result = await execCli(['data', 'query', modelCode, '-p', String(pageNum), '-s', String(pageSize)]);
644
+ const result = await execCli(['data', 'query', modelCode, '-p', String(page), '-s', String(pageSize)]);
645
645
  if (result.error) {
646
646
  throw new Error(result.message || '查询数据失败');
647
647
  }
648
- // CLI 结果转换为原有格式
649
- return {
650
- data: {
651
- headers: result.headers || [],
652
- data: result.data || [],
653
- pageNum: result.pagination?.pageNum || pageNum,
654
- pageSize: result.pagination?.pageSize || pageSize,
655
- total: result.pagination?.total || 0,
656
- }
657
- };
648
+ // CLI 返回格式: { data: [], pagination: { page, pageSize, total } }
649
+ return { data: result.data || [] };
658
650
  } catch (e) {
659
651
  console.warn(`⚠️ CLI 查询数据失败,回退到直接 API: ${e.message}`);
660
652
  useCliMode = false;
@@ -676,22 +668,14 @@ export async function getModelData(token, modelCode, params = {}, options = {})
676
668
 
677
669
  const body = {
678
670
  modelCode,
679
- params: {},
671
+ groupFields: groupFields || [],
672
+ functions: functions || [],
673
+ customQuery: customQuery || {},
674
+ page,
675
+ pageSize,
680
676
  };
681
677
 
682
- if (customQuery) {
683
- body.params.customQuery = customQuery;
684
- }
685
-
686
- if (groupFields && groupFields.length > 0) {
687
- body.params.groupFields = groupFields;
688
- }
689
-
690
- if (functions && functions.length > 0) {
691
- body.params.functions = functions;
692
- }
693
-
694
- const response = await fetch(`${baseUrl}/foresight/api/bi/multdim/anls/ai/query`, {
678
+ const response = await fetch(`${baseUrl}/foresight/api/bi/multdim/anls/ai/query/by/co`, {
695
679
  method: 'POST',
696
680
  headers,
697
681
  body: JSON.stringify(body),
package/src/api.js CHANGED
@@ -30,7 +30,7 @@ const BASIC_AUTH = 'Basic UEM6bkxDbndkSWhpeldieWtIeXVaTTZUcFFEZDdLd0s5SVhESzhMR3
30
30
 
31
31
  const DEFAULT_MENU_HEADERS = {
32
32
  'x-menu-code': 'AI_REPORT',
33
- 'x-menu-id': '2008425412219936770',
33
+ 'x-menu-id': '2009191076595752963',
34
34
  'x-menu-params': 'null',
35
35
  'x-page-code': 'ai_report',
36
36
  };
@@ -326,7 +326,7 @@ export async function getModelColumns(token, modelCodes) {
326
326
  // 查询模型数据
327
327
  export async function getModelData(token, modelCode, params = {}) {
328
328
  const baseUrl = getBaseUrl();
329
- const response = await fetch(baseUrl + '/foresight/api/bi/multdim/anls/ai/query', {
329
+ const response = await fetch(baseUrl + '/foresight/api/bi/multdim/anls/ai/query/by/co', {
330
330
  method: 'POST',
331
331
  headers: {
332
332
  'accept': 'application/json, text/plain, */*',
@@ -336,11 +336,11 @@ export async function getModelData(token, modelCode, params = {}) {
336
336
  },
337
337
  body: JSON.stringify({
338
338
  modelCode,
339
- params: {
340
- pageNum: params.pageNum || 0,
341
- pageSize: params.pageSize || 100,
342
- ...params,
343
- },
339
+ groupFields: params.groupFields || [],
340
+ functions: params.functions || [],
341
+ customQuery: params.customQuery || {},
342
+ page: params.page || params.pageNum || 0,
343
+ pageSize: params.pageSize || 100,
344
344
  }),
345
345
  });
346
346
 
package/src/cli.js CHANGED
@@ -246,7 +246,7 @@ userCmd
246
246
  const userInfo = await getUserInfo();
247
247
 
248
248
  const tenants = (userInfo.tenantList || []).map(t => ({
249
- tenantId: t.tenantId,
249
+ tenantId: t.id, // API 返回的字段名是 id
250
250
  tenantName: t.tenantName,
251
251
  tenantCode: t.tenantCode,
252
252
  isCurrent: t.tenantCode === userInfo.user?.tenantCode,
@@ -256,6 +256,7 @@ userCmd
256
256
  tenants,
257
257
  total: tenants.length,
258
258
  currentTenantCode: userInfo.user?.tenantCode || '',
259
+ currentTenantId: userInfo.user?.tenantId || '',
259
260
  });
260
261
  } catch (error) {
261
262
  printError(error);
@@ -371,23 +372,118 @@ dataCmd
371
372
  .description('Query data from a model')
372
373
  .option('-p, --page <number>', 'Page number (starting from 0)', '0')
373
374
  .option('-s, --size <number>', 'Page size', '100')
375
+ .option('-q, --query <json>', 'Query condition (JSON format)')
376
+ .option('-g, --group <fields>', 'Group fields (comma separated)')
377
+ .option('-f, --functions <json>', 'Aggregation functions (JSON array)')
378
+ .addHelpText('after', `
379
+ Examples:
380
+ # Simple query
381
+ byteplan data query CBEC_PRODUCT -p 0 -s 10
382
+
383
+ # With filter condition
384
+ byteplan data query CBEC_PRODUCT -q '{"type":"condition","field":"category","operator":"=","value":"饮料"}'
385
+
386
+ # With multiple conditions (AND)
387
+ byteplan data query CBEC_PRODUCT -q '{"type":"group","logic":"AND","children":[{"type":"condition","field":"category","operator":"=","value":"饮料"},{"type":"condition","field":"selling_price","operator":">","value":"5"}]}'
388
+
389
+ # With grouping
390
+ byteplan data query CBEC_PRODUCT -g category,subcategory
391
+
392
+ # With aggregation functions
393
+ byteplan data query CBEC_ORDER -g product_id -f '[{"func":"sum","field":"quantity","alias":"total_qty"},{"func":"avg","field":"unit_price","alias":"avg_price"}]'
394
+
395
+ # Complete aggregation example
396
+ byteplan data query CBEC_ORDER -g product_id -q '{"type":"condition","field":"order_date","operator":"BETWEEN","value":["2024-01-01","2024-12-31"]}' -f '[{"func":"sum","field":"amount","alias":"total_amount"},{"func":"count","field":"id","alias":"order_count"}]'
397
+
398
+ Query Syntax:
399
+
400
+ 1. Single Condition:
401
+ {
402
+ "type": "condition",
403
+ "field": "字段名",
404
+ "operator": "=",
405
+ "value": "值"
406
+ }
407
+
408
+ 2. Condition Group (AND/OR):
409
+ {
410
+ "type": "group",
411
+ "logic": "AND",
412
+ "children": [
413
+ { "type": "condition", "field": "field1", "operator": "=", "value": "value1" },
414
+ { "type": "condition", "field": "field2", "operator": ">", "value": "value2" }
415
+ ]
416
+ }
417
+
418
+ Operators: =, !=, >, <, >=, <=, LIKE, IN, BETWEEN
419
+
420
+ Special Fields (DIM/LIST/LOV/LEVEL):
421
+ - Use field name directly (no .code or .name suffix)
422
+ - Use code value for filtering
423
+
424
+ Group Fields (-g):
425
+ Comma-separated field names for aggregation grouping
426
+ Example: -g category,subcategory
427
+
428
+ Aggregation Functions (-f):
429
+ JSON array of function objects:
430
+ [
431
+ { "func": "sum", "field": "数值字段", "alias": "别名" },
432
+ { "func": "avg", "field": "数值字段", "alias": "别名" },
433
+ { "func": "count", "field": "任意字段", "alias": "别名" },
434
+ { "func": "max", "field": "字段", "alias": "别名" },
435
+ { "func": "min", "field": "字段", "alias": "别名" }
436
+ ]
437
+
438
+ Supported functions: sum, avg, count, max, min
439
+
440
+ Note: When using aggregation functions, -g (group) is usually needed.
441
+ Without grouping, aggregation returns a single summary row.
442
+ `)
374
443
  .action(async (modelCode, options) => {
375
444
  try {
376
445
  await loginWithEnv();
377
- const result = await getModelData(null, modelCode, {
378
- pageNum: parseInt(options.page),
446
+
447
+ const params = {
448
+ page: parseInt(options.page),
379
449
  pageSize: parseInt(options.size),
380
- });
450
+ };
451
+
452
+ // 解析查询条件
453
+ if (options.query) {
454
+ try {
455
+ params.customQuery = JSON.parse(options.query);
456
+ } catch (e) {
457
+ printJSON({ error: true, message: 'Invalid JSON query: ' + e.message });
458
+ process.exit(1);
459
+ }
460
+ }
381
461
 
382
- // result.data 可能是数组(直接数据)或对象(包含 data 子字段)
383
- const rows = Array.isArray(result.data) ? result.data : (result.data?.data || []);
462
+ // 解析分组字段
463
+ if (options.group) {
464
+ params.groupFields = options.group.split(',').map(f => f.trim());
465
+ }
466
+
467
+ // 解析聚合函数
468
+ if (options.functions) {
469
+ try {
470
+ params.functions = JSON.parse(options.functions);
471
+ } catch (e) {
472
+ printJSON({ error: true, message: 'Invalid JSON functions: ' + e.message });
473
+ process.exit(1);
474
+ }
475
+ }
476
+
477
+ const result = await getModelData(null, modelCode, params);
478
+
479
+ // result.data 是数据数组
480
+ const rows = Array.isArray(result.data) ? result.data : [];
384
481
  printJSON({
385
- headers: result.headers || result.data?.headers || [],
386
482
  data: rows,
387
483
  pagination: {
388
- pageNum: result.pageNum || result.data?.pageNum || parseInt(options.page),
389
- pageSize: result.pageSize || result.data?.pageSize || parseInt(options.size),
390
- total: result.total || result.data?.total || 0,
484
+ page: parseInt(options.page),
485
+ pageSize: parseInt(options.size),
486
+ total: rows.length,
391
487
  },
392
488
  });
393
489
  } catch (error) {