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 +1 -1
- package/skills/byteplan-api/scripts/api.js +13 -29
- package/src/api.js +7 -7
- package/src/cli.js +106 -10
package/package.json
CHANGED
|
@@ -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<
|
|
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(
|
|
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
|
-
//
|
|
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
|
-
|
|
671
|
+
groupFields: groupFields || [],
|
|
672
|
+
functions: functions || [],
|
|
673
|
+
customQuery: customQuery || {},
|
|
674
|
+
page,
|
|
675
|
+
pageSize,
|
|
680
676
|
};
|
|
681
677
|
|
|
682
|
-
|
|
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': '
|
|
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
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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.
|
|
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
|
-
|
|
378
|
-
|
|
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
|
-
//
|
|
383
|
-
|
|
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
|
-
|
|
389
|
-
pageSize:
|
|
390
|
-
total:
|
|
484
|
+
page: parseInt(options.page),
|
|
485
|
+
pageSize: parseInt(options.size),
|
|
486
|
+
total: rows.length,
|
|
391
487
|
},
|
|
392
488
|
});
|
|
393
489
|
} catch (error) {
|