e10-data 0.1.8 → 0.1.9

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.
Files changed (3) hide show
  1. package/README.md +60 -1
  2. package/bin/e10-data.mjs +166 -74
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -19,7 +19,7 @@ e10-data ds tables|fields|list|chart|stat|count 数据源(业务模块
19
19
  e10-data doc count|list 文档查询(documentListCount + documentList)
20
20
  e10-data noun list --skill <skillKey> 词库查询(可带 --source-type/--source-group/--source-table 三参数)
21
21
  e10-data field id2name|name2id 关联字段翻译(testRemoteBrowser / complete)
22
- e10-data conf get|batch|batch-file|resolve|resolve-file|add|add-file|update|delete 环境参数配置中心(chatBi config map,替代 config-resolve 脚本 URL 直连;confType 默认按 CONN_/DS_/WF_ 前缀推导,可 --type 显式)
22
+ e10-data conf get|batch|batch-file|group|group-file|resolve|resolve-file|add|add-file|update|delete 环境参数配置中心(chatBi config map,替代 config-resolve 脚本 URL 直连;confType 默认按 CONN_/DS_/WF_/API_ 前缀推导,可 --type 显式;confType=api 时支持 confGroup 分组,见下)
23
23
  e10-data exp status|manifest|commits|file|pull|init|commit|lock|release|rollback 专家包版本管理
24
24
  e10-data attend statis 考勤假期余额统计 getAttendInfoStatis(hr-attendance 病假/事假等,v0.1.5 新增)
25
25
  ```
@@ -47,12 +47,71 @@ e10-data conf get CONN_EC_EDCAPP # 读配置
47
47
  e10-data conf resolve '{"connId":"#{CONN_EC_EDCAPP}"}' # 占位符替换为真实值
48
48
  e10-data conf add CONN_EC_EDCAPP --value 10 --name "说明" --attrs '{"schema":"ec_edcapp"}'
49
49
  e10-data conf delete CONN_EC_EDCAPP
50
+ # confType=api + confGroup 分组(v0.1.9 新增)
51
+ e10-data conf group api workflow # 按 类型+分组 批量查全部配置
52
+ e10-data conf get GET_WORKFLOW_LIST --type api --group workflow # 单查(组内定位)
53
+ e10-data conf add GET_WORKFLOW_LIST --type api --group workflow --value /api/workflow/getList --name 查询流程列表 --attrs '{"request":{"pageNo":"页码"},"response":{"list":"流程列表"}}'
54
+ e10-data conf add-file @api-items.json # 批量新增(元素含 confGroup,见下)
55
+ e10-data conf update GET_WORKFLOW_LIST --type api --group workflow --value /api/workflow/queryList
56
+ e10-data conf delete GET_WORKFLOW_LIST --type api --group workflow
50
57
  e10-data exp status --expert data-assistant
51
58
  e10-data exp pull --expert data-assistant --dir <本地专家包目录> [--dry-run] [--force]
52
59
  e10-data attend statis # 查当前登录用户当月假期余额(病假/事假/年假)
53
60
  e10-data attend statis --user 6264843388578732287 --begin 2026-09-01 --end 2026-09-30
54
61
  ```
55
62
 
63
+ ## conf 配置中心与 confGroup 分组(v0.1.9 新增)
64
+
65
+ `conf` 系列对接 chatBi config map 接口,`confGroup` 是**可选**的二级分组维度:后端在 `confType=api` 时按 `confType + confGroup + confKey` 定位配置(如 `api/workflow/GET_WORKFLOW_LIST`),用于把同类 API 定义归档到同一分组。
66
+
67
+ **下发规则(重要)**:只有 `confType` 为 `api`(或显式传了 `--group`)时,CLI 才会在请求体/查询串里带上 `confGroup`;其他 confType 一律不带该字段,避免污染既有配置类型。
68
+
69
+ | 操作 | 命令 | 对应接口 |
70
+ |---|---|---|
71
+ | 新增(批量,可含分组) | `conf add <key> --value v [--type api] [--group g]` / `conf add-file @items.json` | `POST /api/dw/newetl/chatBi/batchAddChatBiConfigMap` |
72
+ | 单查 | `conf get <key> [--type api] [--group g]` | `GET /api/dw/newetl/chatBi/getChatBiConfigMap?confType=&confGroup=&confKey=` |
73
+ | 批量查(按 key) | `conf batch <k1> <k2> ...` / `conf batch-file @items.json` | `POST /api/dw/newetl/chatBi/batchGetChatBiConfigMap` |
74
+ | 批量查(按类型+分组) | `conf group <confType> <confGroup> [--key k]` / `conf group-file @items.json` | `POST /api/dw/newetl/chatBi/batchGetChatBiConfigMapByTypeAndGroup` |
75
+ | 更新 | `conf update <key> [--value v] [--name n] [--attrs a] [--group g]` | `POST /api/dw/newetl/chatBi/updateChatBiConfigMap` |
76
+ | 删除 | `conf delete <key> [--type api] [--group g]` | `DELETE /api/dw/newetl/chatBi/deleteChatBiConfigMap?confType=&confGroup=&confKey=` |
77
+
78
+ 批量新增文件 `api-items.json`(`confType=api` 时元素带 `confGroup`):
79
+
80
+ ```json
81
+ [
82
+ {
83
+ "confType": "api",
84
+ "confGroup": "workflow",
85
+ "confKey": "GET_WORKFLOW_LIST",
86
+ "confValue": "/api/workflow/getList",
87
+ "confName": "查询流程列表",
88
+ "confAttrs": "{\"request\":{\"pageNo\":\"页码\",\"pageSize\":\"每页数量\"},\"response\":{\"list\":\"流程列表\"}}"
89
+ },
90
+ {
91
+ "confType": "api",
92
+ "confGroup": "workflow",
93
+ "confKey": "GET_WORKFLOW_DETAIL",
94
+ "confValue": "/api/workflow/getDetail",
95
+ "confName": "查询流程详情",
96
+ "confAttrs": "{\"request\":{\"id\":\"流程ID\"},\"response\":{\"id\":\"流程ID\",\"name\":\"流程名称\"}}"
97
+ }
98
+ ]
99
+ ```
100
+
101
+ ```bash
102
+ e10-data conf add-file @api-items.json # 批量新增(逐条判重:同 组+键 已存在则跳过)
103
+ e10-data conf group api workflow # 取回 workflow 分组下全部 API 配置
104
+ e10-data conf group-file @groups.json # 多分组一次取回,@groups.json = [{"confType":"api","confGroup":"workflow"}]
105
+ e10-data conf update GET_WORKFLOW_LIST --type api --group workflow --value /api/workflow/queryList
106
+ e10-data conf delete GET_WORKFLOW_LIST --type api --group workflow
107
+ ```
108
+
109
+ 补充说明:
110
+
111
+ - `confKey` 前缀推导 confType:`CONN_→conn`、`DS_→ds`、`WF_→wf`、`API_→api`;其余类型用 `--type` 显式指定(`--type` 与 `--group` 可同时使用)。
112
+ - 同一 `confKey` 可存在于多个 `confGroup`;`conf batch` / `batch-file` 的返回映射在带分组时以 `组|键` 为键,不会互相覆盖。
113
+ - `--json` 输出:`conf group` 返回配置数组(带 `--key` 时返回单条),`conf batch` 返回映射对象。
114
+
56
115
  ## ds --where 过滤条件(v0.1.8 起支持树形 OR)
57
116
 
58
117
  `e10-data ds list|chart|stat|count --where` 接收**条件数组**或**完整条件树**,均可递归嵌套表达 AND/OR:
package/bin/e10-data.mjs CHANGED
@@ -9,8 +9,9 @@
9
9
  * e10-data doc count|list 文档查询 documentListCount / documentList
10
10
  * e10-data noun list 词库 getChatDocsBySkillKey
11
11
  * e10-data field id2name|name2id 关联字段翻译 testRemoteBrowser / complete
12
- * e10-data conf get|batch|batch-file|resolve|resolve-file|add|add-file|update|delete
13
- * 环境参数配置中心(chatBi config map,替代 config-resolve 脚本 URL 直连)
12
+ * e10-data conf get|batch|batch-file|group|group-file|resolve|resolve-file|add|add-file|update|delete
13
+ * 环境参数配置中心(chatBi config map,替代 config-resolve 脚本 URL 直连;
14
+ * confType=api 时支持 confGroup 分组二级定位,见 --group)
14
15
  * e10-data attend statis 考勤假期余额统计 getAttendInfoStatis(hr-attendance 病假/事假,2026-09-07)
15
16
  *
16
17
  * 通用:--json 原样输出;复杂 JSON 参数支持 @文件 或 内联(中文走 @文件 更稳)
@@ -265,6 +266,11 @@ function readJsonArg(val, label) {
265
266
  return parseJsonSafe(raw, label);
266
267
  }
267
268
  function need(arg, args) { if (!args[arg]) throw new Error("缺少必填参数 --" + arg); return args[arg]; }
269
+ // 文件/JSON 参数取值:兼容 --flag <v> 与位置参数 <v>(如 conf add-file @items.json / --add-file @items.json)
270
+ function flagOrPos(args, flag, keys) {
271
+ if (args[flag] !== undefined) return args[flag];
272
+ return keys && keys.length ? keys[0] : undefined;
273
+ }
268
274
 
269
275
  // ---------------- 展示 ----------------
270
276
  function fmt(v) {
@@ -553,13 +559,21 @@ async function cmdFieldName2id(args, json) {
553
559
  }
554
560
 
555
561
  // ---------------- conf:环境参数配置中心(chatBi config map) ----------------
556
- // 覆盖 config-resolve 原 resolve_config.py 的 URL 直连调用:get/batch/batch-file/resolve/resolve-file
562
+ // 覆盖 config-resolve 原 resolve_config.py 的 URL 直连调用:get/batch/batch-file/group/group-file/resolve/resolve-file
557
563
  // 与管理 add/add-file/update/delete。认证复用进程内登录缓存(完整 Cookie + eteamsid,同 query/ds/doc),
558
564
  // 无内置令牌;baseUrl 取登录缓存(与 executeQueryDsl 同域)。confType 默认由 key 前缀推导
559
- // (CONN_→conn / DS_→ds / WF_→wf),可用 --type 显式指定任意大类(如 data-source-query / system-config)。
560
- const CONF_PREFIX_TYPE = [["CONN_", "conn"], ["DS_", "ds"], ["WF_", "wf"]];
565
+ // (CONN_→conn / DS_→ds / WF_→wf / API_→api),可用 --type 显式指定任意大类(如 data-source-query / system-config)。
566
+ //
567
+ // v0.1.9 confGroup(配置分组,可选):
568
+ // 后端在 confType=api 时支持按分组二次分层(如 api/workflow、api/hr),定位维度变为
569
+ // 「confType + confGroup + confKey」。本 CLI 统一用 --group 传分组:
570
+ // · confType 为 api(或显式传了 --group)时,新增/更新/删除/单查 才下发 confGroup 字段,
571
+ // 其他 confType 一律不带该字段,避免污染既有(无分组列)的配置类型。
572
+ // · conf group <confType> <confGroup> 走 batchGetChatBiConfigMapByTypeAndGroup 按类型+分组批量取回。
573
+ const CONF_PREFIX_TYPE = [["CONN_", "conn"], ["DS_", "ds"], ["WF_", "wf"], ["API_", "api"]];
561
574
  const CONF_GET_PATH = "/api/dw/newetl/chatBi/getChatBiConfigMap";
562
575
  const CONF_BATCH_PATH = "/api/dw/newetl/chatBi/batchGetChatBiConfigMap";
576
+ const CONF_BATCH_GROUP_PATH = "/api/dw/newetl/chatBi/batchGetChatBiConfigMapByTypeAndGroup";
563
577
  const CONF_ADD_PATH = "/api/dw/newetl/chatBi/batchAddChatBiConfigMap";
564
578
  const CONF_UPDATE_PATH = "/api/dw/newetl/chatBi/updateChatBiConfigMap";
565
579
  const CONF_DELETE_PATH = "/api/dw/newetl/chatBi/deleteChatBiConfigMap";
@@ -567,7 +581,25 @@ const CONF_TOKEN_RE = /#\{([A-Z][A-Z0-9_]{2,})\}/g;
567
581
  function confKeyType(key, explicitType) {
568
582
  if (explicitType) return explicitType;
569
583
  for (const [p, t] of CONF_PREFIX_TYPE) if (key.startsWith(p)) return t;
570
- throw new Error("无法由 confKey 推导 confType(需 CONN_/DS_/WF_ 前缀或显式 --type): " + key);
584
+ throw new Error("无法由 confKey 推导 confType(需 CONN_/DS_/WF_/API_ 前缀或显式 --type): " + key);
585
+ }
586
+ // confGroup 仅在 confType=api 或调用方显式指定时下发(见上方说明)
587
+ function confUseGroup(ctype, group) {
588
+ return ctype === "api" || (group !== undefined && group !== null && group !== "");
589
+ }
590
+ function confPutGroup(body, ctype, group) {
591
+ if (confUseGroup(ctype, group)) body.confGroup = group === undefined || group === null ? "" : String(group);
592
+ return body;
593
+ }
594
+ function confGroupSuffix(ctype, group) { // GET/DELETE 用的 query 后缀
595
+ return confUseGroup(ctype, group) ? "&confGroup=" + encodeURIComponent(group === undefined || group === null ? "" : String(group)) : "";
596
+ }
597
+ function confItemId(it) { // 同 confKey 可分布在多个 confGroup,带分组时用「组|键」做映射键,避免互相覆盖
598
+ const g = it && it.confGroup;
599
+ return g ? g + "|" + (it.confKey || "") : ((it && it.confKey) || "");
600
+ }
601
+ function confLookup(map, it) { // 兼容后端回包是否带 confGroup:先按「组|键」取,再退化到 confKey
602
+ return map[confItemId(it)] || map[it.confKey];
571
603
  }
572
604
  function confFail(j, url) {
573
605
  const m = (j && (j.msg || (j.actionMsg && j.actionMsg.message))) || "";
@@ -592,51 +624,62 @@ async function confRequest(method, url, bodyObj) {
592
624
  checkAuthFail(resp, text, j);
593
625
  return j;
594
626
  }
595
- async function confGetData(ctype, key, silent) {
596
- const url = CONF_GET_PATH + "?confType=" + encodeURIComponent(ctype) + "&confKey=" + encodeURIComponent(key);
627
+ async function confGetData(ctype, key, silent, group) {
628
+ const url = CONF_GET_PATH + "?confType=" + encodeURIComponent(ctype) + "&confKey=" + encodeURIComponent(key) + confGroupSuffix(ctype, group);
597
629
  let r;
598
630
  try { r = await confRequest("GET", url); }
599
631
  catch (e) { if (silent) return null; throw e; }
600
632
  const data = (r && r.data) || null;
601
633
  if (!silent && (!data || data.confValue === undefined || data.confValue === null || data.confValue === "")) {
602
- throw new Error("配置不存在或为空: confType=" + ctype + " confKey=" + key);
634
+ throw new Error("配置不存在或为空: confType=" + ctype + (group ? " confGroup=" + group : "") + " confKey=" + key);
603
635
  }
604
636
  return data;
605
637
  }
606
638
  function confNormalizeBatch(payload) {
607
639
  const data = (payload && payload.data) || null;
608
640
  const out = {};
609
- if (Array.isArray(data)) {
610
- for (const row of data) {
611
- if (!row || typeof row !== "object") continue;
612
- const k = row.confKey || row.conf_key;
613
- if (k) out[k] = row;
614
- }
615
- } else if (data && typeof data === "object") {
616
- for (const [k, v] of Object.entries(data)) {
617
- if (v && typeof v === "object" && !v.confKey) v.confKey = k;
618
- out[k] = v;
619
- }
620
- }
641
+ const put = (row, fallbackKey) => {
642
+ if (!row || typeof row !== "object") return;
643
+ const k = row.confKey || row.conf_key || fallbackKey;
644
+ if (!k) return;
645
+ if (row.confGroup === undefined) { const g = row.conf_group; if (g !== undefined && g !== null && g !== "") row.confGroup = g; }
646
+ out[confItemId({ confGroup: row.confGroup, confKey: k })] = row;
647
+ };
648
+ if (Array.isArray(data)) for (const row of data) put(row);
649
+ else if (data && typeof data === "object") for (const [k, v] of Object.entries(data)) put(v, k);
621
650
  return out;
622
651
  }
652
+ // 按类型+分组批量取回(batchGetChatBiConfigMapByTypeAndGroup),payload = [{confType, confGroup}...]
653
+ async function confBatchByTypeAndGroup(pairs) {
654
+ const payload = pairs.map((p) => ({ confType: p.confType, confGroup: p.confGroup === undefined || p.confGroup === null ? "" : String(p.confGroup) }));
655
+ const r = await confRequest("POST", CONF_BATCH_GROUP_PATH, payload);
656
+ return confNormalizeBatch(r);
657
+ }
623
658
  async function cmdConfGet(args, json, keys) {
624
659
  const key = keys[0];
625
- if (!key) throw new Error("conf get 缺少 confKey(用法: conf get <key> [--type t])");
660
+ if (!key) throw new Error("conf get 缺少 confKey(用法: conf get <key> [--type t] [--group g])");
626
661
  const ctype = confKeyType(key, args.type);
627
- const data = await confGetData(ctype, key);
662
+ let data;
663
+ try {
664
+ data = await confGetData(ctype, key, false, args.group);
665
+ } catch (e) {
666
+ if (ctype === "api" && !args.group) {
667
+ throw new Error(e.message + "(confType=api 建议用 --group 指定分组,如 --group workflow;或用 conf group api <分组> 查看该分组下全部配置)");
668
+ }
669
+ throw e;
670
+ }
628
671
  if (json) return data;
629
672
  console.log(JSON.stringify(data, null, 1));
630
673
  }
631
674
  async function cmdConfBatch(args, json, keys) {
632
- if (!keys.length) throw new Error("conf batch 缺少 confKey 列表(用法: conf batch <key1> [key2 ...])");
633
- const items = keys.map((k) => ({ confType: confKeyType(k, args.type), confKey: k }));
675
+ if (!keys.length) throw new Error("conf batch 缺少 confKey 列表(用法: conf batch <key1> [key2 ...] [--type t] [--group g])");
676
+ const items = keys.map((k) => { const t = confKeyType(k, args.type); return confPutGroup({ confType: t, confKey: k }, t, args.group); });
634
677
  let map = {};
635
678
  try {
636
679
  const r = await confRequest("POST", CONF_BATCH_PATH, items);
637
680
  map = confNormalizeBatch(r);
638
681
  for (const it of items) {
639
- const c = map[it.confKey];
682
+ const c = confLookup(map, it);
640
683
  if (!c || c.confValue === undefined || c.confValue === null || c.confValue === "") {
641
684
  throw new Error("批量响应缺失 confKey=" + it.confKey);
642
685
  }
@@ -645,43 +688,82 @@ async function cmdConfBatch(args, json, keys) {
645
688
  if (String(e.message).indexOf("批量响应缺失") === 0) throw e;
646
689
  console.error("[config-resolve] 批量接口不可用,降级逐条单查: " + e.message);
647
690
  map = {};
648
- for (const it of items) map[it.confKey] = await confGetData(it.confType, it.confKey);
691
+ for (const it of items) map[confItemId(it)] = await confGetData(it.confType, it.confKey, false, it.confGroup);
649
692
  }
650
693
  if (json) return map;
651
- printHuman("配置 " + items.length + " 条", keys.map((k) => ({ key: k, confType: items.find((x) => x.confKey === k).confType, confValue: (map[k] || {}).confValue ?? "", confName: (map[k] || {}).confName ?? "" })), ["key", "confType", "confValue", "confName"]);
652
- }
653
- async function cmdConfBatchFile(args, json) {
654
- if (!args["batch-file"]) throw new Error("conf batch-file 缺少参数(用法: conf batch-file @items.json)");
655
- const items = readJsonArg(args["batch-file"], "--batch-file");
694
+ printHuman("配置 " + items.length + " 条", keys.map((k) => {
695
+ const it = items.find((x) => x.confKey === k);
696
+ const c = confLookup(map, it) || {};
697
+ return { key: k, confType: it.confType, confGroup: it.confGroup ?? "", confValue: c.confValue ?? "", confName: c.confName ?? "" };
698
+ }), ["key", "confType", "confGroup", "confValue", "confName"]);
699
+ }
700
+ async function cmdConfBatchFile(args, json, keys) {
701
+ const val = flagOrPos(args, "batch-file", keys);
702
+ if (val === undefined) throw new Error("conf batch-file 缺少参数(用法: conf batch-file @items.json)");
703
+ const items = readJsonArg(String(val), "--batch-file");
656
704
  const list = Array.isArray(items) ? items : [items];
657
705
  const map = {};
706
+ const meta = {};
658
707
  for (const it of list) {
659
708
  if (!it.confKey || !it.confType) continue;
660
- map[it.confKey] = await confGetData(it.confType, it.confKey);
709
+ const id = confItemId(it);
710
+ map[id] = await confGetData(it.confType, it.confKey, false, it.confGroup);
711
+ meta[id] = it;
661
712
  }
662
713
  if (json) return map;
663
- printHuman("配置 " + Object.keys(map).length + " 条", Object.keys(map).map((k) => ({ key: k, confValue: (map[k] || {}).confValue ?? "", confName: (map[k] || {}).confName ?? "" })), ["key", "confValue", "confName"]);
714
+ printHuman("配置 " + Object.keys(map).length + " 条", Object.keys(map).map((id) => ({ key: meta[id].confKey, confGroup: meta[id].confGroup ?? "", confValue: (map[id] || {}).confValue ?? "", confName: (map[id] || {}).confName ?? "" })), ["key", "confGroup", "confValue", "confName"]);
715
+ }
716
+ // 按类型+分组批量查(batchGetChatBiConfigMapByTypeAndGroup):pairs = [{confType, confGroup}...]
717
+ async function cmdConfGroup(args, json, keys) {
718
+ const ctype = keys[0] || args.type;
719
+ const group = keys[1] !== undefined ? keys[1] : args.group;
720
+ if (!ctype) throw new Error("conf group 缺少 confType(用法: conf group <confType> <confGroup> | --type api --group workflow)");
721
+ if (group === undefined) throw new Error("conf group 缺少 confGroup(用法: conf group <confType> <confGroup>)");
722
+ const map = await confBatchByTypeAndGroup([{ confType: ctype, confGroup: group }]);
723
+ const rows = Object.values(map);
724
+ const onlyKey = args.key;
725
+ const filtered = onlyKey ? rows.filter((r) => (r.confKey || r.conf_key) === onlyKey) : rows;
726
+ if (json) return onlyKey ? (filtered[0] ?? null) : filtered;
727
+ if (onlyKey && !filtered.length) throw new Error("配置不存在: confType=" + ctype + " confGroup=" + group + " confKey=" + onlyKey);
728
+ printHuman("confType=" + ctype + " confGroup=" + group + " 配置 " + filtered.length + " 条",
729
+ filtered.map((r) => ({ confKey: r.confKey || r.conf_key || "", confValue: r.confValue ?? "", confName: r.confName ?? "", confAttrs: r.confAttrs ?? "" })),
730
+ ["confKey", "confValue", "confName", "confAttrs"]);
731
+ return filtered;
732
+ }
733
+ async function cmdConfGroupFile(args, json, keys) {
734
+ const val = flagOrPos(args, "group-file", keys);
735
+ if (val === undefined) throw new Error("conf group-file 缺少参数(用法: conf group-file @items.json,形如 [{\"confType\":\"api\",\"confGroup\":\"workflow\"}])");
736
+ const pairs = readJsonArg(String(val), "--group-file");
737
+ const list = (Array.isArray(pairs) ? pairs : [pairs]).filter((p) => p && p.confType);
738
+ if (!list.length) throw new Error("conf group-file 内容为空或缺少 confType");
739
+ const map = await confBatchByTypeAndGroup(list);
740
+ const rows = Object.values(map);
741
+ if (json) return map;
742
+ printHuman("批量分组配置 " + rows.length + " 条",
743
+ rows.map((r) => ({ confType: r.confType ?? "", confGroup: r.confGroup ?? "", confKey: r.confKey || r.conf_key || "", confValue: r.confValue ?? "", confName: r.confName ?? "" })),
744
+ ["confType", "confGroup", "confKey", "confValue", "confName"]);
745
+ return map;
664
746
  }
665
- async function confResolveAll(keys) {
747
+ async function confResolveAll(keys, group) {
666
748
  // 多占位符:先批量预取一轮(失败降级逐条单查),返回 {key: data}
667
- const items = keys.map((k) => ({ confType: confKeyType(k, ""), confKey: k }));
749
+ const items = keys.map((k) => confPutGroup({ confType: confKeyType(k, ""), confKey: k }, confKeyType(k, ""), group));
668
750
  const map = {};
669
751
  try {
670
752
  const r = await confRequest("POST", CONF_BATCH_PATH, items);
671
753
  const got = confNormalizeBatch(r);
672
754
  for (const it of items) {
673
- const c = got[it.confKey];
755
+ const c = confLookup(got, it);
674
756
  if (!c || c.confValue === undefined || c.confValue === null || c.confValue === "") throw new Error("缺失 " + it.confKey);
675
757
  map[it.confKey] = c;
676
758
  }
677
759
  } catch {
678
- for (const it of items) map[it.confKey] = await confGetData(it.confType, it.confKey);
760
+ for (const it of items) map[it.confKey] = await confGetData(it.confType, it.confKey, false, it.confGroup);
679
761
  }
680
762
  return map;
681
763
  }
682
- async function confResolveText(text, json) {
764
+ async function confResolveText(text, json, group) {
683
765
  const found = [...new Set([...text.matchAll(CONF_TOKEN_RE)].map((m) => m[1]))];
684
- const map = found.length ? await confResolveAll(found) : {};
766
+ const map = found.length ? await confResolveAll(found, group) : {};
685
767
  const out = text.replace(CONF_TOKEN_RE, (m0, k) => {
686
768
  const cfg = map[k];
687
769
  if (!cfg) throw new Error("配置不存在或为空: " + k);
@@ -692,45 +774,47 @@ async function confResolveText(text, json) {
692
774
  }
693
775
  async function cmdConfResolve(args, json, keys) {
694
776
  let text = keys[0];
695
- if (!text) throw new Error("conf resolve 缺少文本(用法: conf resolve '<含#{KEY}文本>' | @file.txt)");
777
+ if (!text) throw new Error("conf resolve 缺少文本(用法: conf resolve '<含#{KEY}文本>' | @file.txt [--group g])");
696
778
  if (text.startsWith("@")) text = fs.readFileSync(text.slice(1), "utf-8");
697
- const out = await confResolveText(text, json);
779
+ const out = await confResolveText(text, json, args.group);
698
780
  if (json) { console.log(JSON.stringify(out, null, 1)); return out; }
699
781
  process.stdout.write(out + "\n");
700
782
  }
701
- async function cmdConfResolveFile(args, json) {
702
- const p = args["resolve-file"];
703
- if (!p) throw new Error("conf resolve-file 缺少文件路径(用法: conf resolve-file <文件路径>)");
783
+ async function cmdConfResolveFile(args, json, keys) {
784
+ const p = flagOrPos(args, "resolve-file", keys);
785
+ if (!p) throw new Error("conf resolve-file 缺少文件路径(用法: conf resolve-file <文件路径> [--group g])");
704
786
  if (!fs.existsSync(p)) throw new Error("文件不存在: " + p);
705
787
  const text = fs.readFileSync(p, "utf-8");
706
- const out = await confResolveText(text, json);
788
+ const out = await confResolveText(text, json, args.group);
707
789
  if (json) { console.log(JSON.stringify(out, null, 1)); return out; }
708
790
  process.stdout.write(out + "\n");
709
791
  }
710
792
  async function cmdConfAdd(args, json, keys) {
711
793
  const key = keys[0];
712
- if (!key || args.value === undefined) throw new Error("conf add 缺少 confKey/confValue(用法: conf add <key> --value <真实值> [--name] [--attrs] [--type] [--force])");
794
+ if (!key || args.value === undefined) throw new Error("conf add 缺少 confKey/confValue(用法: conf add <key> --value <真实值> [--name] [--attrs] [--type] [--group] [--force])");
713
795
  const ctype = confKeyType(key, args.type);
714
- if (!args.force && await confGetData(ctype, key, true)) {
796
+ if (!args.force && await confGetData(ctype, key, true, args.group)) {
715
797
  console.error("[config-resolve] 配置已存在,跳过新增(如需修改请用 conf update;确需重建可先 conf delete): " + key);
716
798
  return null;
717
799
  }
718
- const item = { confType: ctype, confKey: key, confValue: String(args.value), confAttrs: args.attrs || "", confName: args.name || "" };
800
+ const item = confPutGroup({ confType: ctype, confKey: key, confValue: String(args.value), confAttrs: args.attrs || "", confName: args.name || "" }, ctype, args.group);
719
801
  const r = await confRequest("POST", CONF_ADD_PATH, [item]);
720
802
  if (json) return r;
721
- console.log("新增成功: " + key + " = " + item.confValue);
803
+ console.log("新增成功: " + (item.confGroup ? item.confGroup + "/" : "") + key + " = " + item.confValue);
722
804
  }
723
- async function cmdConfAddFile(args, json) {
724
- if (args["add-file"] === undefined) throw new Error("conf add-file 缺少参数(用法: conf add-file @items.json)");
725
- const items = readJsonArg(args["add-file"], "--add-file");
805
+ async function cmdConfAddFile(args, json, keys) {
806
+ const val = flagOrPos(args, "add-file", keys);
807
+ if (val === undefined) throw new Error("conf add-file 缺少参数(用法: conf add-file @items.json,元素形如 {confType,confGroup,confKey,confValue,confName,confAttrs})");
808
+ const items = readJsonArg(String(val), "--add-file");
726
809
  const list = Array.isArray(items) ? items : [items];
727
810
  const toAdd = [];
728
811
  for (const it of list) {
729
812
  if (!it.confKey || it.confValue === undefined) continue;
730
813
  const ctype = it.confType || confKeyType(it.confKey, args.type);
731
- const dup = await confGetData(ctype, it.confKey, true);
814
+ const group = it.confGroup !== undefined ? it.confGroup : args.group;
815
+ const dup = await confGetData(ctype, it.confKey, true, group);
732
816
  if (dup) { console.error("[config-resolve] 已存在跳过: " + it.confKey); continue; }
733
- toAdd.push({ confType: ctype, confKey: it.confKey, confValue: String(it.confValue), confAttrs: it.confAttrs || "", confName: it.confName || "" });
817
+ toAdd.push(confPutGroup({ confType: ctype, confKey: it.confKey, confValue: String(it.confValue), confAttrs: it.confAttrs || "", confName: it.confName || "" }, ctype, group));
734
818
  }
735
819
  if (!toAdd.length) { console.log("全部已存在,无新增"); return null; }
736
820
  const r = await confRequest("POST", CONF_ADD_PATH, toAdd);
@@ -739,37 +823,40 @@ async function cmdConfAddFile(args, json) {
739
823
  }
740
824
  async function cmdConfUpdate(args, json, keys) {
741
825
  const key = keys[0];
742
- if (!key) throw new Error("conf update 缺少 confKey(用法: conf update <key> [--value v] [--name n] [--attrs a] [--type t])");
826
+ if (!key) throw new Error("conf update 缺少 confKey(用法: conf update <key> [--value v] [--name n] [--attrs a] [--type t] [--group g])");
743
827
  if (args.value === undefined && args.name === undefined && args.attrs === undefined) {
744
828
  throw new Error("conf update 至少需提供 --value / --name / --attrs 之一");
745
829
  }
746
- const body = { confType: confKeyType(key, args.type), confKey: key };
830
+ const ctype = confKeyType(key, args.type);
831
+ const body = confPutGroup({ confType: ctype, confKey: key }, ctype, args.group);
747
832
  if (args.value !== undefined) body.confValue = String(args.value);
748
833
  if (args.name !== undefined) body.confName = args.name;
749
834
  if (args.attrs !== undefined) body.confAttrs = args.attrs;
750
835
  const r = await confRequest("POST", CONF_UPDATE_PATH, body);
751
836
  if (json) return r;
752
- console.log("更新成功: " + key);
837
+ console.log("更新成功: " + (body.confGroup ? body.confGroup + "/" : "") + key);
753
838
  }
754
839
  async function cmdConfDelete(args, json, keys) {
755
840
  const key = keys[0];
756
- if (!key) throw new Error("conf delete 缺少 confKey(用法: conf delete <key> [--type t])");
841
+ if (!key) throw new Error("conf delete 缺少 confKey(用法: conf delete <key> [--type t] [--group g])");
757
842
  const ctype = confKeyType(key, args.type);
758
- const url = CONF_DELETE_PATH + "?confType=" + encodeURIComponent(ctype) + "&confKey=" + encodeURIComponent(key);
843
+ const url = CONF_DELETE_PATH + "?confType=" + encodeURIComponent(ctype) + "&confKey=" + encodeURIComponent(key) + confGroupSuffix(ctype, args.group);
759
844
  const r = await confRequest("DELETE", url);
760
845
  if (json) return r;
761
- console.log("删除成功: " + key);
846
+ console.log("删除成功: " + (confUseGroup(ctype, args.group) && args.group ? args.group + "/" : "") + key);
762
847
  }
763
848
  async function cmdConf(sub, args, json, pos) {
764
849
  const keys = pos.slice(2);
765
850
  switch (sub) {
766
851
  case "get": return cmdConfGet(args, json, keys);
767
852
  case "batch": return cmdConfBatch(args, json, keys);
768
- case "batch-file": return cmdConfBatchFile(args, json);
853
+ case "batch-file": return cmdConfBatchFile(args, json, keys);
854
+ case "group": return cmdConfGroup(args, json, keys);
855
+ case "group-file": return cmdConfGroupFile(args, json, keys);
769
856
  case "resolve": return cmdConfResolve(args, json, keys);
770
- case "resolve-file": return cmdConfResolveFile(args, json);
857
+ case "resolve-file": return cmdConfResolveFile(args, json, keys);
771
858
  case "add": return cmdConfAdd(args, json, keys);
772
- case "add-file": return cmdConfAddFile(args, json);
859
+ case "add-file": return cmdConfAddFile(args, json, keys);
773
860
  case "update": return cmdConfUpdate(args, json, keys);
774
861
  case "delete": return cmdConfDelete(args, json, keys);
775
862
  default: usage(); process.exit(1);
@@ -1168,16 +1255,21 @@ noun 词库查询
1168
1255
  field 关联字段翻译
1169
1256
  field id2name --module <m> --type <t> --ids id1,id2 [--form-param '{"fieldId":"..","module":"ebuilderform"}'|--eb-browser-param '{..}'|--property-type x]
1170
1257
  field name2id --module <m> --type <t> --name 名称 [同上附加参数]
1171
- conf 环境参数配置中心(chatBi config map,替代 config-resolve 脚本 URL 直连;confType 默认由 CONN_/DS_/WF_ 前缀推导,可 --type 显式)
1172
- conf get <key> [--type t] # 单查(confValue/confAttrs/confName 全量 JSON)
1173
- conf batch <key1> [key2 ...] # 批量查(批量接口异常自动降级逐条单查)
1174
- conf batch-file @items.json # 按 [{confType,confKey}..] 显式批量查(支持任意 confType)
1175
- conf resolve '<含#{KEY}文本>'|@file.txt # 文本占位符替换为真实值(含中文建议 @file)
1176
- conf resolve-file <文件路径> # 读文件替换全部占位符并打印(不改写原文件)
1177
- conf add <key> --value <真实值> [--name 说明] [--attrs '{"schema":..}'] [--type t] [--force] # 新增(默认判重,已存在跳过)
1178
- conf add-file @items.json # JSON 数组批量新增(逐条判重)
1179
- conf update <key> [--value v] [--name n] [--attrs a] [--type t] # 更新(confType+confKey 定位,传哪个字段更哪个)
1180
- conf delete <key> [--type t] # 删除
1258
+ conf 环境参数配置中心(chatBi config map,替代 config-resolve 脚本 URL 直连;confType 默认由 CONN_/DS_/WF_/API_ 前缀推导,可 --type 显式)
1259
+ confGroup(配置分组,v0.1.9 新增,可选):confType=api 时后端支持二级分层(如 api/workflow),
1260
+ 定位维度 = confType+confGroup+confKey;仅 confType=api(或显式传 --group)时才下发 confGroup,其他类型不带该字段
1261
+ conf get <key> [--type t] [--group g] # 单查(confValue/confAttrs/confName 全量 JSON)
1262
+ conf batch <key1> [key2 ...] [--type t] [--group g] # 批量查(批量接口异常自动降级逐条单查)
1263
+ conf batch-file @items.json # 按 [{confType,confGroup,confKey}..] 显式批量查(支持任意 confType)
1264
+ conf group <confType> <confGroup> [--key k] # 按类型+分组批量查(batchGetChatBiConfigMapByTypeAndGroup)
1265
+ conf group-file @items.json # 按 [{"confType":"api","confGroup":"workflow"}..] 多分组批量查
1266
+ conf resolve '<含#{KEY}文本>'|@file.txt [--group g] # 文本占位符替换为真实值(含中文建议 @file)
1267
+ conf resolve-file <文件路径> [--group g] # 读文件替换全部占位符并打印(不改写原文件)
1268
+ conf add <key> --value <真实值> [--name 说明] [--attrs '{"request":..,"response":..}'] [--type t] [--group g] [--force] # 新增(默认判重,已存在跳过)
1269
+ conf add-file @items.json # JSON 数组批量新增(逐条判重,元素可带 confGroup)
1270
+ conf update <key> [--value v] [--name n] [--attrs a] [--type t] [--group g] # 更新(confType+confGroup+confKey 定位,传哪个字段更哪个)
1271
+ conf delete <key> [--type t] [--group g] # 删除
1272
+ 示例: conf group api workflow | conf add GET_WORKFLOW_LIST --type api --group workflow --value /api/workflow/getList --name 查询流程列表
1181
1273
  exp 专家包版本管理(expert-repository/v1,响应以 data.actionMsg.code=0 判成功)
1182
1274
  exp status --expert <code> [--branch main] # 仓库状态(headCommitId/headRevision=提交基线)
1183
1275
  exp manifest --expert <code> [--commit <id>] # 文件清单(sha256)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "e10-data",
3
- "version": "0.1.8",
4
- "description": "泛微 E10 数据接口统一 CLI(data-assistant 专家配套):DSL 查询/数据源/文档/词库/关联字段翻译/环境参数配置中心(conf)/专家包版本管理,认证复用 weaver-e10-login 登录态",
3
+ "version": "0.1.9",
4
+ "description": "泛微 E10 数据接口统一 CLI(data-assistant 专家配套):DSL 查询/数据源/文档/词库/关联字段翻译/环境参数配置中心(conf,支持 confGroup 分组)/专家包版本管理,认证复用 weaver-e10-login 登录态",
5
5
  "author": "e10-dw",
6
6
  "license": "MIT",
7
7
  "type": "module",